diff options
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r-- | net/wireless/nl80211.c | 419 |
1 files changed, 323 insertions, 96 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 48260c2d092a..6bc7c4b32fa5 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -98,7 +98,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
98 | [NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 }, | 98 | [NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 }, |
99 | [NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 }, | 99 | [NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 }, |
100 | [NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG }, | 100 | [NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG }, |
101 | [NL80211_ATTR_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 }, | 101 | [NL80211_ATTR_KEY_SEQ] = { .type = NLA_BINARY, .len = 16 }, |
102 | [NL80211_ATTR_KEY_TYPE] = { .type = NLA_U32 }, | 102 | [NL80211_ATTR_KEY_TYPE] = { .type = NLA_U32 }, |
103 | 103 | ||
104 | [NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 }, | 104 | [NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 }, |
@@ -132,8 +132,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
132 | [NL80211_ATTR_MESH_CONFIG] = { .type = NLA_NESTED }, | 132 | [NL80211_ATTR_MESH_CONFIG] = { .type = NLA_NESTED }, |
133 | [NL80211_ATTR_SUPPORT_MESH_AUTH] = { .type = NLA_FLAG }, | 133 | [NL80211_ATTR_SUPPORT_MESH_AUTH] = { .type = NLA_FLAG }, |
134 | 134 | ||
135 | [NL80211_ATTR_HT_CAPABILITY] = { .type = NLA_BINARY, | 135 | [NL80211_ATTR_HT_CAPABILITY] = { .len = NL80211_HT_CAPABILITY_LEN }, |
136 | .len = NL80211_HT_CAPABILITY_LEN }, | ||
137 | 136 | ||
138 | [NL80211_ATTR_MGMT_SUBTYPE] = { .type = NLA_U8 }, | 137 | [NL80211_ATTR_MGMT_SUBTYPE] = { .type = NLA_U8 }, |
139 | [NL80211_ATTR_IE] = { .type = NLA_BINARY, | 138 | [NL80211_ATTR_IE] = { .type = NLA_BINARY, |
@@ -197,6 +196,9 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
197 | [NL80211_ATTR_TDLS_OPERATION] = { .type = NLA_U8 }, | 196 | [NL80211_ATTR_TDLS_OPERATION] = { .type = NLA_U8 }, |
198 | [NL80211_ATTR_TDLS_SUPPORT] = { .type = NLA_FLAG }, | 197 | [NL80211_ATTR_TDLS_SUPPORT] = { .type = NLA_FLAG }, |
199 | [NL80211_ATTR_TDLS_EXTERNAL_SETUP] = { .type = NLA_FLAG }, | 198 | [NL80211_ATTR_TDLS_EXTERNAL_SETUP] = { .type = NLA_FLAG }, |
199 | [NL80211_ATTR_DONT_WAIT_FOR_ACK] = { .type = NLA_FLAG }, | ||
200 | [NL80211_ATTR_PROBE_RESP] = { .type = NLA_BINARY, | ||
201 | .len = IEEE80211_MAX_DATA_LEN }, | ||
200 | }; | 202 | }; |
201 | 203 | ||
202 | /* policy for the key attributes */ | 204 | /* policy for the key attributes */ |
@@ -204,7 +206,7 @@ static const struct nla_policy nl80211_key_policy[NL80211_KEY_MAX + 1] = { | |||
204 | [NL80211_KEY_DATA] = { .type = NLA_BINARY, .len = WLAN_MAX_KEY_LEN }, | 206 | [NL80211_KEY_DATA] = { .type = NLA_BINARY, .len = WLAN_MAX_KEY_LEN }, |
205 | [NL80211_KEY_IDX] = { .type = NLA_U8 }, | 207 | [NL80211_KEY_IDX] = { .type = NLA_U8 }, |
206 | [NL80211_KEY_CIPHER] = { .type = NLA_U32 }, | 208 | [NL80211_KEY_CIPHER] = { .type = NLA_U32 }, |
207 | [NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 }, | 209 | [NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 16 }, |
208 | [NL80211_KEY_DEFAULT] = { .type = NLA_FLAG }, | 210 | [NL80211_KEY_DEFAULT] = { .type = NLA_FLAG }, |
209 | [NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG }, | 211 | [NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG }, |
210 | [NL80211_KEY_TYPE] = { .type = NLA_U32 }, | 212 | [NL80211_KEY_TYPE] = { .type = NLA_U32 }, |
@@ -759,6 +761,10 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
759 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX, | 761 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX, |
760 | dev->wiphy.available_antennas_rx); | 762 | dev->wiphy.available_antennas_rx); |
761 | 763 | ||
764 | if (dev->wiphy.flags & WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD) | ||
765 | NLA_PUT_U32(msg, NL80211_ATTR_PROBE_RESP_OFFLOAD, | ||
766 | dev->wiphy.probe_resp_offload); | ||
767 | |||
762 | if ((dev->wiphy.available_antennas_tx || | 768 | if ((dev->wiphy.available_antennas_tx || |
763 | dev->wiphy.available_antennas_rx) && dev->ops->get_antenna) { | 769 | dev->wiphy.available_antennas_rx) && dev->ops->get_antenna) { |
764 | u32 tx_ant = 0, rx_ant = 0; | 770 | u32 tx_ant = 0, rx_ant = 0; |
@@ -891,6 +897,11 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
891 | } | 897 | } |
892 | if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) | 898 | if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) |
893 | CMD(sched_scan_start, START_SCHED_SCAN); | 899 | CMD(sched_scan_start, START_SCHED_SCAN); |
900 | CMD(probe_client, PROBE_CLIENT); | ||
901 | if (dev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS) { | ||
902 | i++; | ||
903 | NLA_PUT_U32(msg, i, NL80211_CMD_REGISTER_BEACONS); | ||
904 | } | ||
894 | 905 | ||
895 | #undef CMD | 906 | #undef CMD |
896 | 907 | ||
@@ -1008,6 +1019,12 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
1008 | if (nl80211_put_iface_combinations(&dev->wiphy, msg)) | 1019 | if (nl80211_put_iface_combinations(&dev->wiphy, msg)) |
1009 | goto nla_put_failure; | 1020 | goto nla_put_failure; |
1010 | 1021 | ||
1022 | if (dev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME) | ||
1023 | NLA_PUT_U32(msg, NL80211_ATTR_DEVICE_AP_SME, | ||
1024 | dev->wiphy.ap_sme_capa); | ||
1025 | |||
1026 | NLA_PUT_U32(msg, NL80211_ATTR_FEATURE_FLAGS, dev->wiphy.features); | ||
1027 | |||
1011 | return genlmsg_end(msg, hdr); | 1028 | return genlmsg_end(msg, hdr); |
1012 | 1029 | ||
1013 | nla_put_failure: | 1030 | nla_put_failure: |
@@ -1253,6 +1270,12 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
1253 | goto bad_res; | 1270 | goto bad_res; |
1254 | } | 1271 | } |
1255 | 1272 | ||
1273 | if (netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | ||
1274 | netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) { | ||
1275 | result = -EINVAL; | ||
1276 | goto bad_res; | ||
1277 | } | ||
1278 | |||
1256 | nla_for_each_nested(nl_txq_params, | 1279 | nla_for_each_nested(nl_txq_params, |
1257 | info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS], | 1280 | info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS], |
1258 | rem_txq_params) { | 1281 | rem_txq_params) { |
@@ -2150,6 +2173,13 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) | |||
2150 | nla_len(info->attrs[NL80211_ATTR_IE_ASSOC_RESP]); | 2173 | nla_len(info->attrs[NL80211_ATTR_IE_ASSOC_RESP]); |
2151 | } | 2174 | } |
2152 | 2175 | ||
2176 | if (info->attrs[NL80211_ATTR_PROBE_RESP]) { | ||
2177 | params.probe_resp = | ||
2178 | nla_data(info->attrs[NL80211_ATTR_PROBE_RESP]); | ||
2179 | params.probe_resp_len = | ||
2180 | nla_len(info->attrs[NL80211_ATTR_PROBE_RESP]); | ||
2181 | } | ||
2182 | |||
2153 | err = call(&rdev->wiphy, dev, ¶ms); | 2183 | err = call(&rdev->wiphy, dev, ¶ms); |
2154 | if (!err && params.interval) | 2184 | if (!err && params.interval) |
2155 | wdev->beacon_interval = params.interval; | 2185 | wdev->beacon_interval = params.interval; |
@@ -5266,12 +5296,13 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
5266 | bool channel_type_valid = false; | 5296 | bool channel_type_valid = false; |
5267 | u32 freq; | 5297 | u32 freq; |
5268 | int err; | 5298 | int err; |
5269 | void *hdr; | 5299 | void *hdr = NULL; |
5270 | u64 cookie; | 5300 | u64 cookie; |
5271 | struct sk_buff *msg; | 5301 | struct sk_buff *msg = NULL; |
5272 | unsigned int wait = 0; | 5302 | unsigned int wait = 0; |
5273 | bool offchan; | 5303 | bool offchan, no_cck, dont_wait_for_ack; |
5274 | bool no_cck; | 5304 | |
5305 | dont_wait_for_ack = info->attrs[NL80211_ATTR_DONT_WAIT_FOR_ACK]; | ||
5275 | 5306 | ||
5276 | if (!info->attrs[NL80211_ATTR_FRAME] || | 5307 | if (!info->attrs[NL80211_ATTR_FRAME] || |
5277 | !info->attrs[NL80211_ATTR_WIPHY_FREQ]) | 5308 | !info->attrs[NL80211_ATTR_WIPHY_FREQ]) |
@@ -5315,29 +5346,36 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
5315 | if (chan == NULL) | 5346 | if (chan == NULL) |
5316 | return -EINVAL; | 5347 | return -EINVAL; |
5317 | 5348 | ||
5318 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 5349 | if (!dont_wait_for_ack) { |
5319 | if (!msg) | 5350 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
5320 | return -ENOMEM; | 5351 | if (!msg) |
5352 | return -ENOMEM; | ||
5321 | 5353 | ||
5322 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, | 5354 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, |
5323 | NL80211_CMD_FRAME); | 5355 | NL80211_CMD_FRAME); |
5324 | 5356 | ||
5325 | if (IS_ERR(hdr)) { | 5357 | if (IS_ERR(hdr)) { |
5326 | err = PTR_ERR(hdr); | 5358 | err = PTR_ERR(hdr); |
5327 | goto free_msg; | 5359 | goto free_msg; |
5360 | } | ||
5328 | } | 5361 | } |
5362 | |||
5329 | err = cfg80211_mlme_mgmt_tx(rdev, dev, chan, offchan, channel_type, | 5363 | err = cfg80211_mlme_mgmt_tx(rdev, dev, chan, offchan, channel_type, |
5330 | channel_type_valid, wait, | 5364 | channel_type_valid, wait, |
5331 | nla_data(info->attrs[NL80211_ATTR_FRAME]), | 5365 | nla_data(info->attrs[NL80211_ATTR_FRAME]), |
5332 | nla_len(info->attrs[NL80211_ATTR_FRAME]), | 5366 | nla_len(info->attrs[NL80211_ATTR_FRAME]), |
5333 | no_cck, &cookie); | 5367 | no_cck, dont_wait_for_ack, &cookie); |
5334 | if (err) | 5368 | if (err) |
5335 | goto free_msg; | 5369 | goto free_msg; |
5336 | 5370 | ||
5337 | NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie); | 5371 | if (msg) { |
5372 | NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie); | ||
5338 | 5373 | ||
5339 | genlmsg_end(msg, hdr); | 5374 | genlmsg_end(msg, hdr); |
5340 | return genlmsg_reply(msg, info); | 5375 | return genlmsg_reply(msg, info); |
5376 | } | ||
5377 | |||
5378 | return 0; | ||
5341 | 5379 | ||
5342 | nla_put_failure: | 5380 | nla_put_failure: |
5343 | err = -ENOBUFS; | 5381 | err = -ENOBUFS; |
@@ -5827,6 +5865,91 @@ static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info) | |||
5827 | return err; | 5865 | return err; |
5828 | } | 5866 | } |
5829 | 5867 | ||
5868 | static int nl80211_register_unexpected_frame(struct sk_buff *skb, | ||
5869 | struct genl_info *info) | ||
5870 | { | ||
5871 | struct net_device *dev = info->user_ptr[1]; | ||
5872 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
5873 | |||
5874 | if (wdev->iftype != NL80211_IFTYPE_AP && | ||
5875 | wdev->iftype != NL80211_IFTYPE_P2P_GO) | ||
5876 | return -EINVAL; | ||
5877 | |||
5878 | if (wdev->ap_unexpected_nlpid) | ||
5879 | return -EBUSY; | ||
5880 | |||
5881 | wdev->ap_unexpected_nlpid = info->snd_pid; | ||
5882 | return 0; | ||
5883 | } | ||
5884 | |||
5885 | static int nl80211_probe_client(struct sk_buff *skb, | ||
5886 | struct genl_info *info) | ||
5887 | { | ||
5888 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
5889 | struct net_device *dev = info->user_ptr[1]; | ||
5890 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
5891 | struct sk_buff *msg; | ||
5892 | void *hdr; | ||
5893 | const u8 *addr; | ||
5894 | u64 cookie; | ||
5895 | int err; | ||
5896 | |||
5897 | if (wdev->iftype != NL80211_IFTYPE_AP && | ||
5898 | wdev->iftype != NL80211_IFTYPE_P2P_GO) | ||
5899 | return -EOPNOTSUPP; | ||
5900 | |||
5901 | if (!info->attrs[NL80211_ATTR_MAC]) | ||
5902 | return -EINVAL; | ||
5903 | |||
5904 | if (!rdev->ops->probe_client) | ||
5905 | return -EOPNOTSUPP; | ||
5906 | |||
5907 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
5908 | if (!msg) | ||
5909 | return -ENOMEM; | ||
5910 | |||
5911 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, | ||
5912 | NL80211_CMD_PROBE_CLIENT); | ||
5913 | |||
5914 | if (IS_ERR(hdr)) { | ||
5915 | err = PTR_ERR(hdr); | ||
5916 | goto free_msg; | ||
5917 | } | ||
5918 | |||
5919 | addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | ||
5920 | |||
5921 | err = rdev->ops->probe_client(&rdev->wiphy, dev, addr, &cookie); | ||
5922 | if (err) | ||
5923 | goto free_msg; | ||
5924 | |||
5925 | NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie); | ||
5926 | |||
5927 | genlmsg_end(msg, hdr); | ||
5928 | |||
5929 | return genlmsg_reply(msg, info); | ||
5930 | |||
5931 | nla_put_failure: | ||
5932 | err = -ENOBUFS; | ||
5933 | free_msg: | ||
5934 | nlmsg_free(msg); | ||
5935 | return err; | ||
5936 | } | ||
5937 | |||
5938 | static int nl80211_register_beacons(struct sk_buff *skb, struct genl_info *info) | ||
5939 | { | ||
5940 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
5941 | |||
5942 | if (!(rdev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS)) | ||
5943 | return -EOPNOTSUPP; | ||
5944 | |||
5945 | if (rdev->ap_beacons_nlpid) | ||
5946 | return -EBUSY; | ||
5947 | |||
5948 | rdev->ap_beacons_nlpid = info->snd_pid; | ||
5949 | |||
5950 | return 0; | ||
5951 | } | ||
5952 | |||
5830 | #define NL80211_FLAG_NEED_WIPHY 0x01 | 5953 | #define NL80211_FLAG_NEED_WIPHY 0x01 |
5831 | #define NL80211_FLAG_NEED_NETDEV 0x02 | 5954 | #define NL80211_FLAG_NEED_NETDEV 0x02 |
5832 | #define NL80211_FLAG_NEED_RTNL 0x04 | 5955 | #define NL80211_FLAG_NEED_RTNL 0x04 |
@@ -6382,6 +6505,30 @@ static struct genl_ops nl80211_ops[] = { | |||
6382 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | 6505 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | |
6383 | NL80211_FLAG_NEED_RTNL, | 6506 | NL80211_FLAG_NEED_RTNL, |
6384 | }, | 6507 | }, |
6508 | { | ||
6509 | .cmd = NL80211_CMD_UNEXPECTED_FRAME, | ||
6510 | .doit = nl80211_register_unexpected_frame, | ||
6511 | .policy = nl80211_policy, | ||
6512 | .flags = GENL_ADMIN_PERM, | ||
6513 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
6514 | NL80211_FLAG_NEED_RTNL, | ||
6515 | }, | ||
6516 | { | ||
6517 | .cmd = NL80211_CMD_PROBE_CLIENT, | ||
6518 | .doit = nl80211_probe_client, | ||
6519 | .policy = nl80211_policy, | ||
6520 | .flags = GENL_ADMIN_PERM, | ||
6521 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
6522 | NL80211_FLAG_NEED_RTNL, | ||
6523 | }, | ||
6524 | { | ||
6525 | .cmd = NL80211_CMD_REGISTER_BEACONS, | ||
6526 | .doit = nl80211_register_beacons, | ||
6527 | .policy = nl80211_policy, | ||
6528 | .flags = GENL_ADMIN_PERM, | ||
6529 | .internal_flags = NL80211_FLAG_NEED_WIPHY | | ||
6530 | NL80211_FLAG_NEED_RTNL, | ||
6531 | }, | ||
6385 | }; | 6532 | }; |
6386 | 6533 | ||
6387 | static struct genl_multicast_group nl80211_mlme_mcgrp = { | 6534 | static struct genl_multicast_group nl80211_mlme_mcgrp = { |
@@ -6634,10 +6781,7 @@ void nl80211_send_reg_change_event(struct regulatory_request *request) | |||
6634 | if (wiphy_idx_valid(request->wiphy_idx)) | 6781 | if (wiphy_idx_valid(request->wiphy_idx)) |
6635 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, request->wiphy_idx); | 6782 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, request->wiphy_idx); |
6636 | 6783 | ||
6637 | if (genlmsg_end(msg, hdr) < 0) { | 6784 | genlmsg_end(msg, hdr); |
6638 | nlmsg_free(msg); | ||
6639 | return; | ||
6640 | } | ||
6641 | 6785 | ||
6642 | rcu_read_lock(); | 6786 | rcu_read_lock(); |
6643 | genlmsg_multicast_allns(msg, 0, nl80211_regulatory_mcgrp.id, | 6787 | genlmsg_multicast_allns(msg, 0, nl80211_regulatory_mcgrp.id, |
@@ -6673,10 +6817,7 @@ static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev, | |||
6673 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); | 6817 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); |
6674 | NLA_PUT(msg, NL80211_ATTR_FRAME, len, buf); | 6818 | NLA_PUT(msg, NL80211_ATTR_FRAME, len, buf); |
6675 | 6819 | ||
6676 | if (genlmsg_end(msg, hdr) < 0) { | 6820 | genlmsg_end(msg, hdr); |
6677 | nlmsg_free(msg); | ||
6678 | return; | ||
6679 | } | ||
6680 | 6821 | ||
6681 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | 6822 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, |
6682 | nl80211_mlme_mcgrp.id, gfp); | 6823 | nl80211_mlme_mcgrp.id, gfp); |
@@ -6757,10 +6898,7 @@ static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev, | |||
6757 | NLA_PUT_FLAG(msg, NL80211_ATTR_TIMED_OUT); | 6898 | NLA_PUT_FLAG(msg, NL80211_ATTR_TIMED_OUT); |
6758 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); | 6899 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); |
6759 | 6900 | ||
6760 | if (genlmsg_end(msg, hdr) < 0) { | 6901 | genlmsg_end(msg, hdr); |
6761 | nlmsg_free(msg); | ||
6762 | return; | ||
6763 | } | ||
6764 | 6902 | ||
6765 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | 6903 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, |
6766 | nl80211_mlme_mcgrp.id, gfp); | 6904 | nl80211_mlme_mcgrp.id, gfp); |
@@ -6816,10 +6954,7 @@ void nl80211_send_connect_result(struct cfg80211_registered_device *rdev, | |||
6816 | if (resp_ie) | 6954 | if (resp_ie) |
6817 | NLA_PUT(msg, NL80211_ATTR_RESP_IE, resp_ie_len, resp_ie); | 6955 | NLA_PUT(msg, NL80211_ATTR_RESP_IE, resp_ie_len, resp_ie); |
6818 | 6956 | ||
6819 | if (genlmsg_end(msg, hdr) < 0) { | 6957 | genlmsg_end(msg, hdr); |
6820 | nlmsg_free(msg); | ||
6821 | return; | ||
6822 | } | ||
6823 | 6958 | ||
6824 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | 6959 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, |
6825 | nl80211_mlme_mcgrp.id, gfp); | 6960 | nl80211_mlme_mcgrp.id, gfp); |
@@ -6857,10 +6992,7 @@ void nl80211_send_roamed(struct cfg80211_registered_device *rdev, | |||
6857 | if (resp_ie) | 6992 | if (resp_ie) |
6858 | NLA_PUT(msg, NL80211_ATTR_RESP_IE, resp_ie_len, resp_ie); | 6993 | NLA_PUT(msg, NL80211_ATTR_RESP_IE, resp_ie_len, resp_ie); |
6859 | 6994 | ||
6860 | if (genlmsg_end(msg, hdr) < 0) { | 6995 | genlmsg_end(msg, hdr); |
6861 | nlmsg_free(msg); | ||
6862 | return; | ||
6863 | } | ||
6864 | 6996 | ||
6865 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | 6997 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, |
6866 | nl80211_mlme_mcgrp.id, gfp); | 6998 | nl80211_mlme_mcgrp.id, gfp); |
@@ -6898,10 +7030,7 @@ void nl80211_send_disconnected(struct cfg80211_registered_device *rdev, | |||
6898 | if (ie) | 7030 | if (ie) |
6899 | NLA_PUT(msg, NL80211_ATTR_IE, ie_len, ie); | 7031 | NLA_PUT(msg, NL80211_ATTR_IE, ie_len, ie); |
6900 | 7032 | ||
6901 | if (genlmsg_end(msg, hdr) < 0) { | 7033 | genlmsg_end(msg, hdr); |
6902 | nlmsg_free(msg); | ||
6903 | return; | ||
6904 | } | ||
6905 | 7034 | ||
6906 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | 7035 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, |
6907 | nl80211_mlme_mcgrp.id, GFP_KERNEL); | 7036 | nl80211_mlme_mcgrp.id, GFP_KERNEL); |
@@ -6934,10 +7063,7 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev, | |||
6934 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); | 7063 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); |
6935 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid); | 7064 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid); |
6936 | 7065 | ||
6937 | if (genlmsg_end(msg, hdr) < 0) { | 7066 | genlmsg_end(msg, hdr); |
6938 | nlmsg_free(msg); | ||
6939 | return; | ||
6940 | } | ||
6941 | 7067 | ||
6942 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | 7068 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, |
6943 | nl80211_mlme_mcgrp.id, gfp); | 7069 | nl80211_mlme_mcgrp.id, gfp); |
@@ -6972,10 +7098,7 @@ void nl80211_send_new_peer_candidate(struct cfg80211_registered_device *rdev, | |||
6972 | if (ie_len && ie) | 7098 | if (ie_len && ie) |
6973 | NLA_PUT(msg, NL80211_ATTR_IE, ie_len , ie); | 7099 | NLA_PUT(msg, NL80211_ATTR_IE, ie_len , ie); |
6974 | 7100 | ||
6975 | if (genlmsg_end(msg, hdr) < 0) { | 7101 | genlmsg_end(msg, hdr); |
6976 | nlmsg_free(msg); | ||
6977 | return; | ||
6978 | } | ||
6979 | 7102 | ||
6980 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | 7103 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, |
6981 | nl80211_mlme_mcgrp.id, gfp); | 7104 | nl80211_mlme_mcgrp.id, gfp); |
@@ -7014,10 +7137,7 @@ void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, | |||
7014 | if (tsc) | 7137 | if (tsc) |
7015 | NLA_PUT(msg, NL80211_ATTR_KEY_SEQ, 6, tsc); | 7138 | NLA_PUT(msg, NL80211_ATTR_KEY_SEQ, 6, tsc); |
7016 | 7139 | ||
7017 | if (genlmsg_end(msg, hdr) < 0) { | 7140 | genlmsg_end(msg, hdr); |
7018 | nlmsg_free(msg); | ||
7019 | return; | ||
7020 | } | ||
7021 | 7141 | ||
7022 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | 7142 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, |
7023 | nl80211_mlme_mcgrp.id, gfp); | 7143 | nl80211_mlme_mcgrp.id, gfp); |
@@ -7068,10 +7188,7 @@ void nl80211_send_beacon_hint_event(struct wiphy *wiphy, | |||
7068 | goto nla_put_failure; | 7188 | goto nla_put_failure; |
7069 | nla_nest_end(msg, nl_freq); | 7189 | nla_nest_end(msg, nl_freq); |
7070 | 7190 | ||
7071 | if (genlmsg_end(msg, hdr) < 0) { | 7191 | genlmsg_end(msg, hdr); |
7072 | nlmsg_free(msg); | ||
7073 | return; | ||
7074 | } | ||
7075 | 7192 | ||
7076 | rcu_read_lock(); | 7193 | rcu_read_lock(); |
7077 | genlmsg_multicast_allns(msg, 0, nl80211_regulatory_mcgrp.id, | 7194 | genlmsg_multicast_allns(msg, 0, nl80211_regulatory_mcgrp.id, |
@@ -7114,10 +7231,7 @@ static void nl80211_send_remain_on_chan_event( | |||
7114 | if (cmd == NL80211_CMD_REMAIN_ON_CHANNEL) | 7231 | if (cmd == NL80211_CMD_REMAIN_ON_CHANNEL) |
7115 | NLA_PUT_U32(msg, NL80211_ATTR_DURATION, duration); | 7232 | NLA_PUT_U32(msg, NL80211_ATTR_DURATION, duration); |
7116 | 7233 | ||
7117 | if (genlmsg_end(msg, hdr) < 0) { | 7234 | genlmsg_end(msg, hdr); |
7118 | nlmsg_free(msg); | ||
7119 | return; | ||
7120 | } | ||
7121 | 7235 | ||
7122 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | 7236 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, |
7123 | nl80211_mlme_mcgrp.id, gfp); | 7237 | nl80211_mlme_mcgrp.id, gfp); |
@@ -7188,10 +7302,7 @@ void nl80211_send_sta_del_event(struct cfg80211_registered_device *rdev, | |||
7188 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); | 7302 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); |
7189 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); | 7303 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); |
7190 | 7304 | ||
7191 | if (genlmsg_end(msg, hdr) < 0) { | 7305 | genlmsg_end(msg, hdr); |
7192 | nlmsg_free(msg); | ||
7193 | return; | ||
7194 | } | ||
7195 | 7306 | ||
7196 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | 7307 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, |
7197 | nl80211_mlme_mcgrp.id, gfp); | 7308 | nl80211_mlme_mcgrp.id, gfp); |
@@ -7202,13 +7313,68 @@ void nl80211_send_sta_del_event(struct cfg80211_registered_device *rdev, | |||
7202 | nlmsg_free(msg); | 7313 | nlmsg_free(msg); |
7203 | } | 7314 | } |
7204 | 7315 | ||
7316 | static bool __nl80211_unexpected_frame(struct net_device *dev, u8 cmd, | ||
7317 | const u8 *addr, gfp_t gfp) | ||
7318 | { | ||
7319 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
7320 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | ||
7321 | struct sk_buff *msg; | ||
7322 | void *hdr; | ||
7323 | int err; | ||
7324 | u32 nlpid = ACCESS_ONCE(wdev->ap_unexpected_nlpid); | ||
7325 | |||
7326 | if (!nlpid) | ||
7327 | return false; | ||
7328 | |||
7329 | msg = nlmsg_new(100, gfp); | ||
7330 | if (!msg) | ||
7331 | return true; | ||
7332 | |||
7333 | hdr = nl80211hdr_put(msg, 0, 0, 0, cmd); | ||
7334 | if (!hdr) { | ||
7335 | nlmsg_free(msg); | ||
7336 | return true; | ||
7337 | } | ||
7338 | |||
7339 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); | ||
7340 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); | ||
7341 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); | ||
7342 | |||
7343 | err = genlmsg_end(msg, hdr); | ||
7344 | if (err < 0) { | ||
7345 | nlmsg_free(msg); | ||
7346 | return true; | ||
7347 | } | ||
7348 | |||
7349 | genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlpid); | ||
7350 | return true; | ||
7351 | |||
7352 | nla_put_failure: | ||
7353 | genlmsg_cancel(msg, hdr); | ||
7354 | nlmsg_free(msg); | ||
7355 | return true; | ||
7356 | } | ||
7357 | |||
7358 | bool nl80211_unexpected_frame(struct net_device *dev, const u8 *addr, gfp_t gfp) | ||
7359 | { | ||
7360 | return __nl80211_unexpected_frame(dev, NL80211_CMD_UNEXPECTED_FRAME, | ||
7361 | addr, gfp); | ||
7362 | } | ||
7363 | |||
7364 | bool nl80211_unexpected_4addr_frame(struct net_device *dev, | ||
7365 | const u8 *addr, gfp_t gfp) | ||
7366 | { | ||
7367 | return __nl80211_unexpected_frame(dev, | ||
7368 | NL80211_CMD_UNEXPECTED_4ADDR_FRAME, | ||
7369 | addr, gfp); | ||
7370 | } | ||
7371 | |||
7205 | int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, | 7372 | int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, |
7206 | struct net_device *netdev, u32 nlpid, | 7373 | struct net_device *netdev, u32 nlpid, |
7207 | int freq, const u8 *buf, size_t len, gfp_t gfp) | 7374 | int freq, const u8 *buf, size_t len, gfp_t gfp) |
7208 | { | 7375 | { |
7209 | struct sk_buff *msg; | 7376 | struct sk_buff *msg; |
7210 | void *hdr; | 7377 | void *hdr; |
7211 | int err; | ||
7212 | 7378 | ||
7213 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); | 7379 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); |
7214 | if (!msg) | 7380 | if (!msg) |
@@ -7225,16 +7391,9 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, | |||
7225 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq); | 7391 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq); |
7226 | NLA_PUT(msg, NL80211_ATTR_FRAME, len, buf); | 7392 | NLA_PUT(msg, NL80211_ATTR_FRAME, len, buf); |
7227 | 7393 | ||
7228 | err = genlmsg_end(msg, hdr); | 7394 | genlmsg_end(msg, hdr); |
7229 | if (err < 0) { | ||
7230 | nlmsg_free(msg); | ||
7231 | return err; | ||
7232 | } | ||
7233 | 7395 | ||
7234 | err = genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlpid); | 7396 | return genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlpid); |
7235 | if (err < 0) | ||
7236 | return err; | ||
7237 | return 0; | ||
7238 | 7397 | ||
7239 | nla_put_failure: | 7398 | nla_put_failure: |
7240 | genlmsg_cancel(msg, hdr); | 7399 | genlmsg_cancel(msg, hdr); |
@@ -7267,10 +7426,7 @@ void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev, | |||
7267 | if (ack) | 7426 | if (ack) |
7268 | NLA_PUT_FLAG(msg, NL80211_ATTR_ACK); | 7427 | NLA_PUT_FLAG(msg, NL80211_ATTR_ACK); |
7269 | 7428 | ||
7270 | if (genlmsg_end(msg, hdr) < 0) { | 7429 | genlmsg_end(msg, hdr); |
7271 | nlmsg_free(msg); | ||
7272 | return; | ||
7273 | } | ||
7274 | 7430 | ||
7275 | genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp); | 7431 | genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp); |
7276 | return; | 7432 | return; |
@@ -7312,10 +7468,7 @@ nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev, | |||
7312 | 7468 | ||
7313 | nla_nest_end(msg, pinfoattr); | 7469 | nla_nest_end(msg, pinfoattr); |
7314 | 7470 | ||
7315 | if (genlmsg_end(msg, hdr) < 0) { | 7471 | genlmsg_end(msg, hdr); |
7316 | nlmsg_free(msg); | ||
7317 | return; | ||
7318 | } | ||
7319 | 7472 | ||
7320 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | 7473 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, |
7321 | nl80211_mlme_mcgrp.id, gfp); | 7474 | nl80211_mlme_mcgrp.id, gfp); |
@@ -7357,10 +7510,7 @@ void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev, | |||
7357 | 7510 | ||
7358 | nla_nest_end(msg, rekey_attr); | 7511 | nla_nest_end(msg, rekey_attr); |
7359 | 7512 | ||
7360 | if (genlmsg_end(msg, hdr) < 0) { | 7513 | genlmsg_end(msg, hdr); |
7361 | nlmsg_free(msg); | ||
7362 | return; | ||
7363 | } | ||
7364 | 7514 | ||
7365 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | 7515 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, |
7366 | nl80211_mlme_mcgrp.id, gfp); | 7516 | nl80211_mlme_mcgrp.id, gfp); |
@@ -7403,10 +7553,7 @@ void nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev, | |||
7403 | 7553 | ||
7404 | nla_nest_end(msg, attr); | 7554 | nla_nest_end(msg, attr); |
7405 | 7555 | ||
7406 | if (genlmsg_end(msg, hdr) < 0) { | 7556 | genlmsg_end(msg, hdr); |
7407 | nlmsg_free(msg); | ||
7408 | return; | ||
7409 | } | ||
7410 | 7557 | ||
7411 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | 7558 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, |
7412 | nl80211_mlme_mcgrp.id, gfp); | 7559 | nl80211_mlme_mcgrp.id, gfp); |
@@ -7448,7 +7595,45 @@ nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev, | |||
7448 | 7595 | ||
7449 | nla_nest_end(msg, pinfoattr); | 7596 | nla_nest_end(msg, pinfoattr); |
7450 | 7597 | ||
7451 | if (genlmsg_end(msg, hdr) < 0) { | 7598 | genlmsg_end(msg, hdr); |
7599 | |||
7600 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | ||
7601 | nl80211_mlme_mcgrp.id, gfp); | ||
7602 | return; | ||
7603 | |||
7604 | nla_put_failure: | ||
7605 | genlmsg_cancel(msg, hdr); | ||
7606 | nlmsg_free(msg); | ||
7607 | } | ||
7608 | |||
7609 | void cfg80211_probe_status(struct net_device *dev, const u8 *addr, | ||
7610 | u64 cookie, bool acked, gfp_t gfp) | ||
7611 | { | ||
7612 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
7613 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | ||
7614 | struct sk_buff *msg; | ||
7615 | void *hdr; | ||
7616 | int err; | ||
7617 | |||
7618 | msg = nlmsg_new(NLMSG_GOODSIZE, gfp); | ||
7619 | if (!msg) | ||
7620 | return; | ||
7621 | |||
7622 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_PROBE_CLIENT); | ||
7623 | if (!hdr) { | ||
7624 | nlmsg_free(msg); | ||
7625 | return; | ||
7626 | } | ||
7627 | |||
7628 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); | ||
7629 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); | ||
7630 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); | ||
7631 | NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie); | ||
7632 | if (acked) | ||
7633 | NLA_PUT_FLAG(msg, NL80211_ATTR_ACK); | ||
7634 | |||
7635 | err = genlmsg_end(msg, hdr); | ||
7636 | if (err < 0) { | ||
7452 | nlmsg_free(msg); | 7637 | nlmsg_free(msg); |
7453 | return; | 7638 | return; |
7454 | } | 7639 | } |
@@ -7461,6 +7646,45 @@ nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev, | |||
7461 | genlmsg_cancel(msg, hdr); | 7646 | genlmsg_cancel(msg, hdr); |
7462 | nlmsg_free(msg); | 7647 | nlmsg_free(msg); |
7463 | } | 7648 | } |
7649 | EXPORT_SYMBOL(cfg80211_probe_status); | ||
7650 | |||
7651 | void cfg80211_report_obss_beacon(struct wiphy *wiphy, | ||
7652 | const u8 *frame, size_t len, | ||
7653 | int freq, gfp_t gfp) | ||
7654 | { | ||
7655 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
7656 | struct sk_buff *msg; | ||
7657 | void *hdr; | ||
7658 | u32 nlpid = ACCESS_ONCE(rdev->ap_beacons_nlpid); | ||
7659 | |||
7660 | if (!nlpid) | ||
7661 | return; | ||
7662 | |||
7663 | msg = nlmsg_new(len + 100, gfp); | ||
7664 | if (!msg) | ||
7665 | return; | ||
7666 | |||
7667 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME); | ||
7668 | if (!hdr) { | ||
7669 | nlmsg_free(msg); | ||
7670 | return; | ||
7671 | } | ||
7672 | |||
7673 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); | ||
7674 | if (freq) | ||
7675 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq); | ||
7676 | NLA_PUT(msg, NL80211_ATTR_FRAME, len, frame); | ||
7677 | |||
7678 | genlmsg_end(msg, hdr); | ||
7679 | |||
7680 | genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlpid); | ||
7681 | return; | ||
7682 | |||
7683 | nla_put_failure: | ||
7684 | genlmsg_cancel(msg, hdr); | ||
7685 | nlmsg_free(msg); | ||
7686 | } | ||
7687 | EXPORT_SYMBOL(cfg80211_report_obss_beacon); | ||
7464 | 7688 | ||
7465 | static int nl80211_netlink_notify(struct notifier_block * nb, | 7689 | static int nl80211_netlink_notify(struct notifier_block * nb, |
7466 | unsigned long state, | 7690 | unsigned long state, |
@@ -7475,9 +7699,12 @@ static int nl80211_netlink_notify(struct notifier_block * nb, | |||
7475 | 7699 | ||
7476 | rcu_read_lock(); | 7700 | rcu_read_lock(); |
7477 | 7701 | ||
7478 | list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) | 7702 | list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) { |
7479 | list_for_each_entry_rcu(wdev, &rdev->netdev_list, list) | 7703 | list_for_each_entry_rcu(wdev, &rdev->netdev_list, list) |
7480 | cfg80211_mlme_unregister_socket(wdev, notify->pid); | 7704 | cfg80211_mlme_unregister_socket(wdev, notify->pid); |
7705 | if (rdev->ap_beacons_nlpid == notify->pid) | ||
7706 | rdev->ap_beacons_nlpid = 0; | ||
7707 | } | ||
7481 | 7708 | ||
7482 | rcu_read_unlock(); | 7709 | rcu_read_unlock(); |
7483 | 7710 | ||