aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPhoebe Buckheister <phoebe.buckheister@itwm.fraunhofer.de>2014-05-16 11:46:44 -0400
committerDavid S. Miller <davem@davemloft.net>2014-05-16 17:23:41 -0400
commit3e9c156e2c210ab67b12b1b692983a6b97c19d3f (patch)
treee93786b9081ddc9c5c153c94a17fcd4b972b4674
parent9b0bb4a83f27cd9b05d709cdeee86edc174db100 (diff)
ieee802154: add netlink interfaces for llsec
This patch adds user-visible interfaces for the llsec infrastructure. For the added methods, the only major difference between all add/remove implementation lies in how the specific object is parsed, and for dump requests, how objects are written into netlink messages. To save on boilerplate code, table dumps are routed through a helper function that handles netlink dump state, leaving the actual dumping code to care only about iterating over the table to be dumped and filling netlink messages. For add/remove methods, the boilerplate required to work is not quite as large, but still enough to also move into a local helper. Signed-off-by: Phoebe Buckheister <phoebe.buckheister@itwm.fraunhofer.de> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/nl802154.h31
-rw-r--r--net/ieee802154/ieee802154.h19
-rw-r--r--net/ieee802154/netlink.c20
-rw-r--r--net/ieee802154/nl-mac.c807
-rw-r--r--net/ieee802154/nl_policy.c16
5 files changed, 893 insertions, 0 deletions
diff --git a/include/linux/nl802154.h b/include/linux/nl802154.h
index c8d7f3965fff..20163b9a0eae 100644
--- a/include/linux/nl802154.h
+++ b/include/linux/nl802154.h
@@ -80,6 +80,22 @@ enum {
80 80
81 IEEE802154_ATTR_FRAME_RETRIES, 81 IEEE802154_ATTR_FRAME_RETRIES,
82 82
83 IEEE802154_ATTR_LLSEC_ENABLED,
84 IEEE802154_ATTR_LLSEC_SECLEVEL,
85 IEEE802154_ATTR_LLSEC_KEY_MODE,
86 IEEE802154_ATTR_LLSEC_KEY_SOURCE_SHORT,
87 IEEE802154_ATTR_LLSEC_KEY_SOURCE_EXTENDED,
88 IEEE802154_ATTR_LLSEC_KEY_ID,
89 IEEE802154_ATTR_LLSEC_FRAME_COUNTER,
90 IEEE802154_ATTR_LLSEC_KEY_BYTES,
91 IEEE802154_ATTR_LLSEC_KEY_USAGE_FRAME_TYPES,
92 IEEE802154_ATTR_LLSEC_KEY_USAGE_COMMANDS,
93 IEEE802154_ATTR_LLSEC_FRAME_TYPE,
94 IEEE802154_ATTR_LLSEC_CMD_FRAME_ID,
95 IEEE802154_ATTR_LLSEC_SECLEVELS,
96 IEEE802154_ATTR_LLSEC_DEV_OVERRIDE,
97 IEEE802154_ATTR_LLSEC_DEV_KEY_MODE,
98
83 __IEEE802154_ATTR_MAX, 99 __IEEE802154_ATTR_MAX,
84}; 100};
85 101
@@ -134,6 +150,21 @@ enum {
134 150
135 IEEE802154_SET_MACPARAMS, 151 IEEE802154_SET_MACPARAMS,
136 152
153 IEEE802154_LLSEC_GETPARAMS,
154 IEEE802154_LLSEC_SETPARAMS,
155 IEEE802154_LLSEC_LIST_KEY,
156 IEEE802154_LLSEC_ADD_KEY,
157 IEEE802154_LLSEC_DEL_KEY,
158 IEEE802154_LLSEC_LIST_DEV,
159 IEEE802154_LLSEC_ADD_DEV,
160 IEEE802154_LLSEC_DEL_DEV,
161 IEEE802154_LLSEC_LIST_DEVKEY,
162 IEEE802154_LLSEC_ADD_DEVKEY,
163 IEEE802154_LLSEC_DEL_DEVKEY,
164 IEEE802154_LLSEC_LIST_SECLEVEL,
165 IEEE802154_LLSEC_ADD_SECLEVEL,
166 IEEE802154_LLSEC_DEL_SECLEVEL,
167
137 __IEEE802154_CMD_MAX, 168 __IEEE802154_CMD_MAX,
138}; 169};
139 170
diff --git a/net/ieee802154/ieee802154.h b/net/ieee802154/ieee802154.h
index 6693a5cf01ce..8b83a231299e 100644
--- a/net/ieee802154/ieee802154.h
+++ b/net/ieee802154/ieee802154.h
@@ -68,4 +68,23 @@ int ieee802154_list_iface(struct sk_buff *skb, struct genl_info *info);
68int ieee802154_dump_iface(struct sk_buff *skb, struct netlink_callback *cb); 68int ieee802154_dump_iface(struct sk_buff *skb, struct netlink_callback *cb);
69int ieee802154_set_macparams(struct sk_buff *skb, struct genl_info *info); 69int ieee802154_set_macparams(struct sk_buff *skb, struct genl_info *info);
70 70
71int ieee802154_llsec_getparams(struct sk_buff *skb, struct genl_info *info);
72int ieee802154_llsec_setparams(struct sk_buff *skb, struct genl_info *info);
73int ieee802154_llsec_add_key(struct sk_buff *skb, struct genl_info *info);
74int ieee802154_llsec_del_key(struct sk_buff *skb, struct genl_info *info);
75int ieee802154_llsec_dump_keys(struct sk_buff *skb,
76 struct netlink_callback *cb);
77int ieee802154_llsec_add_dev(struct sk_buff *skb, struct genl_info *info);
78int ieee802154_llsec_del_dev(struct sk_buff *skb, struct genl_info *info);
79int ieee802154_llsec_dump_devs(struct sk_buff *skb,
80 struct netlink_callback *cb);
81int ieee802154_llsec_add_devkey(struct sk_buff *skb, struct genl_info *info);
82int ieee802154_llsec_del_devkey(struct sk_buff *skb, struct genl_info *info);
83int ieee802154_llsec_dump_devkeys(struct sk_buff *skb,
84 struct netlink_callback *cb);
85int ieee802154_llsec_add_seclevel(struct sk_buff *skb, struct genl_info *info);
86int ieee802154_llsec_del_seclevel(struct sk_buff *skb, struct genl_info *info);
87int ieee802154_llsec_dump_seclevels(struct sk_buff *skb,
88 struct netlink_callback *cb);
89
71#endif 90#endif
diff --git a/net/ieee802154/netlink.c b/net/ieee802154/netlink.c
index 04b20589d97a..26efcf4fd2ff 100644
--- a/net/ieee802154/netlink.c
+++ b/net/ieee802154/netlink.c
@@ -124,6 +124,26 @@ static const struct genl_ops ieee8021154_ops[] = {
124 IEEE802154_DUMP(IEEE802154_LIST_IFACE, ieee802154_list_iface, 124 IEEE802154_DUMP(IEEE802154_LIST_IFACE, ieee802154_list_iface,
125 ieee802154_dump_iface), 125 ieee802154_dump_iface),
126 IEEE802154_OP(IEEE802154_SET_MACPARAMS, ieee802154_set_macparams), 126 IEEE802154_OP(IEEE802154_SET_MACPARAMS, ieee802154_set_macparams),
127 IEEE802154_OP(IEEE802154_LLSEC_GETPARAMS, ieee802154_llsec_getparams),
128 IEEE802154_OP(IEEE802154_LLSEC_SETPARAMS, ieee802154_llsec_setparams),
129 IEEE802154_DUMP(IEEE802154_LLSEC_LIST_KEY, NULL,
130 ieee802154_llsec_dump_keys),
131 IEEE802154_OP(IEEE802154_LLSEC_ADD_KEY, ieee802154_llsec_add_key),
132 IEEE802154_OP(IEEE802154_LLSEC_DEL_KEY, ieee802154_llsec_del_key),
133 IEEE802154_DUMP(IEEE802154_LLSEC_LIST_DEV, NULL,
134 ieee802154_llsec_dump_devs),
135 IEEE802154_OP(IEEE802154_LLSEC_ADD_DEV, ieee802154_llsec_add_dev),
136 IEEE802154_OP(IEEE802154_LLSEC_DEL_DEV, ieee802154_llsec_del_dev),
137 IEEE802154_DUMP(IEEE802154_LLSEC_LIST_DEVKEY, NULL,
138 ieee802154_llsec_dump_devkeys),
139 IEEE802154_OP(IEEE802154_LLSEC_ADD_DEVKEY, ieee802154_llsec_add_devkey),
140 IEEE802154_OP(IEEE802154_LLSEC_DEL_DEVKEY, ieee802154_llsec_del_devkey),
141 IEEE802154_DUMP(IEEE802154_LLSEC_LIST_SECLEVEL, NULL,
142 ieee802154_llsec_dump_seclevels),
143 IEEE802154_OP(IEEE802154_LLSEC_ADD_SECLEVEL,
144 ieee802154_llsec_add_seclevel),
145 IEEE802154_OP(IEEE802154_LLSEC_DEL_SECLEVEL,
146 ieee802154_llsec_del_seclevel),
127}; 147};
128 148
129static const struct genl_multicast_group ieee802154_mcgrps[] = { 149static const struct genl_multicast_group ieee802154_mcgrps[] = {
diff --git a/net/ieee802154/nl-mac.c b/net/ieee802154/nl-mac.c
index 5d285498c0f6..5617b4c6d6d5 100644
--- a/net/ieee802154/nl-mac.c
+++ b/net/ieee802154/nl-mac.c
@@ -715,3 +715,810 @@ out:
715 dev_put(dev); 715 dev_put(dev);
716 return rc; 716 return rc;
717} 717}
718
719
720
721static int
722ieee802154_llsec_parse_key_id(struct genl_info *info,
723 struct ieee802154_llsec_key_id *desc)
724{
725 memset(desc, 0, sizeof(*desc));
726
727 if (!info->attrs[IEEE802154_ATTR_LLSEC_KEY_MODE])
728 return -EINVAL;
729
730 desc->mode = nla_get_u8(info->attrs[IEEE802154_ATTR_LLSEC_KEY_MODE]);
731
732 if (desc->mode == IEEE802154_SCF_KEY_IMPLICIT) {
733 if (!info->attrs[IEEE802154_ATTR_PAN_ID] &&
734 !(info->attrs[IEEE802154_ATTR_SHORT_ADDR] ||
735 info->attrs[IEEE802154_ATTR_HW_ADDR]))
736 return -EINVAL;
737
738 desc->device_addr.pan_id = nla_get_shortaddr(info->attrs[IEEE802154_ATTR_PAN_ID]);
739
740 if (info->attrs[IEEE802154_ATTR_SHORT_ADDR]) {
741 desc->device_addr.mode = IEEE802154_ADDR_SHORT;
742 desc->device_addr.short_addr = nla_get_shortaddr(info->attrs[IEEE802154_ATTR_SHORT_ADDR]);
743 } else {
744 desc->device_addr.mode = IEEE802154_ADDR_LONG;
745 desc->device_addr.extended_addr = nla_get_hwaddr(info->attrs[IEEE802154_ATTR_HW_ADDR]);
746 }
747 }
748
749 if (desc->mode != IEEE802154_SCF_KEY_IMPLICIT &&
750 !info->attrs[IEEE802154_ATTR_LLSEC_KEY_ID])
751 return -EINVAL;
752
753 if (desc->mode == IEEE802154_SCF_KEY_SHORT_INDEX &&
754 !info->attrs[IEEE802154_ATTR_LLSEC_KEY_SOURCE_SHORT])
755 return -EINVAL;
756
757 if (desc->mode == IEEE802154_SCF_KEY_HW_INDEX &&
758 !info->attrs[IEEE802154_ATTR_LLSEC_KEY_SOURCE_EXTENDED])
759 return -EINVAL;
760
761 if (desc->mode != IEEE802154_SCF_KEY_IMPLICIT)
762 desc->id = nla_get_u8(info->attrs[IEEE802154_ATTR_LLSEC_KEY_ID]);
763
764 switch (desc->mode) {
765 case IEEE802154_SCF_KEY_SHORT_INDEX:
766 {
767 u32 source = nla_get_u32(info->attrs[IEEE802154_ATTR_LLSEC_KEY_SOURCE_SHORT]);
768 desc->short_source = cpu_to_le32(source);
769 break;
770 }
771 case IEEE802154_SCF_KEY_HW_INDEX:
772 desc->extended_source = nla_get_hwaddr(info->attrs[IEEE802154_ATTR_LLSEC_KEY_SOURCE_EXTENDED]);
773 break;
774 }
775
776 return 0;
777}
778
779static int
780ieee802154_llsec_fill_key_id(struct sk_buff *msg,
781 const struct ieee802154_llsec_key_id *desc)
782{
783 if (nla_put_u8(msg, IEEE802154_ATTR_LLSEC_KEY_MODE, desc->mode))
784 return -EMSGSIZE;
785
786 if (desc->mode == IEEE802154_SCF_KEY_IMPLICIT) {
787 if (nla_put_shortaddr(msg, IEEE802154_ATTR_PAN_ID,
788 desc->device_addr.pan_id))
789 return -EMSGSIZE;
790
791 if (desc->device_addr.mode == IEEE802154_ADDR_SHORT &&
792 nla_put_shortaddr(msg, IEEE802154_ATTR_SHORT_ADDR,
793 desc->device_addr.short_addr))
794 return -EMSGSIZE;
795
796 if (desc->device_addr.mode == IEEE802154_ADDR_LONG &&
797 nla_put_hwaddr(msg, IEEE802154_ATTR_HW_ADDR,
798 desc->device_addr.extended_addr))
799 return -EMSGSIZE;
800 }
801
802 if (desc->mode != IEEE802154_SCF_KEY_IMPLICIT &&
803 nla_put_u8(msg, IEEE802154_ATTR_LLSEC_KEY_ID, desc->id))
804 return -EMSGSIZE;
805
806 if (desc->mode == IEEE802154_SCF_KEY_SHORT_INDEX &&
807 nla_put_u32(msg, IEEE802154_ATTR_LLSEC_KEY_SOURCE_SHORT,
808 le32_to_cpu(desc->short_source)))
809 return -EMSGSIZE;
810
811 if (desc->mode == IEEE802154_SCF_KEY_HW_INDEX &&
812 nla_put_hwaddr(msg, IEEE802154_ATTR_LLSEC_KEY_SOURCE_EXTENDED,
813 desc->extended_source))
814 return -EMSGSIZE;
815
816 return 0;
817}
818
819int ieee802154_llsec_getparams(struct sk_buff *skb, struct genl_info *info)
820{
821 struct sk_buff *msg;
822 struct net_device *dev = NULL;
823 int rc = -ENOBUFS;
824 struct ieee802154_mlme_ops *ops;
825 void *hdr;
826 struct ieee802154_llsec_params params;
827
828 pr_debug("%s\n", __func__);
829
830 dev = ieee802154_nl_get_dev(info);
831 if (!dev)
832 return -ENODEV;
833
834 ops = ieee802154_mlme_ops(dev);
835 if (!ops->llsec)
836 return -EOPNOTSUPP;
837
838 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
839 if (!msg)
840 goto out_dev;
841
842 hdr = genlmsg_put(msg, 0, info->snd_seq, &nl802154_family, 0,
843 IEEE802154_LLSEC_GETPARAMS);
844 if (!hdr)
845 goto out_free;
846
847 rc = ops->llsec->get_params(dev, &params);
848 if (rc < 0)
849 goto out_free;
850
851 if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
852 nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
853 nla_put_u8(msg, IEEE802154_ATTR_LLSEC_ENABLED, params.enabled) ||
854 nla_put_u8(msg, IEEE802154_ATTR_LLSEC_SECLEVEL, params.out_level) ||
855 nla_put_u32(msg, IEEE802154_ATTR_LLSEC_FRAME_COUNTER,
856 be32_to_cpu(params.frame_counter)) ||
857 ieee802154_llsec_fill_key_id(msg, &params.out_key))
858 goto out_free;
859
860 dev_put(dev);
861
862 return ieee802154_nl_reply(msg, info);
863out_free:
864 nlmsg_free(msg);
865out_dev:
866 dev_put(dev);
867 return rc;
868}
869
870int ieee802154_llsec_setparams(struct sk_buff *skb, struct genl_info *info)
871{
872 struct net_device *dev = NULL;
873 int rc = -EINVAL;
874 struct ieee802154_mlme_ops *ops;
875 struct ieee802154_llsec_params params;
876 int changed = 0;
877
878 pr_debug("%s\n", __func__);
879
880 dev = ieee802154_nl_get_dev(info);
881 if (!dev)
882 return -ENODEV;
883
884 if (!info->attrs[IEEE802154_ATTR_LLSEC_ENABLED] &&
885 !info->attrs[IEEE802154_ATTR_LLSEC_KEY_MODE] &&
886 !info->attrs[IEEE802154_ATTR_LLSEC_SECLEVEL])
887 goto out;
888
889 ops = ieee802154_mlme_ops(dev);
890 if (!ops->llsec) {
891 rc = -EOPNOTSUPP;
892 goto out;
893 }
894
895 if (info->attrs[IEEE802154_ATTR_LLSEC_SECLEVEL] &&
896 nla_get_u8(info->attrs[IEEE802154_ATTR_LLSEC_SECLEVEL]) > 7)
897 goto out;
898
899 if (info->attrs[IEEE802154_ATTR_LLSEC_ENABLED]) {
900 params.enabled = nla_get_u8(info->attrs[IEEE802154_ATTR_LLSEC_ENABLED]);
901 changed |= IEEE802154_LLSEC_PARAM_ENABLED;
902 }
903
904 if (info->attrs[IEEE802154_ATTR_LLSEC_KEY_MODE]) {
905 if (ieee802154_llsec_parse_key_id(info, &params.out_key))
906 goto out;
907
908 changed |= IEEE802154_LLSEC_PARAM_OUT_KEY;
909 }
910
911 if (info->attrs[IEEE802154_ATTR_LLSEC_SECLEVEL]) {
912 params.out_level = nla_get_u8(info->attrs[IEEE802154_ATTR_LLSEC_SECLEVEL]);
913 changed |= IEEE802154_LLSEC_PARAM_OUT_LEVEL;
914 }
915
916 if (info->attrs[IEEE802154_ATTR_LLSEC_FRAME_COUNTER]) {
917 u32 fc = nla_get_u32(info->attrs[IEEE802154_ATTR_LLSEC_FRAME_COUNTER]);
918
919 params.frame_counter = cpu_to_be32(fc);
920 changed |= IEEE802154_LLSEC_PARAM_FRAME_COUNTER;
921 }
922
923 rc = ops->llsec->set_params(dev, &params, changed);
924
925 dev_put(dev);
926
927 return rc;
928out:
929 dev_put(dev);
930 return rc;
931}
932
933
934
935struct llsec_dump_data {
936 struct sk_buff *skb;
937 int s_idx, s_idx2;
938 int portid;
939 int nlmsg_seq;
940 struct net_device *dev;
941 struct ieee802154_mlme_ops *ops;
942 struct ieee802154_llsec_table *table;
943};
944
945static int
946ieee802154_llsec_dump_table(struct sk_buff *skb, struct netlink_callback *cb,
947 int (*step)(struct llsec_dump_data*))
948{
949 struct net *net = sock_net(skb->sk);
950 struct net_device *dev;
951 struct llsec_dump_data data;
952 int idx = 0;
953 int first_dev = cb->args[0];
954 int rc;
955
956 for_each_netdev(net, dev) {
957 if (idx < first_dev || dev->type != ARPHRD_IEEE802154)
958 goto skip;
959
960 data.ops = ieee802154_mlme_ops(dev);
961 if (!data.ops->llsec)
962 goto skip;
963
964 data.skb = skb;
965 data.s_idx = cb->args[1];
966 data.s_idx2 = cb->args[2];
967 data.dev = dev;
968 data.portid = NETLINK_CB(cb->skb).portid;
969 data.nlmsg_seq = cb->nlh->nlmsg_seq;
970
971 data.ops->llsec->lock_table(dev);
972 data.ops->llsec->get_table(data.dev, &data.table);
973 rc = step(&data);
974 data.ops->llsec->unlock_table(dev);
975
976 if (rc < 0)
977 break;
978
979skip:
980 idx++;
981 }
982 cb->args[0] = idx;
983
984 return skb->len;
985}
986
987static int
988ieee802154_nl_llsec_change(struct sk_buff *skb, struct genl_info *info,
989 int (*fn)(struct net_device*, struct genl_info*))
990{
991 struct net_device *dev = NULL;
992 int rc = -EINVAL;
993
994 dev = ieee802154_nl_get_dev(info);
995 if (!dev)
996 return -ENODEV;
997
998 if (!ieee802154_mlme_ops(dev)->llsec)
999 rc = -EOPNOTSUPP;
1000 else
1001 rc = fn(dev, info);
1002
1003 dev_put(dev);
1004 return rc;
1005}
1006
1007
1008
1009static int
1010ieee802154_llsec_parse_key(struct genl_info *info,
1011 struct ieee802154_llsec_key *key)
1012{
1013 u8 frames;
1014 u32 commands[256 / 32];
1015
1016 memset(key, 0, sizeof(*key));
1017
1018 if (!info->attrs[IEEE802154_ATTR_LLSEC_KEY_USAGE_FRAME_TYPES] ||
1019 !info->attrs[IEEE802154_ATTR_LLSEC_KEY_BYTES])
1020 return -EINVAL;
1021
1022 frames = nla_get_u8(info->attrs[IEEE802154_ATTR_LLSEC_KEY_USAGE_FRAME_TYPES]);
1023 if ((frames & BIT(IEEE802154_FC_TYPE_MAC_CMD)) &&
1024 !info->attrs[IEEE802154_ATTR_LLSEC_KEY_USAGE_COMMANDS])
1025 return -EINVAL;
1026
1027 if (info->attrs[IEEE802154_ATTR_LLSEC_KEY_USAGE_COMMANDS]) {
1028 nla_memcpy(commands,
1029 info->attrs[IEEE802154_ATTR_LLSEC_KEY_USAGE_COMMANDS],
1030 256 / 8);
1031
1032 if (commands[0] || commands[1] || commands[2] || commands[3] ||
1033 commands[4] || commands[5] || commands[6] ||
1034 commands[7] >= BIT(IEEE802154_CMD_GTS_REQ + 1))
1035 return -EINVAL;
1036
1037 key->cmd_frame_ids = commands[7];
1038 }
1039
1040 key->frame_types = frames;
1041
1042 nla_memcpy(key->key, info->attrs[IEEE802154_ATTR_LLSEC_KEY_BYTES],
1043 IEEE802154_LLSEC_KEY_SIZE);
1044
1045 return 0;
1046}
1047
1048static int llsec_add_key(struct net_device *dev, struct genl_info *info)
1049{
1050 struct ieee802154_mlme_ops *ops = ieee802154_mlme_ops(dev);
1051 struct ieee802154_llsec_key key;
1052 struct ieee802154_llsec_key_id id;
1053
1054 if (ieee802154_llsec_parse_key(info, &key) ||
1055 ieee802154_llsec_parse_key_id(info, &id))
1056 return -EINVAL;
1057
1058 return ops->llsec->add_key(dev, &id, &key);
1059}
1060
1061int ieee802154_llsec_add_key(struct sk_buff *skb, struct genl_info *info)
1062{
1063 if ((info->nlhdr->nlmsg_flags & (NLM_F_CREATE | NLM_F_EXCL)) !=
1064 (NLM_F_CREATE | NLM_F_EXCL))
1065 return -EINVAL;
1066
1067 return ieee802154_nl_llsec_change(skb, info, llsec_add_key);
1068}
1069
1070static int llsec_remove_key(struct net_device *dev, struct genl_info *info)
1071{
1072 struct ieee802154_mlme_ops *ops = ieee802154_mlme_ops(dev);
1073 struct ieee802154_llsec_key_id id;
1074
1075 if (ieee802154_llsec_parse_key_id(info, &id))
1076 return -EINVAL;
1077
1078 return ops->llsec->del_key(dev, &id);
1079}
1080
1081int ieee802154_llsec_del_key(struct sk_buff *skb, struct genl_info *info)
1082{
1083 return ieee802154_nl_llsec_change(skb, info, llsec_remove_key);
1084}
1085
1086static int
1087ieee802154_nl_fill_key(struct sk_buff *msg, u32 portid, u32 seq,
1088 const struct ieee802154_llsec_key_entry *key,
1089 const struct net_device *dev)
1090{
1091 void *hdr;
1092 u32 commands[256 / 32];
1093
1094 hdr = genlmsg_put(msg, 0, seq, &nl802154_family, NLM_F_MULTI,
1095 IEEE802154_LLSEC_LIST_KEY);
1096 if (!hdr)
1097 goto out;
1098
1099 if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
1100 nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
1101 ieee802154_llsec_fill_key_id(msg, &key->id) ||
1102 nla_put_u8(msg, IEEE802154_ATTR_LLSEC_KEY_USAGE_FRAME_TYPES,
1103 key->key->frame_types))
1104 goto nla_put_failure;
1105
1106 if (key->key->frame_types & BIT(IEEE802154_FC_TYPE_MAC_CMD)) {
1107 memset(commands, 0, sizeof(commands));
1108 commands[7] = key->key->cmd_frame_ids;
1109 if (nla_put(msg, IEEE802154_ATTR_LLSEC_KEY_USAGE_COMMANDS,
1110 sizeof(commands), commands))
1111 goto nla_put_failure;
1112 }
1113
1114 if (nla_put(msg, IEEE802154_ATTR_LLSEC_KEY_BYTES,
1115 IEEE802154_LLSEC_KEY_SIZE, key->key->key))
1116 goto nla_put_failure;
1117
1118 genlmsg_end(msg, hdr);
1119 return 0;
1120
1121nla_put_failure:
1122 genlmsg_cancel(msg, hdr);
1123out:
1124 return -EMSGSIZE;
1125}
1126
1127static int llsec_iter_keys(struct llsec_dump_data *data)
1128{
1129 struct ieee802154_llsec_key_entry *pos;
1130 int rc = 0, idx = 0;
1131
1132 list_for_each_entry(pos, &data->table->keys, list) {
1133 if (idx++ < data->s_idx)
1134 continue;
1135
1136 if (ieee802154_nl_fill_key(data->skb, data->portid,
1137 data->nlmsg_seq, pos, data->dev)) {
1138 rc = -EMSGSIZE;
1139 break;
1140 }
1141
1142 data->s_idx++;
1143 }
1144
1145 return rc;
1146}
1147
1148int ieee802154_llsec_dump_keys(struct sk_buff *skb, struct netlink_callback *cb)
1149{
1150 return ieee802154_llsec_dump_table(skb, cb, llsec_iter_keys);
1151}
1152
1153
1154
1155static int
1156llsec_parse_dev(struct genl_info *info,
1157 struct ieee802154_llsec_device *dev)
1158{
1159 memset(dev, 0, sizeof(*dev));
1160
1161 if (!info->attrs[IEEE802154_ATTR_LLSEC_FRAME_COUNTER] ||
1162 !info->attrs[IEEE802154_ATTR_HW_ADDR] ||
1163 !info->attrs[IEEE802154_ATTR_LLSEC_DEV_OVERRIDE] ||
1164 !info->attrs[IEEE802154_ATTR_LLSEC_DEV_KEY_MODE] ||
1165 (!!info->attrs[IEEE802154_ATTR_PAN_ID] !=
1166 !!info->attrs[IEEE802154_ATTR_SHORT_ADDR]))
1167 return -EINVAL;
1168
1169 if (info->attrs[IEEE802154_ATTR_PAN_ID]) {
1170 dev->pan_id = nla_get_shortaddr(info->attrs[IEEE802154_ATTR_PAN_ID]);
1171 dev->short_addr = nla_get_shortaddr(info->attrs[IEEE802154_ATTR_SHORT_ADDR]);
1172 } else {
1173 dev->short_addr = cpu_to_le16(IEEE802154_ADDR_UNDEF);
1174 }
1175
1176 dev->hwaddr = nla_get_hwaddr(info->attrs[IEEE802154_ATTR_HW_ADDR]);
1177 dev->frame_counter = nla_get_u32(info->attrs[IEEE802154_ATTR_LLSEC_FRAME_COUNTER]);
1178 dev->seclevel_exempt = !!nla_get_u8(info->attrs[IEEE802154_ATTR_LLSEC_DEV_OVERRIDE]);
1179 dev->key_mode = nla_get_u8(info->attrs[IEEE802154_ATTR_LLSEC_DEV_KEY_MODE]);
1180
1181 if (dev->key_mode >= __IEEE802154_LLSEC_DEVKEY_MAX)
1182 return -EINVAL;
1183
1184 return 0;
1185}
1186
1187static int llsec_add_dev(struct net_device *dev, struct genl_info *info)
1188{
1189 struct ieee802154_mlme_ops *ops = ieee802154_mlme_ops(dev);
1190 struct ieee802154_llsec_device desc;
1191
1192 if (llsec_parse_dev(info, &desc))
1193 return -EINVAL;
1194
1195 return ops->llsec->add_dev(dev, &desc);
1196}
1197
1198int ieee802154_llsec_add_dev(struct sk_buff *skb, struct genl_info *info)
1199{
1200 if ((info->nlhdr->nlmsg_flags & (NLM_F_CREATE | NLM_F_EXCL)) !=
1201 (NLM_F_CREATE | NLM_F_EXCL))
1202 return -EINVAL;
1203
1204 return ieee802154_nl_llsec_change(skb, info, llsec_add_dev);
1205}
1206
1207static int llsec_del_dev(struct net_device *dev, struct genl_info *info)
1208{
1209 struct ieee802154_mlme_ops *ops = ieee802154_mlme_ops(dev);
1210 __le64 devaddr;
1211
1212 if (!info->attrs[IEEE802154_ATTR_HW_ADDR])
1213 return -EINVAL;
1214
1215 devaddr = nla_get_hwaddr(info->attrs[IEEE802154_ATTR_HW_ADDR]);
1216
1217 return ops->llsec->del_dev(dev, devaddr);
1218}
1219
1220int ieee802154_llsec_del_dev(struct sk_buff *skb, struct genl_info *info)
1221{
1222 return ieee802154_nl_llsec_change(skb, info, llsec_del_dev);
1223}
1224
1225static int
1226ieee802154_nl_fill_dev(struct sk_buff *msg, u32 portid, u32 seq,
1227 const struct ieee802154_llsec_device *desc,
1228 const struct net_device *dev)
1229{
1230 void *hdr;
1231
1232 hdr = genlmsg_put(msg, 0, seq, &nl802154_family, NLM_F_MULTI,
1233 IEEE802154_LLSEC_LIST_DEV);
1234 if (!hdr)
1235 goto out;
1236
1237 if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
1238 nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
1239 nla_put_shortaddr(msg, IEEE802154_ATTR_PAN_ID, desc->pan_id) ||
1240 nla_put_shortaddr(msg, IEEE802154_ATTR_SHORT_ADDR,
1241 desc->short_addr) ||
1242 nla_put_hwaddr(msg, IEEE802154_ATTR_HW_ADDR, desc->hwaddr) ||
1243 nla_put_u32(msg, IEEE802154_ATTR_LLSEC_FRAME_COUNTER,
1244 desc->frame_counter) ||
1245 nla_put_u8(msg, IEEE802154_ATTR_LLSEC_DEV_OVERRIDE,
1246 desc->seclevel_exempt) ||
1247 nla_put_u8(msg, IEEE802154_ATTR_LLSEC_DEV_KEY_MODE, desc->key_mode))
1248 goto nla_put_failure;
1249
1250 genlmsg_end(msg, hdr);
1251 return 0;
1252
1253nla_put_failure:
1254 genlmsg_cancel(msg, hdr);
1255out:
1256 return -EMSGSIZE;
1257}
1258
1259static int llsec_iter_devs(struct llsec_dump_data *data)
1260{
1261 struct ieee802154_llsec_device *pos;
1262 int rc = 0, idx = 0;
1263
1264 list_for_each_entry(pos, &data->table->devices, list) {
1265 if (idx++ < data->s_idx)
1266 continue;
1267
1268 if (ieee802154_nl_fill_dev(data->skb, data->portid,
1269 data->nlmsg_seq, pos, data->dev)) {
1270 rc = -EMSGSIZE;
1271 break;
1272 }
1273
1274 data->s_idx++;
1275 }
1276
1277 return rc;
1278}
1279
1280int ieee802154_llsec_dump_devs(struct sk_buff *skb, struct netlink_callback *cb)
1281{
1282 return ieee802154_llsec_dump_table(skb, cb, llsec_iter_devs);
1283}
1284
1285
1286
1287static int llsec_add_devkey(struct net_device *dev, struct genl_info *info)
1288{
1289 struct ieee802154_mlme_ops *ops = ieee802154_mlme_ops(dev);
1290 struct ieee802154_llsec_device_key key;
1291 __le64 devaddr;
1292
1293 if (!info->attrs[IEEE802154_ATTR_LLSEC_FRAME_COUNTER] ||
1294 !info->attrs[IEEE802154_ATTR_HW_ADDR] ||
1295 ieee802154_llsec_parse_key_id(info, &key.key_id))
1296 return -EINVAL;
1297
1298 devaddr = nla_get_hwaddr(info->attrs[IEEE802154_ATTR_HW_ADDR]);
1299 key.frame_counter = nla_get_u32(info->attrs[IEEE802154_ATTR_LLSEC_FRAME_COUNTER]);
1300
1301 return ops->llsec->add_devkey(dev, devaddr, &key);
1302}
1303
1304int ieee802154_llsec_add_devkey(struct sk_buff *skb, struct genl_info *info)
1305{
1306 if ((info->nlhdr->nlmsg_flags & (NLM_F_CREATE | NLM_F_EXCL)) !=
1307 (NLM_F_CREATE | NLM_F_EXCL))
1308 return -EINVAL;
1309
1310 return ieee802154_nl_llsec_change(skb, info, llsec_add_devkey);
1311}
1312
1313static int llsec_del_devkey(struct net_device *dev, struct genl_info *info)
1314{
1315 struct ieee802154_mlme_ops *ops = ieee802154_mlme_ops(dev);
1316 struct ieee802154_llsec_device_key key;
1317 __le64 devaddr;
1318
1319 if (!info->attrs[IEEE802154_ATTR_HW_ADDR] ||
1320 ieee802154_llsec_parse_key_id(info, &key.key_id))
1321 return -EINVAL;
1322
1323 devaddr = nla_get_hwaddr(info->attrs[IEEE802154_ATTR_HW_ADDR]);
1324
1325 return ops->llsec->del_devkey(dev, devaddr, &key);
1326}
1327
1328int ieee802154_llsec_del_devkey(struct sk_buff *skb, struct genl_info *info)
1329{
1330 return ieee802154_nl_llsec_change(skb, info, llsec_del_devkey);
1331}
1332
1333static int
1334ieee802154_nl_fill_devkey(struct sk_buff *msg, u32 portid, u32 seq,
1335 __le64 devaddr,
1336 const struct ieee802154_llsec_device_key *devkey,
1337 const struct net_device *dev)
1338{
1339 void *hdr;
1340
1341 hdr = genlmsg_put(msg, 0, seq, &nl802154_family, NLM_F_MULTI,
1342 IEEE802154_LLSEC_LIST_DEVKEY);
1343 if (!hdr)
1344 goto out;
1345
1346 if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
1347 nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
1348 nla_put_hwaddr(msg, IEEE802154_ATTR_HW_ADDR, devaddr) ||
1349 nla_put_u32(msg, IEEE802154_ATTR_LLSEC_FRAME_COUNTER,
1350 devkey->frame_counter) ||
1351 ieee802154_llsec_fill_key_id(msg, &devkey->key_id))
1352 goto nla_put_failure;
1353
1354 genlmsg_end(msg, hdr);
1355 return 0;
1356
1357nla_put_failure:
1358 genlmsg_cancel(msg, hdr);
1359out:
1360 return -EMSGSIZE;
1361}
1362
1363static int llsec_iter_devkeys(struct llsec_dump_data *data)
1364{
1365 struct ieee802154_llsec_device *dpos;
1366 struct ieee802154_llsec_device_key *kpos;
1367 int rc = 0, idx = 0, idx2;
1368
1369 list_for_each_entry(dpos, &data->table->devices, list) {
1370 if (idx++ < data->s_idx)
1371 continue;
1372
1373 idx2 = 0;
1374
1375 list_for_each_entry(kpos, &dpos->keys, list) {
1376 if (idx2++ < data->s_idx2)
1377 continue;
1378
1379 if (ieee802154_nl_fill_devkey(data->skb, data->portid,
1380 data->nlmsg_seq,
1381 dpos->hwaddr, kpos,
1382 data->dev)) {
1383 return rc = -EMSGSIZE;
1384 }
1385
1386 data->s_idx2++;
1387 }
1388
1389 data->s_idx++;
1390 }
1391
1392 return rc;
1393}
1394
1395int ieee802154_llsec_dump_devkeys(struct sk_buff *skb,
1396 struct netlink_callback *cb)
1397{
1398 return ieee802154_llsec_dump_table(skb, cb, llsec_iter_devkeys);
1399}
1400
1401
1402
1403static int
1404llsec_parse_seclevel(struct genl_info *info,
1405 struct ieee802154_llsec_seclevel *sl)
1406{
1407 memset(sl, 0, sizeof(*sl));
1408
1409 if (!info->attrs[IEEE802154_ATTR_LLSEC_FRAME_TYPE] ||
1410 !info->attrs[IEEE802154_ATTR_LLSEC_SECLEVELS] ||
1411 !info->attrs[IEEE802154_ATTR_LLSEC_DEV_OVERRIDE])
1412 return -EINVAL;
1413
1414 sl->frame_type = nla_get_u8(info->attrs[IEEE802154_ATTR_LLSEC_FRAME_TYPE]);
1415 if (sl->frame_type == IEEE802154_FC_TYPE_MAC_CMD) {
1416 if (!info->attrs[IEEE802154_ATTR_LLSEC_CMD_FRAME_ID])
1417 return -EINVAL;
1418
1419 sl->cmd_frame_id = nla_get_u8(info->attrs[IEEE802154_ATTR_LLSEC_CMD_FRAME_ID]);
1420 }
1421
1422 sl->sec_levels = nla_get_u8(info->attrs[IEEE802154_ATTR_LLSEC_SECLEVELS]);
1423 sl->device_override = nla_get_u8(info->attrs[IEEE802154_ATTR_LLSEC_DEV_OVERRIDE]);
1424
1425 return 0;
1426}
1427
1428static int llsec_add_seclevel(struct net_device *dev, struct genl_info *info)
1429{
1430 struct ieee802154_mlme_ops *ops = ieee802154_mlme_ops(dev);
1431 struct ieee802154_llsec_seclevel sl;
1432
1433 if (llsec_parse_seclevel(info, &sl))
1434 return -EINVAL;
1435
1436 return ops->llsec->add_seclevel(dev, &sl);
1437}
1438
1439int ieee802154_llsec_add_seclevel(struct sk_buff *skb, struct genl_info *info)
1440{
1441 if ((info->nlhdr->nlmsg_flags & (NLM_F_CREATE | NLM_F_EXCL)) !=
1442 (NLM_F_CREATE | NLM_F_EXCL))
1443 return -EINVAL;
1444
1445 return ieee802154_nl_llsec_change(skb, info, llsec_add_seclevel);
1446}
1447
1448static int llsec_del_seclevel(struct net_device *dev, struct genl_info *info)
1449{
1450 struct ieee802154_mlme_ops *ops = ieee802154_mlme_ops(dev);
1451 struct ieee802154_llsec_seclevel sl;
1452
1453 if (llsec_parse_seclevel(info, &sl))
1454 return -EINVAL;
1455
1456 return ops->llsec->del_seclevel(dev, &sl);
1457}
1458
1459int ieee802154_llsec_del_seclevel(struct sk_buff *skb, struct genl_info *info)
1460{
1461 return ieee802154_nl_llsec_change(skb, info, llsec_del_seclevel);
1462}
1463
1464static int
1465ieee802154_nl_fill_seclevel(struct sk_buff *msg, u32 portid, u32 seq,
1466 const struct ieee802154_llsec_seclevel *sl,
1467 const struct net_device *dev)
1468{
1469 void *hdr;
1470
1471 hdr = genlmsg_put(msg, 0, seq, &nl802154_family, NLM_F_MULTI,
1472 IEEE802154_LLSEC_LIST_SECLEVEL);
1473 if (!hdr)
1474 goto out;
1475
1476 if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
1477 nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
1478 nla_put_u8(msg, IEEE802154_ATTR_LLSEC_FRAME_TYPE, sl->frame_type) ||
1479 nla_put_u8(msg, IEEE802154_ATTR_LLSEC_SECLEVELS, sl->sec_levels) ||
1480 nla_put_u8(msg, IEEE802154_ATTR_LLSEC_DEV_OVERRIDE,
1481 sl->device_override))
1482 goto nla_put_failure;
1483
1484 if (sl->frame_type == IEEE802154_FC_TYPE_MAC_CMD &&
1485 nla_put_u8(msg, IEEE802154_ATTR_LLSEC_CMD_FRAME_ID,
1486 sl->cmd_frame_id))
1487 goto nla_put_failure;
1488
1489 genlmsg_end(msg, hdr);
1490 return 0;
1491
1492nla_put_failure:
1493 genlmsg_cancel(msg, hdr);
1494out:
1495 return -EMSGSIZE;
1496}
1497
1498static int llsec_iter_seclevels(struct llsec_dump_data *data)
1499{
1500 struct ieee802154_llsec_seclevel *pos;
1501 int rc = 0, idx = 0;
1502
1503 list_for_each_entry(pos, &data->table->security_levels, list) {
1504 if (idx++ < data->s_idx)
1505 continue;
1506
1507 if (ieee802154_nl_fill_seclevel(data->skb, data->portid,
1508 data->nlmsg_seq, pos,
1509 data->dev)) {
1510 rc = -EMSGSIZE;
1511 break;
1512 }
1513
1514 data->s_idx++;
1515 }
1516
1517 return rc;
1518}
1519
1520int ieee802154_llsec_dump_seclevels(struct sk_buff *skb,
1521 struct netlink_callback *cb)
1522{
1523 return ieee802154_llsec_dump_table(skb, cb, llsec_iter_seclevels);
1524}
diff --git a/net/ieee802154/nl_policy.c b/net/ieee802154/nl_policy.c
index fd7be5e45cef..3a703ab88348 100644
--- a/net/ieee802154/nl_policy.c
+++ b/net/ieee802154/nl_policy.c
@@ -62,5 +62,21 @@ const struct nla_policy ieee802154_policy[IEEE802154_ATTR_MAX + 1] = {
62 [IEEE802154_ATTR_CSMA_MAX_BE] = { .type = NLA_U8, }, 62 [IEEE802154_ATTR_CSMA_MAX_BE] = { .type = NLA_U8, },
63 63
64 [IEEE802154_ATTR_FRAME_RETRIES] = { .type = NLA_S8, }, 64 [IEEE802154_ATTR_FRAME_RETRIES] = { .type = NLA_S8, },
65
66 [IEEE802154_ATTR_LLSEC_ENABLED] = { .type = NLA_U8, },
67 [IEEE802154_ATTR_LLSEC_SECLEVEL] = { .type = NLA_U8, },
68 [IEEE802154_ATTR_LLSEC_KEY_MODE] = { .type = NLA_U8, },
69 [IEEE802154_ATTR_LLSEC_KEY_SOURCE_SHORT] = { .type = NLA_U32, },
70 [IEEE802154_ATTR_LLSEC_KEY_SOURCE_EXTENDED] = { .type = NLA_HW_ADDR, },
71 [IEEE802154_ATTR_LLSEC_KEY_ID] = { .type = NLA_U8, },
72 [IEEE802154_ATTR_LLSEC_FRAME_COUNTER] = { .type = NLA_U32 },
73 [IEEE802154_ATTR_LLSEC_KEY_BYTES] = { .len = 16, },
74 [IEEE802154_ATTR_LLSEC_KEY_USAGE_FRAME_TYPES] = { .type = NLA_U8, },
75 [IEEE802154_ATTR_LLSEC_KEY_USAGE_COMMANDS] = { .len = 258 / 8 },
76 [IEEE802154_ATTR_LLSEC_FRAME_TYPE] = { .type = NLA_U8, },
77 [IEEE802154_ATTR_LLSEC_CMD_FRAME_ID] = { .type = NLA_U8, },
78 [IEEE802154_ATTR_LLSEC_SECLEVELS] = { .type = NLA_U8, },
79 [IEEE802154_ATTR_LLSEC_DEV_OVERRIDE] = { .type = NLA_U8, },
80 [IEEE802154_ATTR_LLSEC_DEV_KEY_MODE] = { .type = NLA_U8, },
65}; 81};
66 82