18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Netlink interface for IEEE 802.15.4 stack
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright 2007, 2008 Siemens AG
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Written by:
88c2ecf20Sopenharmony_ci * Sergey Lapin <slapin@ossfans.org>
98c2ecf20Sopenharmony_ci * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
108c2ecf20Sopenharmony_ci * Maxim Osipov <maxim.osipov@siemens.com>
118c2ecf20Sopenharmony_ci */
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <linux/kernel.h>
148c2ecf20Sopenharmony_ci#include <linux/gfp.h>
158c2ecf20Sopenharmony_ci#include <net/genetlink.h>
168c2ecf20Sopenharmony_ci#include <linux/nl802154.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include "ieee802154.h"
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_cistatic unsigned int ieee802154_seq_num;
218c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(ieee802154_seq_lock);
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci/* Requests to userspace */
248c2ecf20Sopenharmony_cistruct sk_buff *ieee802154_nl_create(int flags, u8 req)
258c2ecf20Sopenharmony_ci{
268c2ecf20Sopenharmony_ci	void *hdr;
278c2ecf20Sopenharmony_ci	struct sk_buff *msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
288c2ecf20Sopenharmony_ci	unsigned long f;
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci	if (!msg)
318c2ecf20Sopenharmony_ci		return NULL;
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ieee802154_seq_lock, f);
348c2ecf20Sopenharmony_ci	hdr = genlmsg_put(msg, 0, ieee802154_seq_num++,
358c2ecf20Sopenharmony_ci			  &nl802154_family, flags, req);
368c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ieee802154_seq_lock, f);
378c2ecf20Sopenharmony_ci	if (!hdr) {
388c2ecf20Sopenharmony_ci		nlmsg_free(msg);
398c2ecf20Sopenharmony_ci		return NULL;
408c2ecf20Sopenharmony_ci	}
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	return msg;
438c2ecf20Sopenharmony_ci}
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ciint ieee802154_nl_mcast(struct sk_buff *msg, unsigned int group)
468c2ecf20Sopenharmony_ci{
478c2ecf20Sopenharmony_ci	struct nlmsghdr *nlh = nlmsg_hdr(msg);
488c2ecf20Sopenharmony_ci	void *hdr = genlmsg_data(nlmsg_data(nlh));
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci	genlmsg_end(msg, hdr);
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	return genlmsg_multicast(&nl802154_family, msg, 0, group, GFP_ATOMIC);
538c2ecf20Sopenharmony_ci}
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_cistruct sk_buff *ieee802154_nl_new_reply(struct genl_info *info,
568c2ecf20Sopenharmony_ci					int flags, u8 req)
578c2ecf20Sopenharmony_ci{
588c2ecf20Sopenharmony_ci	void *hdr;
598c2ecf20Sopenharmony_ci	struct sk_buff *msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	if (!msg)
628c2ecf20Sopenharmony_ci		return NULL;
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	hdr = genlmsg_put_reply(msg, info,
658c2ecf20Sopenharmony_ci				&nl802154_family, flags, req);
668c2ecf20Sopenharmony_ci	if (!hdr) {
678c2ecf20Sopenharmony_ci		nlmsg_free(msg);
688c2ecf20Sopenharmony_ci		return NULL;
698c2ecf20Sopenharmony_ci	}
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	return msg;
728c2ecf20Sopenharmony_ci}
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ciint ieee802154_nl_reply(struct sk_buff *msg, struct genl_info *info)
758c2ecf20Sopenharmony_ci{
768c2ecf20Sopenharmony_ci	struct nlmsghdr *nlh = nlmsg_hdr(msg);
778c2ecf20Sopenharmony_ci	void *hdr = genlmsg_data(nlmsg_data(nlh));
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	genlmsg_end(msg, hdr);
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	return genlmsg_reply(msg, info);
828c2ecf20Sopenharmony_ci}
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_cistatic const struct genl_small_ops ieee802154_ops[] = {
858c2ecf20Sopenharmony_ci	/* see nl-phy.c */
868c2ecf20Sopenharmony_ci	IEEE802154_DUMP(IEEE802154_LIST_PHY, ieee802154_list_phy,
878c2ecf20Sopenharmony_ci			ieee802154_dump_phy),
888c2ecf20Sopenharmony_ci	IEEE802154_OP(IEEE802154_ADD_IFACE, ieee802154_add_iface),
898c2ecf20Sopenharmony_ci	IEEE802154_OP(IEEE802154_DEL_IFACE, ieee802154_del_iface),
908c2ecf20Sopenharmony_ci	/* see nl-mac.c */
918c2ecf20Sopenharmony_ci	IEEE802154_OP(IEEE802154_ASSOCIATE_REQ, ieee802154_associate_req),
928c2ecf20Sopenharmony_ci	IEEE802154_OP(IEEE802154_ASSOCIATE_RESP, ieee802154_associate_resp),
938c2ecf20Sopenharmony_ci	IEEE802154_OP(IEEE802154_DISASSOCIATE_REQ, ieee802154_disassociate_req),
948c2ecf20Sopenharmony_ci	IEEE802154_OP(IEEE802154_SCAN_REQ, ieee802154_scan_req),
958c2ecf20Sopenharmony_ci	IEEE802154_OP(IEEE802154_START_REQ, ieee802154_start_req),
968c2ecf20Sopenharmony_ci	IEEE802154_DUMP(IEEE802154_LIST_IFACE, ieee802154_list_iface,
978c2ecf20Sopenharmony_ci			ieee802154_dump_iface),
988c2ecf20Sopenharmony_ci	IEEE802154_OP(IEEE802154_SET_MACPARAMS, ieee802154_set_macparams),
998c2ecf20Sopenharmony_ci	IEEE802154_OP(IEEE802154_LLSEC_GETPARAMS, ieee802154_llsec_getparams),
1008c2ecf20Sopenharmony_ci	IEEE802154_OP(IEEE802154_LLSEC_SETPARAMS, ieee802154_llsec_setparams),
1018c2ecf20Sopenharmony_ci	IEEE802154_DUMP(IEEE802154_LLSEC_LIST_KEY, NULL,
1028c2ecf20Sopenharmony_ci			ieee802154_llsec_dump_keys),
1038c2ecf20Sopenharmony_ci	IEEE802154_OP(IEEE802154_LLSEC_ADD_KEY, ieee802154_llsec_add_key),
1048c2ecf20Sopenharmony_ci	IEEE802154_OP(IEEE802154_LLSEC_DEL_KEY, ieee802154_llsec_del_key),
1058c2ecf20Sopenharmony_ci	IEEE802154_DUMP(IEEE802154_LLSEC_LIST_DEV, NULL,
1068c2ecf20Sopenharmony_ci			ieee802154_llsec_dump_devs),
1078c2ecf20Sopenharmony_ci	IEEE802154_OP(IEEE802154_LLSEC_ADD_DEV, ieee802154_llsec_add_dev),
1088c2ecf20Sopenharmony_ci	IEEE802154_OP(IEEE802154_LLSEC_DEL_DEV, ieee802154_llsec_del_dev),
1098c2ecf20Sopenharmony_ci	IEEE802154_DUMP(IEEE802154_LLSEC_LIST_DEVKEY, NULL,
1108c2ecf20Sopenharmony_ci			ieee802154_llsec_dump_devkeys),
1118c2ecf20Sopenharmony_ci	IEEE802154_OP(IEEE802154_LLSEC_ADD_DEVKEY, ieee802154_llsec_add_devkey),
1128c2ecf20Sopenharmony_ci	IEEE802154_OP(IEEE802154_LLSEC_DEL_DEVKEY, ieee802154_llsec_del_devkey),
1138c2ecf20Sopenharmony_ci	IEEE802154_DUMP(IEEE802154_LLSEC_LIST_SECLEVEL, NULL,
1148c2ecf20Sopenharmony_ci			ieee802154_llsec_dump_seclevels),
1158c2ecf20Sopenharmony_ci	IEEE802154_OP(IEEE802154_LLSEC_ADD_SECLEVEL,
1168c2ecf20Sopenharmony_ci		      ieee802154_llsec_add_seclevel),
1178c2ecf20Sopenharmony_ci	IEEE802154_OP(IEEE802154_LLSEC_DEL_SECLEVEL,
1188c2ecf20Sopenharmony_ci		      ieee802154_llsec_del_seclevel),
1198c2ecf20Sopenharmony_ci};
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_cistatic const struct genl_multicast_group ieee802154_mcgrps[] = {
1228c2ecf20Sopenharmony_ci	[IEEE802154_COORD_MCGRP] = { .name = IEEE802154_MCAST_COORD_NAME, },
1238c2ecf20Sopenharmony_ci	[IEEE802154_BEACON_MCGRP] = { .name = IEEE802154_MCAST_BEACON_NAME, },
1248c2ecf20Sopenharmony_ci};
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_cistruct genl_family nl802154_family __ro_after_init = {
1278c2ecf20Sopenharmony_ci	.hdrsize	= 0,
1288c2ecf20Sopenharmony_ci	.name		= IEEE802154_NL_NAME,
1298c2ecf20Sopenharmony_ci	.version	= 1,
1308c2ecf20Sopenharmony_ci	.maxattr	= IEEE802154_ATTR_MAX,
1318c2ecf20Sopenharmony_ci	.policy		= ieee802154_policy,
1328c2ecf20Sopenharmony_ci	.module		= THIS_MODULE,
1338c2ecf20Sopenharmony_ci	.small_ops	= ieee802154_ops,
1348c2ecf20Sopenharmony_ci	.n_small_ops	= ARRAY_SIZE(ieee802154_ops),
1358c2ecf20Sopenharmony_ci	.mcgrps		= ieee802154_mcgrps,
1368c2ecf20Sopenharmony_ci	.n_mcgrps	= ARRAY_SIZE(ieee802154_mcgrps),
1378c2ecf20Sopenharmony_ci};
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ciint __init ieee802154_nl_init(void)
1408c2ecf20Sopenharmony_ci{
1418c2ecf20Sopenharmony_ci	return genl_register_family(&nl802154_family);
1428c2ecf20Sopenharmony_ci}
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_civoid ieee802154_nl_exit(void)
1458c2ecf20Sopenharmony_ci{
1468c2ecf20Sopenharmony_ci	genl_unregister_family(&nl802154_family);
1478c2ecf20Sopenharmony_ci}
148