diff options
-rw-r--r-- | include/linux/nl80211.h | 36 | ||||
-rw-r--r-- | include/net/cfg80211.h | 46 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 9 | ||||
-rw-r--r-- | net/wireless/Makefile | 2 | ||||
-rw-r--r-- | net/wireless/mlme.c | 46 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 72 | ||||
-rw-r--r-- | net/wireless/nl80211.h | 12 |
7 files changed, 219 insertions, 4 deletions
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 3700d927e245..5ce68ae8314e 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h | |||
@@ -161,6 +161,25 @@ | |||
161 | * %NL80211_REG_TYPE_COUNTRY the alpha2 to which we have moved on | 161 | * %NL80211_REG_TYPE_COUNTRY the alpha2 to which we have moved on |
162 | * to (%NL80211_ATTR_REG_ALPHA2). | 162 | * to (%NL80211_ATTR_REG_ALPHA2). |
163 | * | 163 | * |
164 | * @NL80211_CMD_AUTHENTICATE: authentication notification (on the "mlme" | ||
165 | * multicast group). This event reports reception of an Authentication | ||
166 | * frame in station and IBSS modes when the local MLME processed the | ||
167 | * frame, i.e., it was for the local STA and was received in correct | ||
168 | * state. This is similar to MLME-AUTHENTICATE.confirm primitive in the | ||
169 | * MLME SAP interface (kernel providing MLME, userspace SME). The | ||
170 | * included NL80211_ATTR_FRAME attribute contains the management frame | ||
171 | * (including both the header and frame body, but not FCS). | ||
172 | * @NL80211_CMD_ASSOCIATE: association notification; like | ||
173 | * NL80211_CMD_AUTHENTICATE but for Association Response and Reassociation | ||
174 | * Response frames (similar to MLME-ASSOCIATE.confirm or | ||
175 | * MLME-REASSOCIATE.confirm primitives). | ||
176 | * @NL80211_CMD_DEAUTHENTICATE: deauthentication notification; like | ||
177 | * NL80211_CMD_AUTHENTICATE but for Deauthentication frames (similar to | ||
178 | * MLME-DEAUTHENTICATE.indication primitive). | ||
179 | * @NL80211_CMD_DISASSOCIATE: disassociation notification; like | ||
180 | * NL80211_CMD_AUTHENTICATE but for Disassociation frames (similar to | ||
181 | * MLME-DISASSOCIATE.indication primitive). | ||
182 | * | ||
164 | * @NL80211_CMD_MAX: highest used command number | 183 | * @NL80211_CMD_MAX: highest used command number |
165 | * @__NL80211_CMD_AFTER_LAST: internal use | 184 | * @__NL80211_CMD_AFTER_LAST: internal use |
166 | */ | 185 | */ |
@@ -217,6 +236,11 @@ enum nl80211_commands { | |||
217 | 236 | ||
218 | NL80211_CMD_REG_CHANGE, | 237 | NL80211_CMD_REG_CHANGE, |
219 | 238 | ||
239 | NL80211_CMD_AUTHENTICATE, | ||
240 | NL80211_CMD_ASSOCIATE, | ||
241 | NL80211_CMD_DEAUTHENTICATE, | ||
242 | NL80211_CMD_DISASSOCIATE, | ||
243 | |||
220 | /* add new commands above here */ | 244 | /* add new commands above here */ |
221 | 245 | ||
222 | /* used to define NL80211_CMD_MAX below */ | 246 | /* used to define NL80211_CMD_MAX below */ |
@@ -230,8 +254,11 @@ enum nl80211_commands { | |||
230 | */ | 254 | */ |
231 | #define NL80211_CMD_SET_BSS NL80211_CMD_SET_BSS | 255 | #define NL80211_CMD_SET_BSS NL80211_CMD_SET_BSS |
232 | #define NL80211_CMD_SET_MGMT_EXTRA_IE NL80211_CMD_SET_MGMT_EXTRA_IE | 256 | #define NL80211_CMD_SET_MGMT_EXTRA_IE NL80211_CMD_SET_MGMT_EXTRA_IE |
233 | |||
234 | #define NL80211_CMD_REG_CHANGE NL80211_CMD_REG_CHANGE | 257 | #define NL80211_CMD_REG_CHANGE NL80211_CMD_REG_CHANGE |
258 | #define NL80211_CMD_AUTHENTICATE NL80211_CMD_AUTHENTICATE | ||
259 | #define NL80211_CMD_ASSOCIATE NL80211_CMD_ASSOCIATE | ||
260 | #define NL80211_CMD_DEAUTHENTICATE NL80211_CMD_DEAUTHENTICATE | ||
261 | #define NL80211_CMD_DISASSOCIATE NL80211_CMD_DISASSOCIATE | ||
235 | 262 | ||
236 | /** | 263 | /** |
237 | * enum nl80211_attrs - nl80211 netlink attributes | 264 | * enum nl80211_attrs - nl80211 netlink attributes |
@@ -353,6 +380,10 @@ enum nl80211_commands { | |||
353 | * an array of command numbers (i.e. a mapping index to command number) | 380 | * an array of command numbers (i.e. a mapping index to command number) |
354 | * that the driver for the given wiphy supports. | 381 | * that the driver for the given wiphy supports. |
355 | * | 382 | * |
383 | * @NL80211_ATTR_FRAME: frame data (binary attribute), including frame header | ||
384 | * and body, but not FCS; used, e.g., with NL80211_CMD_AUTHENTICATE and | ||
385 | * NL80211_CMD_ASSOCIATE events | ||
386 | * | ||
356 | * @NL80211_ATTR_MAX: highest attribute number currently defined | 387 | * @NL80211_ATTR_MAX: highest attribute number currently defined |
357 | * @__NL80211_ATTR_AFTER_LAST: internal use | 388 | * @__NL80211_ATTR_AFTER_LAST: internal use |
358 | */ | 389 | */ |
@@ -432,6 +463,8 @@ enum nl80211_attrs { | |||
432 | 463 | ||
433 | NL80211_ATTR_SUPPORTED_COMMANDS, | 464 | NL80211_ATTR_SUPPORTED_COMMANDS, |
434 | 465 | ||
466 | NL80211_ATTR_FRAME, | ||
467 | |||
435 | /* add attributes here, update the policy in nl80211.c */ | 468 | /* add attributes here, update the policy in nl80211.c */ |
436 | 469 | ||
437 | __NL80211_ATTR_AFTER_LAST, | 470 | __NL80211_ATTR_AFTER_LAST, |
@@ -451,6 +484,7 @@ enum nl80211_attrs { | |||
451 | #define NL80211_ATTR_IE NL80211_ATTR_IE | 484 | #define NL80211_ATTR_IE NL80211_ATTR_IE |
452 | #define NL80211_ATTR_REG_INITIATOR NL80211_ATTR_REG_INITIATOR | 485 | #define NL80211_ATTR_REG_INITIATOR NL80211_ATTR_REG_INITIATOR |
453 | #define NL80211_ATTR_REG_TYPE NL80211_ATTR_REG_TYPE | 486 | #define NL80211_ATTR_REG_TYPE NL80211_ATTR_REG_TYPE |
487 | #define NL80211_ATTR_FRAME NL80211_ATTR_FRAME | ||
454 | 488 | ||
455 | #define NL80211_MAX_SUPP_RATES 32 | 489 | #define NL80211_MAX_SUPP_RATES 32 |
456 | #define NL80211_MAX_SUPP_REG_RULES 32 | 490 | #define NL80211_MAX_SUPP_REG_RULES 32 |
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 50f3fd9ff524..ad44016021b1 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h | |||
@@ -807,4 +807,50 @@ void cfg80211_put_bss(struct cfg80211_bss *bss); | |||
807 | */ | 807 | */ |
808 | void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *bss); | 808 | void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *bss); |
809 | 809 | ||
810 | /** | ||
811 | * cfg80211_send_rx_auth - notification of processed authentication | ||
812 | * @dev: network device | ||
813 | * @buf: authentication frame (header + body) | ||
814 | * @len: length of the frame data | ||
815 | * | ||
816 | * This function is called whenever an authentication has been processed in | ||
817 | * station mode. | ||
818 | */ | ||
819 | void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len); | ||
820 | |||
821 | /** | ||
822 | * cfg80211_send_rx_assoc - notification of processed association | ||
823 | * @dev: network device | ||
824 | * @buf: (re)association response frame (header + body) | ||
825 | * @len: length of the frame data | ||
826 | * | ||
827 | * This function is called whenever a (re)association response has been | ||
828 | * processed in station mode. | ||
829 | */ | ||
830 | void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len); | ||
831 | |||
832 | /** | ||
833 | * cfg80211_send_rx_deauth - notification of processed deauthentication | ||
834 | * @dev: network device | ||
835 | * @buf: deauthentication frame (header + body) | ||
836 | * @len: length of the frame data | ||
837 | * | ||
838 | * This function is called whenever deauthentication has been processed in | ||
839 | * station mode. | ||
840 | */ | ||
841 | void cfg80211_send_rx_deauth(struct net_device *dev, const u8 *buf, | ||
842 | size_t len); | ||
843 | |||
844 | /** | ||
845 | * cfg80211_send_rx_disassoc - notification of processed disassociation | ||
846 | * @dev: network device | ||
847 | * @buf: disassociation response frame (header + body) | ||
848 | * @len: length of the frame data | ||
849 | * | ||
850 | * This function is called whenever disassociation has been processed in | ||
851 | * station mode. | ||
852 | */ | ||
853 | void cfg80211_send_rx_disassoc(struct net_device *dev, const u8 *buf, | ||
854 | size_t len); | ||
855 | |||
810 | #endif /* __NET_CFG80211_H */ | 856 | #endif /* __NET_CFG80211_H */ |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 1f49b63d8dd2..6dc7a61bc18b 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -1085,11 +1085,13 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, | |||
1085 | case WLAN_AUTH_OPEN: | 1085 | case WLAN_AUTH_OPEN: |
1086 | case WLAN_AUTH_LEAP: | 1086 | case WLAN_AUTH_LEAP: |
1087 | ieee80211_auth_completed(sdata); | 1087 | ieee80211_auth_completed(sdata); |
1088 | cfg80211_send_rx_auth(sdata->dev, (u8 *) mgmt, len); | ||
1088 | break; | 1089 | break; |
1089 | case WLAN_AUTH_SHARED_KEY: | 1090 | case WLAN_AUTH_SHARED_KEY: |
1090 | if (ifmgd->auth_transaction == 4) | 1091 | if (ifmgd->auth_transaction == 4) { |
1091 | ieee80211_auth_completed(sdata); | 1092 | ieee80211_auth_completed(sdata); |
1092 | else | 1093 | cfg80211_send_rx_auth(sdata->dev, (u8 *) mgmt, len); |
1094 | } else | ||
1093 | ieee80211_auth_challenge(sdata, mgmt, len); | 1095 | ieee80211_auth_challenge(sdata, mgmt, len); |
1094 | break; | 1096 | break; |
1095 | } | 1097 | } |
@@ -1125,6 +1127,7 @@ static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, | |||
1125 | 1127 | ||
1126 | ieee80211_set_disassoc(sdata, true, false, 0); | 1128 | ieee80211_set_disassoc(sdata, true, false, 0); |
1127 | ifmgd->flags &= ~IEEE80211_STA_AUTHENTICATED; | 1129 | ifmgd->flags &= ~IEEE80211_STA_AUTHENTICATED; |
1130 | cfg80211_send_rx_deauth(sdata->dev, (u8 *) mgmt, len); | ||
1128 | } | 1131 | } |
1129 | 1132 | ||
1130 | 1133 | ||
@@ -1154,6 +1157,7 @@ static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1154 | } | 1157 | } |
1155 | 1158 | ||
1156 | ieee80211_set_disassoc(sdata, false, false, reason_code); | 1159 | ieee80211_set_disassoc(sdata, false, false, reason_code); |
1160 | cfg80211_send_rx_disassoc(sdata->dev, (u8 *) mgmt, len); | ||
1157 | } | 1161 | } |
1158 | 1162 | ||
1159 | 1163 | ||
@@ -1370,6 +1374,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1370 | ieee80211_set_associated(sdata, changed); | 1374 | ieee80211_set_associated(sdata, changed); |
1371 | 1375 | ||
1372 | ieee80211_associated(sdata); | 1376 | ieee80211_associated(sdata); |
1377 | cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, len); | ||
1373 | } | 1378 | } |
1374 | 1379 | ||
1375 | 1380 | ||
diff --git a/net/wireless/Makefile b/net/wireless/Makefile index c157b4d8014b..6d1e7b27b752 100644 --- a/net/wireless/Makefile +++ b/net/wireless/Makefile | |||
@@ -5,7 +5,7 @@ obj-$(CONFIG_LIB80211_CRYPT_WEP) += lib80211_crypt_wep.o | |||
5 | obj-$(CONFIG_LIB80211_CRYPT_CCMP) += lib80211_crypt_ccmp.o | 5 | obj-$(CONFIG_LIB80211_CRYPT_CCMP) += lib80211_crypt_ccmp.o |
6 | obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o | 6 | obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o |
7 | 7 | ||
8 | cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o | 8 | cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o mlme.o |
9 | cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o | 9 | cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o |
10 | 10 | ||
11 | ccflags-y += -D__CHECK_ENDIAN__ | 11 | ccflags-y += -D__CHECK_ENDIAN__ |
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c new file mode 100644 index 000000000000..bec5721b6f99 --- /dev/null +++ b/net/wireless/mlme.c | |||
@@ -0,0 +1,46 @@ | |||
1 | /* | ||
2 | * cfg80211 MLME SAP interface | ||
3 | * | ||
4 | * Copyright (c) 2009, Jouni Malinen <j@w1.fi> | ||
5 | */ | ||
6 | |||
7 | #include <linux/kernel.h> | ||
8 | #include <linux/module.h> | ||
9 | #include <linux/netdevice.h> | ||
10 | #include <linux/nl80211.h> | ||
11 | #include <net/cfg80211.h> | ||
12 | #include "core.h" | ||
13 | #include "nl80211.h" | ||
14 | |||
15 | void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len) | ||
16 | { | ||
17 | struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; | ||
18 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
19 | nl80211_send_rx_auth(rdev, dev, buf, len); | ||
20 | } | ||
21 | EXPORT_SYMBOL(cfg80211_send_rx_auth); | ||
22 | |||
23 | void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len) | ||
24 | { | ||
25 | struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; | ||
26 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
27 | nl80211_send_rx_assoc(rdev, dev, buf, len); | ||
28 | } | ||
29 | EXPORT_SYMBOL(cfg80211_send_rx_assoc); | ||
30 | |||
31 | void cfg80211_send_rx_deauth(struct net_device *dev, const u8 *buf, size_t len) | ||
32 | { | ||
33 | struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; | ||
34 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
35 | nl80211_send_rx_deauth(rdev, dev, buf, len); | ||
36 | } | ||
37 | EXPORT_SYMBOL(cfg80211_send_rx_deauth); | ||
38 | |||
39 | void cfg80211_send_rx_disassoc(struct net_device *dev, const u8 *buf, | ||
40 | size_t len) | ||
41 | { | ||
42 | struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; | ||
43 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
44 | nl80211_send_rx_disassoc(rdev, dev, buf, len); | ||
45 | } | ||
46 | EXPORT_SYMBOL(cfg80211_send_rx_disassoc); | ||
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index a3ecf8d73898..c034c2418cb3 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -2830,6 +2830,9 @@ static struct genl_ops nl80211_ops[] = { | |||
2830 | .dumpit = nl80211_dump_scan, | 2830 | .dumpit = nl80211_dump_scan, |
2831 | }, | 2831 | }, |
2832 | }; | 2832 | }; |
2833 | static struct genl_multicast_group nl80211_mlme_mcgrp = { | ||
2834 | .name = "mlme", | ||
2835 | }; | ||
2833 | 2836 | ||
2834 | /* multicast groups */ | 2837 | /* multicast groups */ |
2835 | static struct genl_multicast_group nl80211_config_mcgrp = { | 2838 | static struct genl_multicast_group nl80211_config_mcgrp = { |
@@ -2975,6 +2978,71 @@ nla_put_failure: | |||
2975 | nlmsg_free(msg); | 2978 | nlmsg_free(msg); |
2976 | } | 2979 | } |
2977 | 2980 | ||
2981 | static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev, | ||
2982 | struct net_device *netdev, | ||
2983 | const u8 *buf, size_t len, | ||
2984 | enum nl80211_commands cmd) | ||
2985 | { | ||
2986 | struct sk_buff *msg; | ||
2987 | void *hdr; | ||
2988 | |||
2989 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | ||
2990 | if (!msg) | ||
2991 | return; | ||
2992 | |||
2993 | hdr = nl80211hdr_put(msg, 0, 0, 0, cmd); | ||
2994 | if (!hdr) { | ||
2995 | nlmsg_free(msg); | ||
2996 | return; | ||
2997 | } | ||
2998 | |||
2999 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); | ||
3000 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); | ||
3001 | NLA_PUT(msg, NL80211_ATTR_FRAME, len, buf); | ||
3002 | |||
3003 | if (genlmsg_end(msg, hdr) < 0) { | ||
3004 | nlmsg_free(msg); | ||
3005 | return; | ||
3006 | } | ||
3007 | |||
3008 | genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, GFP_KERNEL); | ||
3009 | return; | ||
3010 | |||
3011 | nla_put_failure: | ||
3012 | genlmsg_cancel(msg, hdr); | ||
3013 | nlmsg_free(msg); | ||
3014 | } | ||
3015 | |||
3016 | void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev, | ||
3017 | struct net_device *netdev, const u8 *buf, size_t len) | ||
3018 | { | ||
3019 | nl80211_send_mlme_event(rdev, netdev, buf, len, | ||
3020 | NL80211_CMD_AUTHENTICATE); | ||
3021 | } | ||
3022 | |||
3023 | void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev, | ||
3024 | struct net_device *netdev, const u8 *buf, | ||
3025 | size_t len) | ||
3026 | { | ||
3027 | nl80211_send_mlme_event(rdev, netdev, buf, len, NL80211_CMD_ASSOCIATE); | ||
3028 | } | ||
3029 | |||
3030 | void nl80211_send_rx_deauth(struct cfg80211_registered_device *rdev, | ||
3031 | struct net_device *netdev, const u8 *buf, | ||
3032 | size_t len) | ||
3033 | { | ||
3034 | nl80211_send_mlme_event(rdev, netdev, buf, len, | ||
3035 | NL80211_CMD_DEAUTHENTICATE); | ||
3036 | } | ||
3037 | |||
3038 | void nl80211_send_rx_disassoc(struct cfg80211_registered_device *rdev, | ||
3039 | struct net_device *netdev, const u8 *buf, | ||
3040 | size_t len) | ||
3041 | { | ||
3042 | nl80211_send_mlme_event(rdev, netdev, buf, len, | ||
3043 | NL80211_CMD_DISASSOCIATE); | ||
3044 | } | ||
3045 | |||
2978 | /* initialisation/exit functions */ | 3046 | /* initialisation/exit functions */ |
2979 | 3047 | ||
2980 | int nl80211_init(void) | 3048 | int nl80211_init(void) |
@@ -3003,6 +3071,10 @@ int nl80211_init(void) | |||
3003 | if (err) | 3071 | if (err) |
3004 | goto err_out; | 3072 | goto err_out; |
3005 | 3073 | ||
3074 | err = genl_register_mc_group(&nl80211_fam, &nl80211_mlme_mcgrp); | ||
3075 | if (err) | ||
3076 | goto err_out; | ||
3077 | |||
3006 | return 0; | 3078 | return 0; |
3007 | err_out: | 3079 | err_out: |
3008 | genl_unregister_family(&nl80211_fam); | 3080 | genl_unregister_family(&nl80211_fam); |
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index 5b5fe1339de0..b77af4ab80be 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h | |||
@@ -11,5 +11,17 @@ extern void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, | |||
11 | extern void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, | 11 | extern void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, |
12 | struct net_device *netdev); | 12 | struct net_device *netdev); |
13 | extern void nl80211_send_reg_change_event(struct regulatory_request *request); | 13 | extern void nl80211_send_reg_change_event(struct regulatory_request *request); |
14 | extern void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev, | ||
15 | struct net_device *netdev, | ||
16 | const u8 *buf, size_t len); | ||
17 | extern void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev, | ||
18 | struct net_device *netdev, | ||
19 | const u8 *buf, size_t len); | ||
20 | extern void nl80211_send_rx_deauth(struct cfg80211_registered_device *rdev, | ||
21 | struct net_device *netdev, | ||
22 | const u8 *buf, size_t len); | ||
23 | extern void nl80211_send_rx_disassoc(struct cfg80211_registered_device *rdev, | ||
24 | struct net_device *netdev, | ||
25 | const u8 *buf, size_t len); | ||
14 | 26 | ||
15 | #endif /* __NET_WIRELESS_NL80211_H */ | 27 | #endif /* __NET_WIRELESS_NL80211_H */ |