2 * This is the new netlink-based wireless configuration interface.
4 * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
8 #include <linux/module.h>
10 #include <linux/mutex.h>
11 #include <linux/list.h>
12 #include <linux/if_ether.h>
13 #include <linux/ieee80211.h>
14 #include <linux/nl80211.h>
15 #include <linux/rtnetlink.h>
16 #include <net/genetlink.h>
17 #include <net/cfg80211.h>
21 /* the netlink family */
22 static struct genl_family nl80211_fam
= {
23 .id
= GENL_ID_GENERATE
, /* don't bother with a hardcoded ID */
24 .name
= "nl80211", /* have users key off the name instead */
25 .hdrsize
= 0, /* no private header */
26 .version
= 1, /* no particular meaning now */
27 .maxattr
= NL80211_ATTR_MAX
,
30 /* internal helper: validate an information element attribute */
31 static int check_information_element(struct nlattr
*nla
)
33 int len
= nla_len(nla
);
34 u8
*data
= nla_data(nla
);
38 /* 1 byte ID, 1 byte len, `len' bytes data */
39 elementlen
= *(data
+1) + 2;
43 return len
? -EINVAL
: 0;
46 /* internal helper: get drv and dev */
47 static int get_drv_dev_by_info_ifindex(struct genl_info
*info
,
48 struct cfg80211_registered_device
**drv
,
49 struct net_device
**dev
)
53 if (!info
->attrs
[NL80211_ATTR_IFINDEX
])
56 ifindex
= nla_get_u32(info
->attrs
[NL80211_ATTR_IFINDEX
]);
57 *dev
= dev_get_by_index(ifindex
);
61 *drv
= cfg80211_get_dev_from_ifindex(ifindex
);
70 /* policy for the attributes */
71 static struct nla_policy nl80211_policy
[NL80211_ATTR_MAX
+1] __read_mostly
= {
72 [NL80211_ATTR_IFINDEX
] = { .type
= NLA_U32
},
73 [NL80211_ATTR_IFNAME
] = { .type
= NLA_NUL_STRING
, .len
= IFNAMSIZ
-1 },
74 [NL80211_ATTR_WIPHY
] = { .type
= NLA_U32
},
75 [NL80211_ATTR_WIPHY_NAME
] = { .type
= NLA_NUL_STRING
,
76 .len
= BUS_ID_SIZE
-1 },
77 [NL80211_ATTR_IFTYPE
] = { .type
= NLA_U32
},
78 [NL80211_ATTR_BSSID
] = { .len
= ETH_ALEN
},
79 [NL80211_ATTR_SSID
] = { .type
= NLA_BINARY
,
80 .len
= IEEE80211_MAX_SSID_LEN
},
81 [NL80211_ATTR_CHANNEL
] = { .type
= NLA_U32
},
82 [NL80211_ATTR_PHYMODE
] = { .type
= NLA_U32
},
83 [NL80211_ATTR_CHANNEL_LIST
] = { .type
= NLA_NESTED
},
84 [NL80211_ATTR_BSS_LIST
] = { .type
= NLA_NESTED
},
85 [NL80211_ATTR_BSSTYPE
] = { .type
= NLA_U32
},
86 [NL80211_ATTR_BEACON_PERIOD
] = { .type
= NLA_U32
},
87 [NL80211_ATTR_DTIM_PERIOD
] = { .type
= NLA_U32
},
88 [NL80211_ATTR_TIMESTAMP
] = { .type
= NLA_U64
},
89 [NL80211_ATTR_IE
] = { .type
= NLA_BINARY
, .len
= NL80211_MAX_IE_LEN
},
90 [NL80211_ATTR_AUTH_ALGORITHM
] = { .type
= NLA_U32
},
91 [NL80211_ATTR_TIMEOUT_TU
] = { .type
= NLA_U32
},
92 [NL80211_ATTR_REASON_CODE
] = { .type
= NLA_U32
},
93 [NL80211_ATTR_ASSOCIATION_ID
] = { .type
= NLA_U16
},
94 [NL80211_ATTR_DEAUTHENTICATED
] = { .type
= NLA_FLAG
},
95 [NL80211_ATTR_RX_SENSITIVITY
] = { .type
= NLA_U32
},
96 [NL80211_ATTR_TRANSMIT_POWER
] = { .type
= NLA_U32
},
97 [NL80211_ATTR_FRAG_THRESHOLD
] = { .type
= NLA_U32
},
98 [NL80211_ATTR_FLAG_SCAN_ACTIVE
] = { .type
= NLA_FLAG
},
99 [NL80211_ATTR_BEACON_HEAD
] = { .type
= NLA_BINARY
},
100 [NL80211_ATTR_BEACON_TAIL
] = { .type
= NLA_BINARY
},
101 [NL80211_ATTR_KEY_DATA
] = { .type
= NLA_BINARY
,
102 .len
= WLAN_MAX_KEY_LEN
},
103 [NL80211_ATTR_KEY_ID
] = { .type
= NLA_U32
},
104 [NL80211_ATTR_KEY_TYPE
] = { .type
= NLA_U32
},
105 [NL80211_ATTR_MAC
] = { .len
= ETH_ALEN
},
106 [NL80211_ATTR_KEY_CIPHER
] = { .type
= NLA_U32
},
109 /* netlink command implementations */
111 #define CHECK_CMD(ptr, cmd) \
113 NLA_PUT_FLAG(msg, NL80211_CMD_##cmd);
115 static int nl80211_get_cmdlist(struct sk_buff
*skb
, struct genl_info
*info
)
117 struct cfg80211_registered_device
*drv
;
121 struct nlattr
*start
;
123 drv
= cfg80211_get_dev_from_info(info
);
127 hdr
= nl80211msg_new(&msg
, info
->snd_pid
, info
->snd_seq
, 0,
128 NL80211_CMD_NEW_CMDLIST
);
134 NLA_PUT_U32(msg
, NL80211_ATTR_WIPHY
, drv
->idx
);
136 start
= nla_nest_start(msg
, NL80211_ATTR_CMDS
);
138 goto nla_put_failure
;
140 /* unconditionally allow some common commands we handle centrally
141 * or where we require the implementation */
142 NLA_PUT_FLAG(msg
, NL80211_CMD_GET_CMDLIST
);
143 NLA_PUT_FLAG(msg
, NL80211_CMD_GET_WIPHYS
);
144 NLA_PUT_FLAG(msg
, NL80211_CMD_GET_INTERFACES
);
145 NLA_PUT_FLAG(msg
, NL80211_CMD_RENAME_WIPHY
);
147 CHECK_CMD(add_virtual_intf
, ADD_VIRTUAL_INTERFACE
);
148 CHECK_CMD(del_virtual_intf
, DEL_VIRTUAL_INTERFACE
);
149 CHECK_CMD(associate
, ASSOCIATE
);
150 CHECK_CMD(disassociate
, DISASSOCIATE
);
151 CHECK_CMD(deauth
, DEAUTH
);
152 CHECK_CMD(initiate_scan
, INITIATE_SCAN
);
153 CHECK_CMD(get_association
, GET_ASSOCIATION
);
154 CHECK_CMD(get_auth_list
, GET_AUTH_LIST
);
155 CHECK_CMD(add_key
, ADD_KEY
);
156 CHECK_CMD(del_key
, DEL_KEY
);
158 nla_nest_end(msg
, start
);
160 genlmsg_end(msg
, hdr
);
162 err
= genlmsg_unicast(msg
, info
->snd_pid
);
169 cfg80211_put_dev(drv
);
174 static int nl80211_get_wiphys(struct sk_buff
*skb
, struct genl_info
*info
)
178 struct nlattr
*start
, *indexstart
;
179 struct cfg80211_registered_device
*drv
;
182 hdr
= nl80211msg_new(&msg
, info
->snd_pid
, info
->snd_seq
, 0,
183 NL80211_CMD_NEW_WIPHYS
);
187 start
= nla_nest_start(msg
, NL80211_ATTR_WIPHY_LIST
);
189 goto nla_outer_nest_failure
;
191 mutex_lock(&cfg80211_drv_mutex
);
192 list_for_each_entry(drv
, &cfg80211_drv_list
, list
) {
193 indexstart
= nla_nest_start(msg
, idx
++);
195 goto nla_put_failure
;
196 NLA_PUT_U32(msg
, NL80211_ATTR_WIPHY
, drv
->idx
);
197 nla_nest_end(msg
, indexstart
);
199 mutex_unlock(&cfg80211_drv_mutex
);
201 nla_nest_end(msg
, start
);
203 genlmsg_end(msg
, hdr
);
205 return genlmsg_unicast(msg
, info
->snd_pid
);
208 mutex_unlock(&cfg80211_drv_mutex
);
209 nla_outer_nest_failure
:
214 static int addifidx(struct net_device
*dev
, struct sk_buff
*skb
, int *idx
)
217 struct nlattr
*start
;
221 start
= nla_nest_start(skb
, *idx
++);
223 goto nla_put_failure
;
225 NLA_PUT_U32(skb
, NL80211_ATTR_IFINDEX
, dev
->ifindex
);
226 NLA_PUT_STRING(skb
, NL80211_ATTR_IFNAME
, dev
->name
);
228 nla_nest_end(skb
, start
);
236 static int nl80211_get_intfs(struct sk_buff
*skb
, struct genl_info
*info
)
238 struct cfg80211_registered_device
*drv
;
242 struct nlattr
*start
;
243 struct wireless_dev
*wdev
;
245 drv
= cfg80211_get_dev_from_info(info
);
249 hdr
= nl80211msg_new(&msg
, info
->snd_pid
, info
->snd_seq
, 0,
250 NL80211_CMD_NEW_INTERFACES
);
256 NLA_PUT_U32(msg
, NL80211_ATTR_WIPHY
, drv
->idx
);
258 start
= nla_nest_start(msg
, NL80211_ATTR_INTERFACE_LIST
);
266 mutex_lock(&drv
->devlist_mtx
);
267 list_for_each_entry(wdev
, &drv
->netdev_list
, list
) {
268 err
= addifidx(wdev
->netdev
, msg
, &array_idx
);
272 mutex_unlock(&drv
->devlist_mtx
);
276 nla_nest_end(msg
, start
);
278 genlmsg_end(msg
, hdr
);
280 err
= genlmsg_unicast(msg
, info
->snd_pid
);
288 cfg80211_put_dev(drv
);
292 static int nl80211_add_virt_intf(struct sk_buff
*skb
, struct genl_info
*info
)
294 struct cfg80211_registered_device
*drv
;
296 enum nl80211_iftype type
= NL80211_IFTYPE_UNSPECIFIED
;
298 if (!info
->attrs
[NL80211_ATTR_IFNAME
])
301 if (info
->attrs
[NL80211_ATTR_IFTYPE
]) {
302 type
= nla_get_u32(info
->attrs
[NL80211_ATTR_IFTYPE
]);
303 if (type
> NL80211_IFTYPE_MAX
)
307 drv
= cfg80211_get_dev_from_info(info
);
311 if (!drv
->ops
->add_virtual_intf
) {
317 err
= drv
->ops
->add_virtual_intf(&drv
->wiphy
,
318 nla_data(info
->attrs
[NL80211_ATTR_IFNAME
]), type
);
322 cfg80211_put_dev(drv
);
326 static int nl80211_del_virt_intf(struct sk_buff
*skb
, struct genl_info
*info
)
328 struct cfg80211_registered_device
*drv
;
330 struct net_device
*dev
;
332 err
= get_drv_dev_by_info_ifindex(info
, &drv
, &dev
);
335 ifindex
= dev
->ifindex
;
338 if (!drv
->ops
->del_virtual_intf
) {
344 err
= drv
->ops
->del_virtual_intf(&drv
->wiphy
, ifindex
);
348 cfg80211_put_dev(drv
);
352 static int nl80211_change_virt_intf(struct sk_buff
*skb
, struct genl_info
*info
)
354 struct cfg80211_registered_device
*drv
;
356 enum nl80211_iftype type
;
357 struct net_device
*dev
;
359 if (info
->attrs
[NL80211_ATTR_IFTYPE
]) {
360 type
= nla_get_u32(info
->attrs
[NL80211_ATTR_IFTYPE
]);
361 if (type
> NL80211_IFTYPE_MAX
)
366 err
= get_drv_dev_by_info_ifindex(info
, &drv
, &dev
);
369 ifindex
= dev
->ifindex
;
372 if (!drv
->ops
->change_virtual_intf
) {
378 err
= drv
->ops
->change_virtual_intf(&drv
->wiphy
, ifindex
, type
);
382 cfg80211_put_dev(drv
);
386 static int nl80211_get_association(struct sk_buff
*skb
, struct genl_info
*info
)
388 struct cfg80211_registered_device
*drv
;
390 struct net_device
*dev
;
395 err
= get_drv_dev_by_info_ifindex(info
, &drv
, &dev
);
399 if (!drv
->ops
->get_association
) {
405 err
= drv
->ops
->get_association(&drv
->wiphy
, dev
, bssid
);
410 hdr
= nl80211msg_new(&msg
, info
->snd_pid
, info
->snd_seq
, 0,
411 NL80211_CMD_ASSOCIATION_CHANGED
);
418 NLA_PUT_U32(msg
, NL80211_ATTR_IFINDEX
, dev
->ifindex
);
420 NLA_PUT(msg
, NL80211_ATTR_BSSID
, ETH_ALEN
, bssid
);
422 genlmsg_end(msg
, hdr
);
423 err
= genlmsg_unicast(msg
, info
->snd_pid
);
430 cfg80211_put_dev(drv
);
435 static int nl80211_associate(struct sk_buff
*skb
, struct genl_info
*info
)
437 struct cfg80211_registered_device
*drv
;
439 struct net_device
*dev
;
440 struct association_params assoc_params
;
442 memset(&assoc_params
, 0, sizeof(assoc_params
));
444 err
= get_drv_dev_by_info_ifindex(info
, &drv
, &dev
);
448 if (!drv
->ops
->associate
) {
453 if (!info
->attrs
[NL80211_ATTR_SSID
])
456 assoc_params
.ssid
= nla_data(info
->attrs
[NL80211_ATTR_SSID
]);
457 assoc_params
.ssid_len
= nla_len(info
->attrs
[NL80211_ATTR_SSID
]);
459 if (info
->attrs
[NL80211_ATTR_BSSID
])
460 assoc_params
.bssid
= nla_data(info
->attrs
[NL80211_ATTR_BSSID
]);
462 if (info
->attrs
[NL80211_ATTR_IE
]) {
463 err
= check_information_element(info
->attrs
[NL80211_ATTR_IE
]);
466 assoc_params
.ie
= nla_data(info
->attrs
[NL80211_ATTR_IE
]);
467 assoc_params
.ie_len
= nla_len(info
->attrs
[NL80211_ATTR_IE
]);
470 if (info
->attrs
[NL80211_ATTR_TIMEOUT_TU
]) {
471 assoc_params
.timeout
=
472 nla_get_u32(info
->attrs
[NL80211_ATTR_TIMEOUT_TU
]);
473 assoc_params
.valid
|= ASSOC_PARAMS_TIMEOUT
;
477 err
= drv
->ops
->associate(&drv
->wiphy
, dev
, &assoc_params
);
481 cfg80211_put_dev(drv
);
486 static int nl80211_disassoc_deauth(struct sk_buff
*skb
, struct genl_info
*info
)
488 struct cfg80211_registered_device
*drv
;
490 struct net_device
*dev
;
491 int (*act
)(struct wiphy
*wiphy
, struct net_device
*dev
);
493 err
= get_drv_dev_by_info_ifindex(info
, &drv
, &dev
);
497 switch (info
->genlhdr
->cmd
) {
498 case NL80211_CMD_DISASSOCIATE
:
499 act
= drv
->ops
->disassociate
;
501 case NL80211_CMD_DEAUTH
:
502 act
= drv
->ops
->deauth
;
514 err
= act(&drv
->wiphy
, dev
);
517 cfg80211_put_dev(drv
);
527 static int add_bssid(void *data
, u8
*bssid
)
529 struct add_cb_data
*cb
= data
;
531 struct nlattr
*start
;
533 start
= nla_nest_start(cb
->skb
, cb
->idx
++);
535 goto nla_put_failure
;
537 NLA_PUT(cb
->skb
, NL80211_ATTR_BSSID
, ETH_ALEN
, bssid
);
539 nla_nest_end(cb
->skb
, start
);
546 static int nl80211_get_auth_list(struct sk_buff
*skb
, struct genl_info
*info
)
548 struct cfg80211_registered_device
*drv
;
549 struct net_device
*dev
;
553 struct nlattr
*start
;
554 struct add_cb_data cb
;
556 err
= get_drv_dev_by_info_ifindex(info
, &drv
, &dev
);
560 if (!drv
->ops
->get_auth_list
) {
565 hdr
= nl80211msg_new(&msg
, info
->snd_pid
, info
->snd_seq
, 0,
566 NL80211_CMD_NEW_AUTH_LIST
);
572 NLA_PUT_U32(msg
, NL80211_ATTR_IFINDEX
, dev
->ifindex
);
574 start
= nla_nest_start(msg
, NL80211_ATTR_BSS_LIST
);
583 err
= drv
->ops
->get_auth_list(&drv
->wiphy
, dev
, &cb
, add_bssid
);
588 nla_nest_end(msg
, start
);
590 genlmsg_end(msg
, hdr
);
592 err
= genlmsg_unicast(msg
, info
->snd_pid
);
600 cfg80211_put_dev(drv
);
605 static int nl80211_initiate_scan(struct sk_buff
*skb
, struct genl_info
*info
)
607 struct cfg80211_registered_device
*drv
;
609 struct net_device
*dev
;
610 struct scan_params params
;
611 struct scan_channel
*channels
= NULL
;
614 if (info
->attrs
[NL80211_ATTR_PHYMODE
])
615 params
.phymode
= nla_get_u32(info
->attrs
[NL80211_ATTR_PHYMODE
]);
617 if (params
.phymode
> NL80211_PHYMODE_MAX
)
620 err
= get_drv_dev_by_info_ifindex(info
, &drv
, &dev
);
624 if (!drv
->ops
->initiate_scan
) {
629 params
.active
= nla_get_flag(info
->attrs
[NL80211_ATTR_FLAG_SCAN_ACTIVE
]);
631 if (info
->attrs
[NL80211_ATTR_CHANNEL_LIST
]) {
632 struct nlattr
*attr
= info
->attrs
[NL80211_ATTR_CHANNEL_LIST
];
637 /* let's count first */
639 nla_for_each_attr(nla
, nla_data(attr
), nla_len(attr
), rem
)
643 /* assume we should actually scan all channels,
644 * scanning no channels make no sense */
649 if (count
> NL80211_MAX_CHANNEL_LIST_ITEM
) {
654 channels
= kmalloc(count
* sizeof(struct scan_channel
),
656 tb
= kmalloc((NL80211_ATTR_MAX
+1) * sizeof(struct nlattr
),
660 nla_for_each_attr(nla
, nla_data(attr
), nla_len(attr
), rem
) {
661 err
= nla_parse(tb
, NL80211_ATTR_MAX
, nla_data(nla
),
662 nla_len(nla
), nl80211_policy
);
664 if (err
|| !tb
[NL80211_ATTR_CHANNEL
]) {
671 channels
[count
].phymode
= params
.phymode
;
673 if (tb
[NL80211_ATTR_PHYMODE
])
674 channels
[count
].phymode
=
675 nla_get_u32(tb
[NL80211_ATTR_PHYMODE
]);
677 if (channels
[count
].phymode
> NL80211_PHYMODE_MAX
) {
684 channels
[count
].channel
=
685 nla_get_u32(tb
[NL80211_ATTR_CHANNEL
]);
687 channels
[count
].active
=
688 nla_get_flag(tb
[NL80211_ATTR_FLAG_SCAN_ACTIVE
]);
695 params
.channels
= channels
;
696 params
.n_channels
= count
;
699 err
= drv
->ops
->initiate_scan(&drv
->wiphy
, dev
, ¶ms
);
704 cfg80211_put_dev(drv
);
709 static int nl80211_rename_wiphy(struct sk_buff
*skb
, struct genl_info
*info
)
711 struct cfg80211_registered_device
*rdev
;
714 if (!info
->attrs
[NL80211_ATTR_WIPHY_NAME
])
717 rdev
= cfg80211_get_dev_from_info(info
);
719 return PTR_ERR(rdev
);
721 result
= cfg80211_dev_rename(rdev
, nla_data(info
->attrs
[NL80211_ATTR_WIPHY_NAME
]));
723 cfg80211_put_dev(rdev
);
727 static int nl80211_key_cmd(struct sk_buff
*skb
, struct genl_info
*info
)
729 struct cfg80211_registered_device
*drv
;
731 struct net_device
*dev
;
732 struct key_params params
;
733 int (*act
)(struct wiphy
*wiphy
, struct net_device
*dev
,
734 struct key_params
*params
);
736 memset(¶ms
, 0, sizeof(params
));
738 if (!info
->attrs
[NL80211_ATTR_KEY_TYPE
])
741 if (!info
->attrs
[NL80211_ATTR_KEY_CIPHER
])
744 params
.key_type
= nla_get_u32(info
->attrs
[NL80211_ATTR_KEY_TYPE
]);
745 if (params
.key_type
> NL80211_KEYTYPE_MAX
)
748 err
= get_drv_dev_by_info_ifindex(info
, &drv
, &dev
);
752 switch (info
->genlhdr
->cmd
) {
753 case NL80211_CMD_ADD_KEY
:
754 act
= drv
->ops
->add_key
;
757 case NL80211_CMD_DEL_KEY
:
758 act
= drv
->ops
->del_key
;
770 if (info
->attrs
[NL80211_ATTR_KEY_DATA
]) {
771 params
.key
= nla_data(info
->attrs
[NL80211_ATTR_KEY_DATA
]);
772 params
.key_len
= nla_len(info
->attrs
[NL80211_ATTR_KEY_DATA
]);
775 if (info
->attrs
[NL80211_ATTR_KEY_ID
]) {
776 params
.key_id
= nla_get_u32(info
->attrs
[NL80211_ATTR_KEY_ID
]);
781 params
.cipher
= nla_get_u32(info
->attrs
[NL80211_ATTR_KEY_CIPHER
]);
783 if (info
->attrs
[NL80211_ATTR_MAC
]) {
784 params
.macaddress
= nla_data(info
->attrs
[NL80211_ATTR_MAC
]);
786 params
.macaddress
= NULL
;
790 err
= act(&drv
->wiphy
, dev
, ¶ms
);
794 cfg80211_put_dev(drv
);
799 static struct genl_ops nl80211_ops
[] = {
801 .cmd
= NL80211_CMD_RENAME_WIPHY
,
802 .doit
= nl80211_rename_wiphy
,
803 .policy
= nl80211_policy
,
804 .flags
= GENL_ADMIN_PERM
,
807 .cmd
= NL80211_CMD_GET_CMDLIST
,
808 .doit
= nl80211_get_cmdlist
,
809 .policy
= nl80211_policy
,
810 /* can be retrieved by unprivileged users */
813 .cmd
= NL80211_CMD_ADD_VIRTUAL_INTERFACE
,
814 .doit
= nl80211_add_virt_intf
,
815 .policy
= nl80211_policy
,
816 .flags
= GENL_ADMIN_PERM
,
819 .cmd
= NL80211_CMD_DEL_VIRTUAL_INTERFACE
,
820 .doit
= nl80211_del_virt_intf
,
821 .policy
= nl80211_policy
,
822 .flags
= GENL_ADMIN_PERM
,
825 .cmd
= NL80211_CMD_CHANGE_VIRTUAL_INTERFACE
,
826 .doit
= nl80211_change_virt_intf
,
827 .policy
= nl80211_policy
,
828 .flags
= GENL_ADMIN_PERM
,
831 .cmd
= NL80211_CMD_GET_WIPHYS
,
832 .doit
= nl80211_get_wiphys
,
833 .policy
= nl80211_policy
,
834 /* can be retrieved by unprivileged users */
837 .cmd
= NL80211_CMD_GET_INTERFACES
,
838 .doit
= nl80211_get_intfs
,
839 .policy
= nl80211_policy
,
840 /* can be retrieved by unprivileged users */
843 .cmd
= NL80211_CMD_INITIATE_SCAN
,
844 .doit
= nl80211_initiate_scan
,
845 .policy
= nl80211_policy
,
846 .flags
= GENL_ADMIN_PERM
,
849 .cmd
= NL80211_CMD_GET_ASSOCIATION
,
850 .doit
= nl80211_get_association
,
851 .policy
= nl80211_policy
,
852 /* can be retrieved by unprivileged users */
855 .cmd
= NL80211_CMD_ASSOCIATE
,
856 .doit
= nl80211_associate
,
857 .policy
= nl80211_policy
,
858 .flags
= GENL_ADMIN_PERM
,
861 .cmd
= NL80211_CMD_DISASSOCIATE
,
862 .doit
= nl80211_disassoc_deauth
,
863 .policy
= nl80211_policy
,
864 .flags
= GENL_ADMIN_PERM
,
867 .cmd
= NL80211_CMD_DEAUTH
,
868 .doit
= nl80211_disassoc_deauth
,
869 .policy
= nl80211_policy
,
870 .flags
= GENL_ADMIN_PERM
,
873 .cmd
= NL80211_CMD_GET_AUTH_LIST
,
874 .doit
= nl80211_get_auth_list
,
875 .policy
= nl80211_policy
,
876 /* can be retrieved by unprivileged users */
880 .cmd = NL80211_CMD_AP_SET_BEACON,
881 .policy = nl80211_policy,
882 .flags = GENL_ADMIN_PERM,
885 .cmd = NL80211_CMD_AP_ADD_STA,
886 .policy = nl80211_policy,
887 .flags = GENL_ADMIN_PERM,
890 .cmd = NL80211_CMD_AP_UPDATE_STA,
891 .policy = nl80211_policy,
892 .flags = GENL_ADMIN_PERM,
895 .cmd = NL80211_CMD_AP_GET_STA_INFO,
896 .policy = nl80211_policy,
897 .flags = GENL_ADMIN_PERM,
900 .cmd = NL80211_CMD_AP_SET_RATESETS,
901 .policy = nl80211_policy,
902 .flags = GENL_ADMIN_PERM,
906 .cmd
= NL80211_CMD_ADD_KEY
,
907 .doit
= nl80211_key_cmd
,
908 .policy
= nl80211_policy
,
909 .flags
= GENL_ADMIN_PERM
,
912 .cmd
= NL80211_CMD_DEL_KEY
,
913 .doit
= nl80211_key_cmd
,
914 .policy
= nl80211_policy
,
915 .flags
= GENL_ADMIN_PERM
,
920 /* exported functions */
922 void *nl80211hdr_put(struct sk_buff
*skb
, u32 pid
, u32 seq
, int flags
, u8 cmd
)
924 /* since there is no private header just add the generic one */
925 return genlmsg_put(skb
, pid
, seq
, &nl80211_fam
, flags
, cmd
);
927 EXPORT_SYMBOL_GPL(nl80211hdr_put
);
929 void *nl80211msg_new(struct sk_buff
**skb
, u32 pid
, u32 seq
, int flags
, u8 cmd
)
933 *skb
= nlmsg_new(NLMSG_GOODSIZE
, GFP_KERNEL
);
935 return ERR_PTR(-ENOBUFS
);
937 hdr
= nl80211hdr_put(*skb
, pid
, seq
, flags
, cmd
);
940 return ERR_PTR(-ENOBUFS
);
945 EXPORT_SYMBOL_GPL(nl80211msg_new
);
947 /* notification functions */
949 void nl80211_notify_dev_rename(struct cfg80211_registered_device
*rdev
)
954 hdr
= nl80211msg_new(&msg
, 0, 0, 0, NL80211_CMD_WIPHY_NEWNAME
);
958 NLA_PUT_U32(msg
, NL80211_ATTR_WIPHY
, rdev
->idx
);
959 NLA_PUT_STRING(msg
, NL80211_ATTR_WIPHY_NAME
, wiphy_name(&rdev
->wiphy
));
961 genlmsg_end(msg
, hdr
);
962 genlmsg_multicast(msg
, 0, NL80211_GROUP_CONFIG
, GFP_KERNEL
);
970 /* initialisation/exit functions */
972 int nl80211_init(void)
976 err
= genl_register_family(&nl80211_fam
);
980 for (i
= 0; i
< ARRAY_SIZE(nl80211_ops
); i
++) {
981 err
= genl_register_ops(&nl80211_fam
, &nl80211_ops
[i
]);
987 genl_unregister_family(&nl80211_fam
);
991 void nl80211_exit(void)
993 genl_unregister_family(&nl80211_fam
);