diff options
author | David S. Miller <davem@sunset.davemloft.net> | 2007-07-14 21:58:49 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-07-14 21:58:49 -0400 |
commit | cf3842ec5015c862f4869e3641a8549393bb958e (patch) | |
tree | 6c2f0158504f3463fcca1359de90b699cb636e97 /net | |
parent | b3b0b681b12478a7afa7d1f3d58be96830e16c7d (diff) | |
parent | 63fc33ceb0ccc08b3f62d7bfe56a33eb33ca9427 (diff) |
Merge branch 'upstream-davem' of master.kernel.org:/pub/scm/linux/kernel/git/linville/wireless-2.6
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/debugfs_netdev.c | 2 | ||||
-rw-r--r-- | net/mac80211/hostapd_ioctl.h | 8 | ||||
-rw-r--r-- | net/mac80211/ieee80211.c | 449 | ||||
-rw-r--r-- | net/mac80211/ieee80211_common.h | 9 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 14 | ||||
-rw-r--r-- | net/mac80211/ieee80211_iface.c | 3 | ||||
-rw-r--r-- | net/mac80211/ieee80211_ioctl.c | 240 | ||||
-rw-r--r-- | net/mac80211/ieee80211_sta.c | 98 | ||||
-rw-r--r-- | net/mac80211/rc80211_simple.c | 8 | ||||
-rw-r--r-- | net/wireless/Makefile | 2 | ||||
-rw-r--r-- | net/wireless/radiotap.c | 257 |
11 files changed, 778 insertions, 312 deletions
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 9e3964638bad..a3e01d76d503 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c | |||
@@ -118,7 +118,7 @@ static ssize_t ieee80211_if_fmt_flags( | |||
118 | sdata->u.sta.authenticated ? "AUTH\n" : "", | 118 | sdata->u.sta.authenticated ? "AUTH\n" : "", |
119 | sdata->u.sta.associated ? "ASSOC\n" : "", | 119 | sdata->u.sta.associated ? "ASSOC\n" : "", |
120 | sdata->u.sta.probereq_poll ? "PROBEREQ POLL\n" : "", | 120 | sdata->u.sta.probereq_poll ? "PROBEREQ POLL\n" : "", |
121 | sdata->u.sta.use_protection ? "CTS prot\n" : ""); | 121 | sdata->use_protection ? "CTS prot\n" : ""); |
122 | } | 122 | } |
123 | __IEEE80211_IF_FILE(flags); | 123 | __IEEE80211_IF_FILE(flags); |
124 | 124 | ||
diff --git a/net/mac80211/hostapd_ioctl.h b/net/mac80211/hostapd_ioctl.h index 34fa128e9872..52da513f060a 100644 --- a/net/mac80211/hostapd_ioctl.h +++ b/net/mac80211/hostapd_ioctl.h | |||
@@ -26,24 +26,16 @@ | |||
26 | * mess shall be deleted completely. */ | 26 | * mess shall be deleted completely. */ |
27 | enum { | 27 | enum { |
28 | PRISM2_PARAM_IEEE_802_1X = 23, | 28 | PRISM2_PARAM_IEEE_802_1X = 23, |
29 | PRISM2_PARAM_ANTSEL_TX = 24, | ||
30 | PRISM2_PARAM_ANTSEL_RX = 25, | ||
31 | 29 | ||
32 | /* Instant802 additions */ | 30 | /* Instant802 additions */ |
33 | PRISM2_PARAM_CTS_PROTECT_ERP_FRAMES = 1001, | 31 | PRISM2_PARAM_CTS_PROTECT_ERP_FRAMES = 1001, |
34 | PRISM2_PARAM_DROP_UNENCRYPTED = 1002, | ||
35 | PRISM2_PARAM_PREAMBLE = 1003, | 32 | PRISM2_PARAM_PREAMBLE = 1003, |
36 | PRISM2_PARAM_SHORT_SLOT_TIME = 1006, | 33 | PRISM2_PARAM_SHORT_SLOT_TIME = 1006, |
37 | PRISM2_PARAM_NEXT_MODE = 1008, | 34 | PRISM2_PARAM_NEXT_MODE = 1008, |
38 | PRISM2_PARAM_CLEAR_KEYS = 1009, | ||
39 | PRISM2_PARAM_RADIO_ENABLED = 1010, | 35 | PRISM2_PARAM_RADIO_ENABLED = 1010, |
40 | PRISM2_PARAM_ANTENNA_MODE = 1013, | 36 | PRISM2_PARAM_ANTENNA_MODE = 1013, |
41 | PRISM2_PARAM_STAT_TIME = 1016, | 37 | PRISM2_PARAM_STAT_TIME = 1016, |
42 | PRISM2_PARAM_STA_ANTENNA_SEL = 1017, | 38 | PRISM2_PARAM_STA_ANTENNA_SEL = 1017, |
43 | PRISM2_PARAM_FORCE_UNICAST_RATE = 1018, | ||
44 | PRISM2_PARAM_RATE_CTRL_NUM_UP = 1019, | ||
45 | PRISM2_PARAM_RATE_CTRL_NUM_DOWN = 1020, | ||
46 | PRISM2_PARAM_MAX_RATECTRL_RATE = 1021, | ||
47 | PRISM2_PARAM_TX_POWER_REDUCTION = 1022, | 39 | PRISM2_PARAM_TX_POWER_REDUCTION = 1022, |
48 | PRISM2_PARAM_KEY_TX_RX_THRESHOLD = 1024, | 40 | PRISM2_PARAM_KEY_TX_RX_THRESHOLD = 1024, |
49 | PRISM2_PARAM_DEFAULT_WEP_ONLY = 1026, | 41 | PRISM2_PARAM_DEFAULT_WEP_ONLY = 1026, |
diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 4e84f24fd439..2ddf4ef4065e 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/compiler.h> | 24 | #include <linux/compiler.h> |
25 | #include <linux/bitmap.h> | 25 | #include <linux/bitmap.h> |
26 | #include <net/cfg80211.h> | 26 | #include <net/cfg80211.h> |
27 | #include <asm/unaligned.h> | ||
27 | 28 | ||
28 | #include "ieee80211_common.h" | 29 | #include "ieee80211_common.h" |
29 | #include "ieee80211_i.h" | 30 | #include "ieee80211_i.h" |
@@ -56,6 +57,17 @@ static const unsigned char eapol_header[] = | |||
56 | { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x88, 0x8e }; | 57 | { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x88, 0x8e }; |
57 | 58 | ||
58 | 59 | ||
60 | /* | ||
61 | * For seeing transmitted packets on monitor interfaces | ||
62 | * we have a radiotap header too. | ||
63 | */ | ||
64 | struct ieee80211_tx_status_rtap_hdr { | ||
65 | struct ieee80211_radiotap_header hdr; | ||
66 | __le16 tx_flags; | ||
67 | u8 data_retries; | ||
68 | } __attribute__ ((packed)); | ||
69 | |||
70 | |||
59 | static inline void ieee80211_include_sequence(struct ieee80211_sub_if_data *sdata, | 71 | static inline void ieee80211_include_sequence(struct ieee80211_sub_if_data *sdata, |
60 | struct ieee80211_hdr *hdr) | 72 | struct ieee80211_hdr *hdr) |
61 | { | 73 | { |
@@ -430,7 +442,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_txrx_data *tx) | |||
430 | if (!tx->u.tx.rate) | 442 | if (!tx->u.tx.rate) |
431 | return TXRX_DROP; | 443 | return TXRX_DROP; |
432 | if (tx->u.tx.mode->mode == MODE_IEEE80211G && | 444 | if (tx->u.tx.mode->mode == MODE_IEEE80211G && |
433 | tx->local->cts_protect_erp_frames && tx->fragmented && | 445 | tx->sdata->use_protection && tx->fragmented && |
434 | extra.nonerp) { | 446 | extra.nonerp) { |
435 | tx->u.tx.last_frag_rate = tx->u.tx.rate; | 447 | tx->u.tx.last_frag_rate = tx->u.tx.rate; |
436 | tx->u.tx.probe_last_frag = extra.probe ? 1 : 0; | 448 | tx->u.tx.probe_last_frag = extra.probe ? 1 : 0; |
@@ -528,7 +540,7 @@ ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx) | |||
528 | /* reserve enough extra head and tail room for possible | 540 | /* reserve enough extra head and tail room for possible |
529 | * encryption */ | 541 | * encryption */ |
530 | frag = frags[i] = | 542 | frag = frags[i] = |
531 | dev_alloc_skb(tx->local->hw.extra_tx_headroom + | 543 | dev_alloc_skb(tx->local->tx_headroom + |
532 | frag_threshold + | 544 | frag_threshold + |
533 | IEEE80211_ENCRYPT_HEADROOM + | 545 | IEEE80211_ENCRYPT_HEADROOM + |
534 | IEEE80211_ENCRYPT_TAILROOM); | 546 | IEEE80211_ENCRYPT_TAILROOM); |
@@ -537,8 +549,8 @@ ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx) | |||
537 | /* Make sure that all fragments use the same priority so | 549 | /* Make sure that all fragments use the same priority so |
538 | * that they end up using the same TX queue */ | 550 | * that they end up using the same TX queue */ |
539 | frag->priority = first->priority; | 551 | frag->priority = first->priority; |
540 | skb_reserve(frag, tx->local->hw.extra_tx_headroom + | 552 | skb_reserve(frag, tx->local->tx_headroom + |
541 | IEEE80211_ENCRYPT_HEADROOM); | 553 | IEEE80211_ENCRYPT_HEADROOM); |
542 | fhdr = (struct ieee80211_hdr *) skb_put(frag, hdrlen); | 554 | fhdr = (struct ieee80211_hdr *) skb_put(frag, hdrlen); |
543 | memcpy(fhdr, first->data, hdrlen); | 555 | memcpy(fhdr, first->data, hdrlen); |
544 | if (i == num_fragm - 2) | 556 | if (i == num_fragm - 2) |
@@ -856,8 +868,7 @@ ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx) | |||
856 | * for the frame. */ | 868 | * for the frame. */ |
857 | if (mode->mode == MODE_IEEE80211G && | 869 | if (mode->mode == MODE_IEEE80211G && |
858 | (tx->u.tx.rate->flags & IEEE80211_RATE_ERP) && | 870 | (tx->u.tx.rate->flags & IEEE80211_RATE_ERP) && |
859 | tx->u.tx.unicast && | 871 | tx->u.tx.unicast && tx->sdata->use_protection && |
860 | tx->local->cts_protect_erp_frames && | ||
861 | !(control->flags & IEEE80211_TXCTL_USE_RTS_CTS)) | 872 | !(control->flags & IEEE80211_TXCTL_USE_RTS_CTS)) |
862 | control->flags |= IEEE80211_TXCTL_USE_CTS_PROTECT; | 873 | control->flags |= IEEE80211_TXCTL_USE_CTS_PROTECT; |
863 | 874 | ||
@@ -1118,7 +1129,138 @@ ieee80211_tx_h_ps_buf(struct ieee80211_txrx_data *tx) | |||
1118 | } | 1129 | } |
1119 | 1130 | ||
1120 | 1131 | ||
1121 | static void inline | 1132 | /* |
1133 | * deal with packet injection down monitor interface | ||
1134 | * with Radiotap Header -- only called for monitor mode interface | ||
1135 | */ | ||
1136 | |||
1137 | static ieee80211_txrx_result | ||
1138 | __ieee80211_parse_tx_radiotap( | ||
1139 | struct ieee80211_txrx_data *tx, | ||
1140 | struct sk_buff *skb, struct ieee80211_tx_control *control) | ||
1141 | { | ||
1142 | /* | ||
1143 | * this is the moment to interpret and discard the radiotap header that | ||
1144 | * must be at the start of the packet injected in Monitor mode | ||
1145 | * | ||
1146 | * Need to take some care with endian-ness since radiotap | ||
1147 | * args are little-endian | ||
1148 | */ | ||
1149 | |||
1150 | struct ieee80211_radiotap_iterator iterator; | ||
1151 | struct ieee80211_radiotap_header *rthdr = | ||
1152 | (struct ieee80211_radiotap_header *) skb->data; | ||
1153 | struct ieee80211_hw_mode *mode = tx->local->hw.conf.mode; | ||
1154 | int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len); | ||
1155 | |||
1156 | /* | ||
1157 | * default control situation for all injected packets | ||
1158 | * FIXME: this does not suit all usage cases, expand to allow control | ||
1159 | */ | ||
1160 | |||
1161 | control->retry_limit = 1; /* no retry */ | ||
1162 | control->key_idx = -1; /* no encryption key */ | ||
1163 | control->flags &= ~(IEEE80211_TXCTL_USE_RTS_CTS | | ||
1164 | IEEE80211_TXCTL_USE_CTS_PROTECT); | ||
1165 | control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT | | ||
1166 | IEEE80211_TXCTL_NO_ACK; | ||
1167 | control->antenna_sel_tx = 0; /* default to default antenna */ | ||
1168 | |||
1169 | /* | ||
1170 | * for every radiotap entry that is present | ||
1171 | * (ieee80211_radiotap_iterator_next returns -ENOENT when no more | ||
1172 | * entries present, or -EINVAL on error) | ||
1173 | */ | ||
1174 | |||
1175 | while (!ret) { | ||
1176 | int i, target_rate; | ||
1177 | |||
1178 | ret = ieee80211_radiotap_iterator_next(&iterator); | ||
1179 | |||
1180 | if (ret) | ||
1181 | continue; | ||
1182 | |||
1183 | /* see if this argument is something we can use */ | ||
1184 | switch (iterator.this_arg_index) { | ||
1185 | /* | ||
1186 | * You must take care when dereferencing iterator.this_arg | ||
1187 | * for multibyte types... the pointer is not aligned. Use | ||
1188 | * get_unaligned((type *)iterator.this_arg) to dereference | ||
1189 | * iterator.this_arg for type "type" safely on all arches. | ||
1190 | */ | ||
1191 | case IEEE80211_RADIOTAP_RATE: | ||
1192 | /* | ||
1193 | * radiotap rate u8 is in 500kbps units eg, 0x02=1Mbps | ||
1194 | * ieee80211 rate int is in 100kbps units eg, 0x0a=1Mbps | ||
1195 | */ | ||
1196 | target_rate = (*iterator.this_arg) * 5; | ||
1197 | for (i = 0; i < mode->num_rates; i++) { | ||
1198 | struct ieee80211_rate *r = &mode->rates[i]; | ||
1199 | |||
1200 | if (r->rate > target_rate) | ||
1201 | continue; | ||
1202 | |||
1203 | control->rate = r; | ||
1204 | |||
1205 | if (r->flags & IEEE80211_RATE_PREAMBLE2) | ||
1206 | control->tx_rate = r->val2; | ||
1207 | else | ||
1208 | control->tx_rate = r->val; | ||
1209 | |||
1210 | /* end on exact match */ | ||
1211 | if (r->rate == target_rate) | ||
1212 | i = mode->num_rates; | ||
1213 | } | ||
1214 | break; | ||
1215 | |||
1216 | case IEEE80211_RADIOTAP_ANTENNA: | ||
1217 | /* | ||
1218 | * radiotap uses 0 for 1st ant, mac80211 is 1 for | ||
1219 | * 1st ant | ||
1220 | */ | ||
1221 | control->antenna_sel_tx = (*iterator.this_arg) + 1; | ||
1222 | break; | ||
1223 | |||
1224 | case IEEE80211_RADIOTAP_DBM_TX_POWER: | ||
1225 | control->power_level = *iterator.this_arg; | ||
1226 | break; | ||
1227 | |||
1228 | case IEEE80211_RADIOTAP_FLAGS: | ||
1229 | if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FCS) { | ||
1230 | /* | ||
1231 | * this indicates that the skb we have been | ||
1232 | * handed has the 32-bit FCS CRC at the end... | ||
1233 | * we should react to that by snipping it off | ||
1234 | * because it will be recomputed and added | ||
1235 | * on transmission | ||
1236 | */ | ||
1237 | if (skb->len < (iterator.max_length + FCS_LEN)) | ||
1238 | return TXRX_DROP; | ||
1239 | |||
1240 | skb_trim(skb, skb->len - FCS_LEN); | ||
1241 | } | ||
1242 | break; | ||
1243 | |||
1244 | default: | ||
1245 | break; | ||
1246 | } | ||
1247 | } | ||
1248 | |||
1249 | if (ret != -ENOENT) /* ie, if we didn't simply run out of fields */ | ||
1250 | return TXRX_DROP; | ||
1251 | |||
1252 | /* | ||
1253 | * remove the radiotap header | ||
1254 | * iterator->max_length was sanity-checked against | ||
1255 | * skb->len by iterator init | ||
1256 | */ | ||
1257 | skb_pull(skb, iterator.max_length); | ||
1258 | |||
1259 | return TXRX_CONTINUE; | ||
1260 | } | ||
1261 | |||
1262 | |||
1263 | static ieee80211_txrx_result inline | ||
1122 | __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, | 1264 | __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, |
1123 | struct sk_buff *skb, | 1265 | struct sk_buff *skb, |
1124 | struct net_device *dev, | 1266 | struct net_device *dev, |
@@ -1126,6 +1268,9 @@ __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, | |||
1126 | { | 1268 | { |
1127 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 1269 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
1128 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 1270 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
1271 | struct ieee80211_sub_if_data *sdata; | ||
1272 | ieee80211_txrx_result res = TXRX_CONTINUE; | ||
1273 | |||
1129 | int hdrlen; | 1274 | int hdrlen; |
1130 | 1275 | ||
1131 | memset(tx, 0, sizeof(*tx)); | 1276 | memset(tx, 0, sizeof(*tx)); |
@@ -1135,7 +1280,32 @@ __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, | |||
1135 | tx->sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 1280 | tx->sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
1136 | tx->sta = sta_info_get(local, hdr->addr1); | 1281 | tx->sta = sta_info_get(local, hdr->addr1); |
1137 | tx->fc = le16_to_cpu(hdr->frame_control); | 1282 | tx->fc = le16_to_cpu(hdr->frame_control); |
1283 | |||
1284 | /* | ||
1285 | * set defaults for things that can be set by | ||
1286 | * injected radiotap headers | ||
1287 | */ | ||
1138 | control->power_level = local->hw.conf.power_level; | 1288 | control->power_level = local->hw.conf.power_level; |
1289 | control->antenna_sel_tx = local->hw.conf.antenna_sel_tx; | ||
1290 | if (local->sta_antenna_sel != STA_ANTENNA_SEL_AUTO && tx->sta) | ||
1291 | control->antenna_sel_tx = tx->sta->antenna_sel_tx; | ||
1292 | |||
1293 | /* process and remove the injection radiotap header */ | ||
1294 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1295 | if (unlikely(sdata->type == IEEE80211_IF_TYPE_MNTR)) { | ||
1296 | if (__ieee80211_parse_tx_radiotap(tx, skb, control) == | ||
1297 | TXRX_DROP) { | ||
1298 | return TXRX_DROP; | ||
1299 | } | ||
1300 | /* | ||
1301 | * we removed the radiotap header after this point, | ||
1302 | * we filled control with what we could use | ||
1303 | * set to the actual ieee header now | ||
1304 | */ | ||
1305 | hdr = (struct ieee80211_hdr *) skb->data; | ||
1306 | res = TXRX_QUEUED; /* indication it was monitor packet */ | ||
1307 | } | ||
1308 | |||
1139 | tx->u.tx.control = control; | 1309 | tx->u.tx.control = control; |
1140 | tx->u.tx.unicast = !is_multicast_ether_addr(hdr->addr1); | 1310 | tx->u.tx.unicast = !is_multicast_ether_addr(hdr->addr1); |
1141 | if (is_multicast_ether_addr(hdr->addr1)) | 1311 | if (is_multicast_ether_addr(hdr->addr1)) |
@@ -1152,9 +1322,6 @@ __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, | |||
1152 | control->flags |= IEEE80211_TXCTL_CLEAR_DST_MASK; | 1322 | control->flags |= IEEE80211_TXCTL_CLEAR_DST_MASK; |
1153 | tx->sta->clear_dst_mask = 0; | 1323 | tx->sta->clear_dst_mask = 0; |
1154 | } | 1324 | } |
1155 | control->antenna_sel_tx = local->hw.conf.antenna_sel_tx; | ||
1156 | if (local->sta_antenna_sel != STA_ANTENNA_SEL_AUTO && tx->sta) | ||
1157 | control->antenna_sel_tx = tx->sta->antenna_sel_tx; | ||
1158 | hdrlen = ieee80211_get_hdrlen(tx->fc); | 1325 | hdrlen = ieee80211_get_hdrlen(tx->fc); |
1159 | if (skb->len > hdrlen + sizeof(rfc1042_header) + 2) { | 1326 | if (skb->len > hdrlen + sizeof(rfc1042_header) + 2) { |
1160 | u8 *pos = &skb->data[hdrlen + sizeof(rfc1042_header)]; | 1327 | u8 *pos = &skb->data[hdrlen + sizeof(rfc1042_header)]; |
@@ -1162,6 +1329,7 @@ __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, | |||
1162 | } | 1329 | } |
1163 | control->flags |= IEEE80211_TXCTL_FIRST_FRAGMENT; | 1330 | control->flags |= IEEE80211_TXCTL_FIRST_FRAGMENT; |
1164 | 1331 | ||
1332 | return res; | ||
1165 | } | 1333 | } |
1166 | 1334 | ||
1167 | static int inline is_ieee80211_device(struct net_device *dev, | 1335 | static int inline is_ieee80211_device(struct net_device *dev, |
@@ -1274,7 +1442,7 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, | |||
1274 | struct sta_info *sta; | 1442 | struct sta_info *sta; |
1275 | ieee80211_tx_handler *handler; | 1443 | ieee80211_tx_handler *handler; |
1276 | struct ieee80211_txrx_data tx; | 1444 | struct ieee80211_txrx_data tx; |
1277 | ieee80211_txrx_result res = TXRX_DROP; | 1445 | ieee80211_txrx_result res = TXRX_DROP, res_prepare; |
1278 | int ret, i; | 1446 | int ret, i; |
1279 | 1447 | ||
1280 | WARN_ON(__ieee80211_queue_pending(local, control->queue)); | 1448 | WARN_ON(__ieee80211_queue_pending(local, control->queue)); |
@@ -1284,15 +1452,26 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, | |||
1284 | return 0; | 1452 | return 0; |
1285 | } | 1453 | } |
1286 | 1454 | ||
1287 | __ieee80211_tx_prepare(&tx, skb, dev, control); | 1455 | res_prepare = __ieee80211_tx_prepare(&tx, skb, dev, control); |
1456 | |||
1457 | if (res_prepare == TXRX_DROP) { | ||
1458 | dev_kfree_skb(skb); | ||
1459 | return 0; | ||
1460 | } | ||
1461 | |||
1288 | sta = tx.sta; | 1462 | sta = tx.sta; |
1289 | tx.u.tx.mgmt_interface = mgmt; | 1463 | tx.u.tx.mgmt_interface = mgmt; |
1290 | tx.u.tx.mode = local->hw.conf.mode; | 1464 | tx.u.tx.mode = local->hw.conf.mode; |
1291 | 1465 | ||
1292 | for (handler = local->tx_handlers; *handler != NULL; handler++) { | 1466 | if (res_prepare == TXRX_QUEUED) { /* if it was an injected packet */ |
1293 | res = (*handler)(&tx); | 1467 | res = TXRX_CONTINUE; |
1294 | if (res != TXRX_CONTINUE) | 1468 | } else { |
1295 | break; | 1469 | for (handler = local->tx_handlers; *handler != NULL; |
1470 | handler++) { | ||
1471 | res = (*handler)(&tx); | ||
1472 | if (res != TXRX_CONTINUE) | ||
1473 | break; | ||
1474 | } | ||
1296 | } | 1475 | } |
1297 | 1476 | ||
1298 | skb = tx.skb; /* handlers are allowed to change skb */ | 1477 | skb = tx.skb; /* handlers are allowed to change skb */ |
@@ -1467,8 +1646,7 @@ static int ieee80211_master_start_xmit(struct sk_buff *skb, | |||
1467 | } | 1646 | } |
1468 | osdata = IEEE80211_DEV_TO_SUB_IF(odev); | 1647 | osdata = IEEE80211_DEV_TO_SUB_IF(odev); |
1469 | 1648 | ||
1470 | headroom = osdata->local->hw.extra_tx_headroom + | 1649 | headroom = osdata->local->tx_headroom + IEEE80211_ENCRYPT_HEADROOM; |
1471 | IEEE80211_ENCRYPT_HEADROOM; | ||
1472 | if (skb_headroom(skb) < headroom) { | 1650 | if (skb_headroom(skb) < headroom) { |
1473 | if (pskb_expand_head(skb, headroom, 0, GFP_ATOMIC)) { | 1651 | if (pskb_expand_head(skb, headroom, 0, GFP_ATOMIC)) { |
1474 | dev_kfree_skb(skb); | 1652 | dev_kfree_skb(skb); |
@@ -1494,6 +1672,56 @@ static int ieee80211_master_start_xmit(struct sk_buff *skb, | |||
1494 | } | 1672 | } |
1495 | 1673 | ||
1496 | 1674 | ||
1675 | int ieee80211_monitor_start_xmit(struct sk_buff *skb, | ||
1676 | struct net_device *dev) | ||
1677 | { | ||
1678 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
1679 | struct ieee80211_tx_packet_data *pkt_data; | ||
1680 | struct ieee80211_radiotap_header *prthdr = | ||
1681 | (struct ieee80211_radiotap_header *)skb->data; | ||
1682 | u16 len; | ||
1683 | |||
1684 | /* | ||
1685 | * there must be a radiotap header at the | ||
1686 | * start in this case | ||
1687 | */ | ||
1688 | if (unlikely(prthdr->it_version)) { | ||
1689 | /* only version 0 is supported */ | ||
1690 | dev_kfree_skb(skb); | ||
1691 | return NETDEV_TX_OK; | ||
1692 | } | ||
1693 | |||
1694 | skb->dev = local->mdev; | ||
1695 | |||
1696 | pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; | ||
1697 | memset(pkt_data, 0, sizeof(*pkt_data)); | ||
1698 | pkt_data->ifindex = dev->ifindex; | ||
1699 | pkt_data->mgmt_iface = 0; | ||
1700 | pkt_data->do_not_encrypt = 1; | ||
1701 | |||
1702 | /* above needed because we set skb device to master */ | ||
1703 | |||
1704 | /* | ||
1705 | * fix up the pointers accounting for the radiotap | ||
1706 | * header still being in there. We are being given | ||
1707 | * a precooked IEEE80211 header so no need for | ||
1708 | * normal processing | ||
1709 | */ | ||
1710 | len = le16_to_cpu(get_unaligned(&prthdr->it_len)); | ||
1711 | skb_set_mac_header(skb, len); | ||
1712 | skb_set_network_header(skb, len + sizeof(struct ieee80211_hdr)); | ||
1713 | skb_set_transport_header(skb, len + sizeof(struct ieee80211_hdr)); | ||
1714 | |||
1715 | /* | ||
1716 | * pass the radiotap header up to | ||
1717 | * the next stage intact | ||
1718 | */ | ||
1719 | dev_queue_xmit(skb); | ||
1720 | |||
1721 | return NETDEV_TX_OK; | ||
1722 | } | ||
1723 | |||
1724 | |||
1497 | /** | 1725 | /** |
1498 | * ieee80211_subif_start_xmit - netif start_xmit function for Ethernet-type | 1726 | * ieee80211_subif_start_xmit - netif start_xmit function for Ethernet-type |
1499 | * subinterfaces (wlan#, WDS, and VLAN interfaces) | 1727 | * subinterfaces (wlan#, WDS, and VLAN interfaces) |
@@ -1509,8 +1737,8 @@ static int ieee80211_master_start_xmit(struct sk_buff *skb, | |||
1509 | * encapsulated packet will then be passed to master interface, wlan#.11, for | 1737 | * encapsulated packet will then be passed to master interface, wlan#.11, for |
1510 | * transmission (through low-level driver). | 1738 | * transmission (through low-level driver). |
1511 | */ | 1739 | */ |
1512 | static int ieee80211_subif_start_xmit(struct sk_buff *skb, | 1740 | int ieee80211_subif_start_xmit(struct sk_buff *skb, |
1513 | struct net_device *dev) | 1741 | struct net_device *dev) |
1514 | { | 1742 | { |
1515 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 1743 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
1516 | struct ieee80211_tx_packet_data *pkt_data; | 1744 | struct ieee80211_tx_packet_data *pkt_data; |
@@ -1619,7 +1847,7 @@ static int ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1619 | * build in headroom in __dev_alloc_skb() (linux/skbuff.h) and | 1847 | * build in headroom in __dev_alloc_skb() (linux/skbuff.h) and |
1620 | * alloc_skb() (net/core/skbuff.c) | 1848 | * alloc_skb() (net/core/skbuff.c) |
1621 | */ | 1849 | */ |
1622 | head_need = hdrlen + encaps_len + local->hw.extra_tx_headroom; | 1850 | head_need = hdrlen + encaps_len + local->tx_headroom; |
1623 | head_need -= skb_headroom(skb); | 1851 | head_need -= skb_headroom(skb); |
1624 | 1852 | ||
1625 | /* We are going to modify skb data, so make a copy of it if happens to | 1853 | /* We are going to modify skb data, so make a copy of it if happens to |
@@ -1658,7 +1886,7 @@ static int ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1658 | 1886 | ||
1659 | pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; | 1887 | pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; |
1660 | memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data)); | 1888 | memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data)); |
1661 | pkt_data->ifindex = sdata->dev->ifindex; | 1889 | pkt_data->ifindex = dev->ifindex; |
1662 | pkt_data->mgmt_iface = (sdata->type == IEEE80211_IF_TYPE_MGMT); | 1890 | pkt_data->mgmt_iface = (sdata->type == IEEE80211_IF_TYPE_MGMT); |
1663 | pkt_data->do_not_encrypt = no_encrypt; | 1891 | pkt_data->do_not_encrypt = no_encrypt; |
1664 | 1892 | ||
@@ -1706,9 +1934,9 @@ ieee80211_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
1706 | return 0; | 1934 | return 0; |
1707 | } | 1935 | } |
1708 | 1936 | ||
1709 | if (skb_headroom(skb) < sdata->local->hw.extra_tx_headroom) { | 1937 | if (skb_headroom(skb) < sdata->local->tx_headroom) { |
1710 | if (pskb_expand_head(skb, | 1938 | if (pskb_expand_head(skb, sdata->local->tx_headroom, |
1711 | sdata->local->hw.extra_tx_headroom, 0, GFP_ATOMIC)) { | 1939 | 0, GFP_ATOMIC)) { |
1712 | dev_kfree_skb(skb); | 1940 | dev_kfree_skb(skb); |
1713 | return 0; | 1941 | return 0; |
1714 | } | 1942 | } |
@@ -1847,12 +2075,12 @@ struct sk_buff * ieee80211_beacon_get(struct ieee80211_hw *hw, int if_id, | |||
1847 | bh_len = ap->beacon_head_len; | 2075 | bh_len = ap->beacon_head_len; |
1848 | bt_len = ap->beacon_tail_len; | 2076 | bt_len = ap->beacon_tail_len; |
1849 | 2077 | ||
1850 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + | 2078 | skb = dev_alloc_skb(local->tx_headroom + |
1851 | bh_len + bt_len + 256 /* maximum TIM len */); | 2079 | bh_len + bt_len + 256 /* maximum TIM len */); |
1852 | if (!skb) | 2080 | if (!skb) |
1853 | return NULL; | 2081 | return NULL; |
1854 | 2082 | ||
1855 | skb_reserve(skb, local->hw.extra_tx_headroom); | 2083 | skb_reserve(skb, local->tx_headroom); |
1856 | memcpy(skb_put(skb, bh_len), b_head, bh_len); | 2084 | memcpy(skb_put(skb, bh_len), b_head, bh_len); |
1857 | 2085 | ||
1858 | ieee80211_include_sequence(sdata, (struct ieee80211_hdr *)skb->data); | 2086 | ieee80211_include_sequence(sdata, (struct ieee80211_hdr *)skb->data); |
@@ -2376,8 +2604,7 @@ static void ieee80211_start_hard_monitor(struct ieee80211_local *local) | |||
2376 | struct ieee80211_if_init_conf conf; | 2604 | struct ieee80211_if_init_conf conf; |
2377 | 2605 | ||
2378 | if (local->open_count && local->open_count == local->monitors && | 2606 | if (local->open_count && local->open_count == local->monitors && |
2379 | !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER) && | 2607 | !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER)) { |
2380 | local->ops->add_interface) { | ||
2381 | conf.if_id = -1; | 2608 | conf.if_id = -1; |
2382 | conf.type = IEEE80211_IF_TYPE_MNTR; | 2609 | conf.type = IEEE80211_IF_TYPE_MNTR; |
2383 | conf.mac_addr = NULL; | 2610 | conf.mac_addr = NULL; |
@@ -2420,21 +2647,14 @@ static int ieee80211_open(struct net_device *dev) | |||
2420 | } | 2647 | } |
2421 | ieee80211_start_soft_monitor(local); | 2648 | ieee80211_start_soft_monitor(local); |
2422 | 2649 | ||
2423 | if (local->ops->add_interface) { | 2650 | conf.if_id = dev->ifindex; |
2424 | conf.if_id = dev->ifindex; | 2651 | conf.type = sdata->type; |
2425 | conf.type = sdata->type; | 2652 | conf.mac_addr = dev->dev_addr; |
2426 | conf.mac_addr = dev->dev_addr; | 2653 | res = local->ops->add_interface(local_to_hw(local), &conf); |
2427 | res = local->ops->add_interface(local_to_hw(local), &conf); | 2654 | if (res) { |
2428 | if (res) { | 2655 | if (sdata->type == IEEE80211_IF_TYPE_MNTR) |
2429 | if (sdata->type == IEEE80211_IF_TYPE_MNTR) | 2656 | ieee80211_start_hard_monitor(local); |
2430 | ieee80211_start_hard_monitor(local); | 2657 | return res; |
2431 | return res; | ||
2432 | } | ||
2433 | } else { | ||
2434 | if (sdata->type != IEEE80211_IF_TYPE_STA) | ||
2435 | return -EOPNOTSUPP; | ||
2436 | if (local->open_count > 0) | ||
2437 | return -ENOBUFS; | ||
2438 | } | 2658 | } |
2439 | 2659 | ||
2440 | if (local->open_count == 0) { | 2660 | if (local->open_count == 0) { |
@@ -2941,34 +3161,6 @@ int ieee80211_radar_status(struct ieee80211_hw *hw, int channel, | |||
2941 | } | 3161 | } |
2942 | EXPORT_SYMBOL(ieee80211_radar_status); | 3162 | EXPORT_SYMBOL(ieee80211_radar_status); |
2943 | 3163 | ||
2944 | int ieee80211_set_aid_for_sta(struct ieee80211_hw *hw, u8 *peer_address, | ||
2945 | u16 aid) | ||
2946 | { | ||
2947 | struct sk_buff *skb; | ||
2948 | struct ieee80211_msg_set_aid_for_sta *msg; | ||
2949 | struct ieee80211_local *local = hw_to_local(hw); | ||
2950 | |||
2951 | /* unlikely because if this event only happens for APs, | ||
2952 | * which require an open ap device. */ | ||
2953 | if (unlikely(!local->apdev)) | ||
2954 | return 0; | ||
2955 | |||
2956 | skb = dev_alloc_skb(sizeof(struct ieee80211_frame_info) + | ||
2957 | sizeof(struct ieee80211_msg_set_aid_for_sta)); | ||
2958 | |||
2959 | if (!skb) | ||
2960 | return -ENOMEM; | ||
2961 | skb_reserve(skb, sizeof(struct ieee80211_frame_info)); | ||
2962 | |||
2963 | msg = (struct ieee80211_msg_set_aid_for_sta *) | ||
2964 | skb_put(skb, sizeof(struct ieee80211_msg_set_aid_for_sta)); | ||
2965 | memcpy(msg->sta_address, peer_address, ETH_ALEN); | ||
2966 | msg->aid = aid; | ||
2967 | |||
2968 | ieee80211_rx_mgmt(local, skb, NULL, ieee80211_msg_set_aid_for_sta); | ||
2969 | return 0; | ||
2970 | } | ||
2971 | EXPORT_SYMBOL(ieee80211_set_aid_for_sta); | ||
2972 | 3164 | ||
2973 | static void ap_sta_ps_start(struct net_device *dev, struct sta_info *sta) | 3165 | static void ap_sta_ps_start(struct net_device *dev, struct sta_info *sta) |
2974 | { | 3166 | { |
@@ -4284,6 +4476,9 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, | |||
4284 | struct ieee80211_local *local = hw_to_local(hw); | 4476 | struct ieee80211_local *local = hw_to_local(hw); |
4285 | u16 frag, type; | 4477 | u16 frag, type; |
4286 | u32 msg_type; | 4478 | u32 msg_type; |
4479 | struct ieee80211_tx_status_rtap_hdr *rthdr; | ||
4480 | struct ieee80211_sub_if_data *sdata; | ||
4481 | int monitors; | ||
4287 | 4482 | ||
4288 | if (!status) { | 4483 | if (!status) { |
4289 | printk(KERN_ERR | 4484 | printk(KERN_ERR |
@@ -4395,27 +4590,100 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, | |||
4395 | local->dot11FailedCount++; | 4590 | local->dot11FailedCount++; |
4396 | } | 4591 | } |
4397 | 4592 | ||
4398 | if (!(status->control.flags & IEEE80211_TXCTL_REQ_TX_STATUS) | 4593 | msg_type = (status->flags & IEEE80211_TX_STATUS_ACK) ? |
4399 | || unlikely(!local->apdev)) { | 4594 | ieee80211_msg_tx_callback_ack : ieee80211_msg_tx_callback_fail; |
4595 | |||
4596 | /* this was a transmitted frame, but now we want to reuse it */ | ||
4597 | skb_orphan(skb); | ||
4598 | |||
4599 | if ((status->control.flags & IEEE80211_TXCTL_REQ_TX_STATUS) && | ||
4600 | local->apdev) { | ||
4601 | if (local->monitors) { | ||
4602 | skb2 = skb_clone(skb, GFP_ATOMIC); | ||
4603 | } else { | ||
4604 | skb2 = skb; | ||
4605 | skb = NULL; | ||
4606 | } | ||
4607 | |||
4608 | if (skb2) | ||
4609 | /* Send frame to hostapd */ | ||
4610 | ieee80211_rx_mgmt(local, skb2, NULL, msg_type); | ||
4611 | |||
4612 | if (!skb) | ||
4613 | return; | ||
4614 | } | ||
4615 | |||
4616 | if (!local->monitors) { | ||
4400 | dev_kfree_skb(skb); | 4617 | dev_kfree_skb(skb); |
4401 | return; | 4618 | return; |
4402 | } | 4619 | } |
4403 | 4620 | ||
4404 | msg_type = (status->flags & IEEE80211_TX_STATUS_ACK) ? | 4621 | /* send frame to monitor interfaces now */ |
4405 | ieee80211_msg_tx_callback_ack : ieee80211_msg_tx_callback_fail; | ||
4406 | 4622 | ||
4407 | /* skb was the original skb used for TX. Clone it and give the clone | 4623 | if (skb_headroom(skb) < sizeof(*rthdr)) { |
4408 | * to netif_rx(). Free original skb. */ | 4624 | printk(KERN_ERR "ieee80211_tx_status: headroom too small\n"); |
4409 | skb2 = skb_copy(skb, GFP_ATOMIC); | ||
4410 | if (!skb2) { | ||
4411 | dev_kfree_skb(skb); | 4625 | dev_kfree_skb(skb); |
4412 | return; | 4626 | return; |
4413 | } | 4627 | } |
4414 | dev_kfree_skb(skb); | ||
4415 | skb = skb2; | ||
4416 | 4628 | ||
4417 | /* Send frame to hostapd */ | 4629 | rthdr = (struct ieee80211_tx_status_rtap_hdr*) |
4418 | ieee80211_rx_mgmt(local, skb, NULL, msg_type); | 4630 | skb_push(skb, sizeof(*rthdr)); |
4631 | |||
4632 | memset(rthdr, 0, sizeof(*rthdr)); | ||
4633 | rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr)); | ||
4634 | rthdr->hdr.it_present = | ||
4635 | cpu_to_le32((1 << IEEE80211_RADIOTAP_TX_FLAGS) | | ||
4636 | (1 << IEEE80211_RADIOTAP_DATA_RETRIES)); | ||
4637 | |||
4638 | if (!(status->flags & IEEE80211_TX_STATUS_ACK) && | ||
4639 | !is_multicast_ether_addr(hdr->addr1)) | ||
4640 | rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_FAIL); | ||
4641 | |||
4642 | if ((status->control.flags & IEEE80211_TXCTL_USE_RTS_CTS) && | ||
4643 | (status->control.flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) | ||
4644 | rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_CTS); | ||
4645 | else if (status->control.flags & IEEE80211_TXCTL_USE_RTS_CTS) | ||
4646 | rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_RTS); | ||
4647 | |||
4648 | rthdr->data_retries = status->retry_count; | ||
4649 | |||
4650 | read_lock(&local->sub_if_lock); | ||
4651 | monitors = local->monitors; | ||
4652 | list_for_each_entry(sdata, &local->sub_if_list, list) { | ||
4653 | /* | ||
4654 | * Using the monitors counter is possibly racy, but | ||
4655 | * if the value is wrong we simply either clone the skb | ||
4656 | * once too much or forget sending it to one monitor iface | ||
4657 | * The latter case isn't nice but fixing the race is much | ||
4658 | * more complicated. | ||
4659 | */ | ||
4660 | if (!monitors || !skb) | ||
4661 | goto out; | ||
4662 | |||
4663 | if (sdata->type == IEEE80211_IF_TYPE_MNTR) { | ||
4664 | if (!netif_running(sdata->dev)) | ||
4665 | continue; | ||
4666 | monitors--; | ||
4667 | if (monitors) | ||
4668 | skb2 = skb_clone(skb, GFP_KERNEL); | ||
4669 | else | ||
4670 | skb2 = NULL; | ||
4671 | skb->dev = sdata->dev; | ||
4672 | /* XXX: is this sufficient for BPF? */ | ||
4673 | skb_set_mac_header(skb, 0); | ||
4674 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
4675 | skb->pkt_type = PACKET_OTHERHOST; | ||
4676 | skb->protocol = htons(ETH_P_802_2); | ||
4677 | memset(skb->cb, 0, sizeof(skb->cb)); | ||
4678 | netif_rx(skb); | ||
4679 | skb = skb2; | ||
4680 | break; | ||
4681 | } | ||
4682 | } | ||
4683 | out: | ||
4684 | read_unlock(&local->sub_if_lock); | ||
4685 | if (skb) | ||
4686 | dev_kfree_skb(skb); | ||
4419 | } | 4687 | } |
4420 | EXPORT_SYMBOL(ieee80211_tx_status); | 4688 | EXPORT_SYMBOL(ieee80211_tx_status); |
4421 | 4689 | ||
@@ -4619,6 +4887,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
4619 | ((sizeof(struct ieee80211_local) + | 4887 | ((sizeof(struct ieee80211_local) + |
4620 | NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST); | 4888 | NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST); |
4621 | 4889 | ||
4890 | BUG_ON(!ops->tx); | ||
4891 | BUG_ON(!ops->config); | ||
4892 | BUG_ON(!ops->add_interface); | ||
4622 | local->ops = ops; | 4893 | local->ops = ops; |
4623 | 4894 | ||
4624 | /* for now, mdev needs sub_if_data :/ */ | 4895 | /* for now, mdev needs sub_if_data :/ */ |
@@ -4647,8 +4918,6 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
4647 | local->short_retry_limit = 7; | 4918 | local->short_retry_limit = 7; |
4648 | local->long_retry_limit = 4; | 4919 | local->long_retry_limit = 4; |
4649 | local->hw.conf.radio_enabled = 1; | 4920 | local->hw.conf.radio_enabled = 1; |
4650 | local->rate_ctrl_num_up = RATE_CONTROL_NUM_UP; | ||
4651 | local->rate_ctrl_num_down = RATE_CONTROL_NUM_DOWN; | ||
4652 | 4921 | ||
4653 | local->enabled_modes = (unsigned int) -1; | 4922 | local->enabled_modes = (unsigned int) -1; |
4654 | 4923 | ||
@@ -4712,6 +4981,14 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
4712 | goto fail_workqueue; | 4981 | goto fail_workqueue; |
4713 | } | 4982 | } |
4714 | 4983 | ||
4984 | /* | ||
4985 | * The hardware needs headroom for sending the frame, | ||
4986 | * and we need some headroom for passing the frame to monitor | ||
4987 | * interfaces, but never both at the same time. | ||
4988 | */ | ||
4989 | local->tx_headroom = max(local->hw.extra_tx_headroom, | ||
4990 | sizeof(struct ieee80211_tx_status_rtap_hdr)); | ||
4991 | |||
4715 | debugfs_hw_add(local); | 4992 | debugfs_hw_add(local); |
4716 | 4993 | ||
4717 | local->hw.conf.beacon_int = 1000; | 4994 | local->hw.conf.beacon_int = 1000; |
diff --git a/net/mac80211/ieee80211_common.h b/net/mac80211/ieee80211_common.h index b9a73e7f5f75..77c6afb7f6a8 100644 --- a/net/mac80211/ieee80211_common.h +++ b/net/mac80211/ieee80211_common.h | |||
@@ -47,21 +47,16 @@ enum ieee80211_msg_type { | |||
47 | ieee80211_msg_normal = 0, | 47 | ieee80211_msg_normal = 0, |
48 | ieee80211_msg_tx_callback_ack = 1, | 48 | ieee80211_msg_tx_callback_ack = 1, |
49 | ieee80211_msg_tx_callback_fail = 2, | 49 | ieee80211_msg_tx_callback_fail = 2, |
50 | ieee80211_msg_passive_scan = 3, | 50 | /* hole at 3, was ieee80211_msg_passive_scan but unused */ |
51 | ieee80211_msg_wep_frame_unknown_key = 4, | 51 | ieee80211_msg_wep_frame_unknown_key = 4, |
52 | ieee80211_msg_michael_mic_failure = 5, | 52 | ieee80211_msg_michael_mic_failure = 5, |
53 | /* hole at 6, was monitor but never sent to userspace */ | 53 | /* hole at 6, was monitor but never sent to userspace */ |
54 | ieee80211_msg_sta_not_assoc = 7, | 54 | ieee80211_msg_sta_not_assoc = 7, |
55 | ieee80211_msg_set_aid_for_sta = 8 /* used by Intersil MVC driver */, | 55 | /* 8 was ieee80211_msg_set_aid_for_sta */ |
56 | ieee80211_msg_key_threshold_notification = 9, | 56 | ieee80211_msg_key_threshold_notification = 9, |
57 | ieee80211_msg_radar = 11, | 57 | ieee80211_msg_radar = 11, |
58 | }; | 58 | }; |
59 | 59 | ||
60 | struct ieee80211_msg_set_aid_for_sta { | ||
61 | char sta_address[ETH_ALEN]; | ||
62 | u16 aid; | ||
63 | }; | ||
64 | |||
65 | struct ieee80211_msg_key_notification { | 60 | struct ieee80211_msg_key_notification { |
66 | int tx_rx_count; | 61 | int tx_rx_count; |
67 | char ifname[IFNAMSIZ]; | 62 | char ifname[IFNAMSIZ]; |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index af4d14d0b969..055a2a912185 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -99,6 +99,12 @@ struct ieee80211_sta_bss { | |||
99 | int probe_resp; | 99 | int probe_resp; |
100 | unsigned long last_update; | 100 | unsigned long last_update; |
101 | 101 | ||
102 | /* during assocation, we save an ERP value from a probe response so | ||
103 | * that we can feed ERP info to the driver when handling the | ||
104 | * association completes. these fields probably won't be up-to-date | ||
105 | * otherwise, you probably don't want to use them. */ | ||
106 | int has_erp_value; | ||
107 | u8 erp_value; | ||
102 | }; | 108 | }; |
103 | 109 | ||
104 | 110 | ||
@@ -235,7 +241,6 @@ struct ieee80211_if_sta { | |||
235 | unsigned int authenticated:1; | 241 | unsigned int authenticated:1; |
236 | unsigned int associated:1; | 242 | unsigned int associated:1; |
237 | unsigned int probereq_poll:1; | 243 | unsigned int probereq_poll:1; |
238 | unsigned int use_protection:1; | ||
239 | unsigned int create_ibss:1; | 244 | unsigned int create_ibss:1; |
240 | unsigned int mixed_cell:1; | 245 | unsigned int mixed_cell:1; |
241 | unsigned int wmm_enabled:1; | 246 | unsigned int wmm_enabled:1; |
@@ -278,6 +283,7 @@ struct ieee80211_sub_if_data { | |||
278 | int mc_count; | 283 | int mc_count; |
279 | unsigned int allmulti:1; | 284 | unsigned int allmulti:1; |
280 | unsigned int promisc:1; | 285 | unsigned int promisc:1; |
286 | unsigned int use_protection:1; /* CTS protect ERP frames */ | ||
281 | 287 | ||
282 | struct net_device_stats stats; | 288 | struct net_device_stats stats; |
283 | int drop_unencrypted; | 289 | int drop_unencrypted; |
@@ -392,6 +398,7 @@ struct ieee80211_local { | |||
392 | int monitors; | 398 | int monitors; |
393 | struct iw_statistics wstats; | 399 | struct iw_statistics wstats; |
394 | u8 wstats_flags; | 400 | u8 wstats_flags; |
401 | int tx_headroom; /* required headroom for hardware/radiotap */ | ||
395 | 402 | ||
396 | enum { | 403 | enum { |
397 | IEEE80211_DEV_UNINITIALIZED = 0, | 404 | IEEE80211_DEV_UNINITIALIZED = 0, |
@@ -437,7 +444,6 @@ struct ieee80211_local { | |||
437 | int *basic_rates[NUM_IEEE80211_MODES]; | 444 | int *basic_rates[NUM_IEEE80211_MODES]; |
438 | 445 | ||
439 | int rts_threshold; | 446 | int rts_threshold; |
440 | int cts_protect_erp_frames; | ||
441 | int fragmentation_threshold; | 447 | int fragmentation_threshold; |
442 | int short_retry_limit; /* dot11ShortRetryLimit */ | 448 | int short_retry_limit; /* dot11ShortRetryLimit */ |
443 | int long_retry_limit; /* dot11LongRetryLimit */ | 449 | int long_retry_limit; /* dot11LongRetryLimit */ |
@@ -513,8 +519,6 @@ struct ieee80211_local { | |||
513 | STA_ANTENNA_SEL_SW_CTRL_DEBUG = 2 | 519 | STA_ANTENNA_SEL_SW_CTRL_DEBUG = 2 |
514 | } sta_antenna_sel; | 520 | } sta_antenna_sel; |
515 | 521 | ||
516 | int rate_ctrl_num_up, rate_ctrl_num_down; | ||
517 | |||
518 | #ifdef CONFIG_MAC80211_DEBUG_COUNTERS | 522 | #ifdef CONFIG_MAC80211_DEBUG_COUNTERS |
519 | /* TX/RX handler statistics */ | 523 | /* TX/RX handler statistics */ |
520 | unsigned int tx_handlers_drop; | 524 | unsigned int tx_handlers_drop; |
@@ -719,6 +723,8 @@ void ieee80211_prepare_rates(struct ieee80211_local *local, | |||
719 | struct ieee80211_hw_mode *mode); | 723 | struct ieee80211_hw_mode *mode); |
720 | void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx); | 724 | void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx); |
721 | int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr); | 725 | int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr); |
726 | int ieee80211_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev); | ||
727 | int ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev); | ||
722 | void ieee80211_if_setup(struct net_device *dev); | 728 | void ieee80211_if_setup(struct net_device *dev); |
723 | void ieee80211_if_mgmt_setup(struct net_device *dev); | 729 | void ieee80211_if_mgmt_setup(struct net_device *dev); |
724 | int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local, | 730 | int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local, |
diff --git a/net/mac80211/ieee80211_iface.c b/net/mac80211/ieee80211_iface.c index cf0f32e8c2a2..8532a5ccdd1e 100644 --- a/net/mac80211/ieee80211_iface.c +++ b/net/mac80211/ieee80211_iface.c | |||
@@ -157,6 +157,8 @@ void ieee80211_if_set_type(struct net_device *dev, int type) | |||
157 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 157 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
158 | int oldtype = sdata->type; | 158 | int oldtype = sdata->type; |
159 | 159 | ||
160 | dev->hard_start_xmit = ieee80211_subif_start_xmit; | ||
161 | |||
160 | sdata->type = type; | 162 | sdata->type = type; |
161 | switch (type) { | 163 | switch (type) { |
162 | case IEEE80211_IF_TYPE_WDS: | 164 | case IEEE80211_IF_TYPE_WDS: |
@@ -196,6 +198,7 @@ void ieee80211_if_set_type(struct net_device *dev, int type) | |||
196 | } | 198 | } |
197 | case IEEE80211_IF_TYPE_MNTR: | 199 | case IEEE80211_IF_TYPE_MNTR: |
198 | dev->type = ARPHRD_IEEE80211_RADIOTAP; | 200 | dev->type = ARPHRD_IEEE80211_RADIOTAP; |
201 | dev->hard_start_xmit = ieee80211_monitor_start_xmit; | ||
199 | break; | 202 | break; |
200 | default: | 203 | default: |
201 | printk(KERN_WARNING "%s: %s: Unknown interface type 0x%x", | 204 | printk(KERN_WARNING "%s: %s: Unknown interface type 0x%x", |
diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c index 66e8a976b311..5918dd079e12 100644 --- a/net/mac80211/ieee80211_ioctl.c +++ b/net/mac80211/ieee80211_ioctl.c | |||
@@ -345,6 +345,8 @@ static int ieee80211_ioctl_giwrange(struct net_device *dev, | |||
345 | { | 345 | { |
346 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 346 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
347 | struct iw_range *range = (struct iw_range *) extra; | 347 | struct iw_range *range = (struct iw_range *) extra; |
348 | struct ieee80211_hw_mode *mode = NULL; | ||
349 | int c = 0; | ||
348 | 350 | ||
349 | data->length = sizeof(struct iw_range); | 351 | data->length = sizeof(struct iw_range); |
350 | memset(range, 0, sizeof(struct iw_range)); | 352 | memset(range, 0, sizeof(struct iw_range)); |
@@ -378,6 +380,29 @@ static int ieee80211_ioctl_giwrange(struct net_device *dev, | |||
378 | range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | | 380 | range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | |
379 | IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; | 381 | IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; |
380 | 382 | ||
383 | list_for_each_entry(mode, &local->modes_list, list) { | ||
384 | int i = 0; | ||
385 | |||
386 | if (!(local->enabled_modes & (1 << mode->mode)) || | ||
387 | (local->hw_modes & local->enabled_modes & | ||
388 | (1 << MODE_IEEE80211G) && mode->mode == MODE_IEEE80211B)) | ||
389 | continue; | ||
390 | |||
391 | while (i < mode->num_channels && c < IW_MAX_FREQUENCIES) { | ||
392 | struct ieee80211_channel *chan = &mode->channels[i]; | ||
393 | |||
394 | if (chan->flag & IEEE80211_CHAN_W_SCAN) { | ||
395 | range->freq[c].i = chan->chan; | ||
396 | range->freq[c].m = chan->freq * 100000; | ||
397 | range->freq[c].e = 1; | ||
398 | c++; | ||
399 | } | ||
400 | i++; | ||
401 | } | ||
402 | } | ||
403 | range->num_channels = c; | ||
404 | range->num_frequency = c; | ||
405 | |||
381 | IW_EVENT_CAPA_SET_KERNEL(range->event_capa); | 406 | IW_EVENT_CAPA_SET_KERNEL(range->event_capa); |
382 | IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWTHRSPY); | 407 | IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWTHRSPY); |
383 | IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP); | 408 | IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP); |
@@ -838,6 +863,44 @@ static int ieee80211_ioctl_giwscan(struct net_device *dev, | |||
838 | } | 863 | } |
839 | 864 | ||
840 | 865 | ||
866 | static int ieee80211_ioctl_siwrate(struct net_device *dev, | ||
867 | struct iw_request_info *info, | ||
868 | struct iw_param *rate, char *extra) | ||
869 | { | ||
870 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
871 | struct ieee80211_hw_mode *mode; | ||
872 | int i; | ||
873 | u32 target_rate = rate->value / 100000; | ||
874 | struct ieee80211_sub_if_data *sdata; | ||
875 | |||
876 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
877 | if (!sdata->bss) | ||
878 | return -ENODEV; | ||
879 | mode = local->oper_hw_mode; | ||
880 | /* target_rate = -1, rate->fixed = 0 means auto only, so use all rates | ||
881 | * target_rate = X, rate->fixed = 1 means only rate X | ||
882 | * target_rate = X, rate->fixed = 0 means all rates <= X */ | ||
883 | sdata->bss->max_ratectrl_rateidx = -1; | ||
884 | sdata->bss->force_unicast_rateidx = -1; | ||
885 | if (rate->value < 0) | ||
886 | return 0; | ||
887 | for (i=0; i< mode->num_rates; i++) { | ||
888 | struct ieee80211_rate *rates = &mode->rates[i]; | ||
889 | int this_rate = rates->rate; | ||
890 | |||
891 | if (mode->mode == MODE_ATHEROS_TURBO || | ||
892 | mode->mode == MODE_ATHEROS_TURBOG) | ||
893 | this_rate *= 2; | ||
894 | if (target_rate == this_rate) { | ||
895 | sdata->bss->max_ratectrl_rateidx = i; | ||
896 | if (rate->fixed) | ||
897 | sdata->bss->force_unicast_rateidx = i; | ||
898 | break; | ||
899 | } | ||
900 | } | ||
901 | return 0; | ||
902 | } | ||
903 | |||
841 | static int ieee80211_ioctl_giwrate(struct net_device *dev, | 904 | static int ieee80211_ioctl_giwrate(struct net_device *dev, |
842 | struct iw_request_info *info, | 905 | struct iw_request_info *info, |
843 | struct iw_param *rate, char *extra) | 906 | struct iw_param *rate, char *extra) |
@@ -993,118 +1056,6 @@ static int ieee80211_ioctl_giwretry(struct net_device *dev, | |||
993 | return 0; | 1056 | return 0; |
994 | } | 1057 | } |
995 | 1058 | ||
996 | static int ieee80211_ioctl_clear_keys(struct net_device *dev) | ||
997 | { | ||
998 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
999 | struct ieee80211_key_conf key; | ||
1000 | int i; | ||
1001 | u8 addr[ETH_ALEN]; | ||
1002 | struct ieee80211_key_conf *keyconf; | ||
1003 | struct ieee80211_sub_if_data *sdata; | ||
1004 | struct sta_info *sta; | ||
1005 | |||
1006 | memset(addr, 0xff, ETH_ALEN); | ||
1007 | read_lock(&local->sub_if_lock); | ||
1008 | list_for_each_entry(sdata, &local->sub_if_list, list) { | ||
1009 | for (i = 0; i < NUM_DEFAULT_KEYS; i++) { | ||
1010 | keyconf = NULL; | ||
1011 | if (sdata->keys[i] && | ||
1012 | !sdata->keys[i]->force_sw_encrypt && | ||
1013 | local->ops->set_key && | ||
1014 | (keyconf = ieee80211_key_data2conf(local, | ||
1015 | sdata->keys[i]))) | ||
1016 | local->ops->set_key(local_to_hw(local), | ||
1017 | DISABLE_KEY, addr, | ||
1018 | keyconf, 0); | ||
1019 | kfree(keyconf); | ||
1020 | ieee80211_key_free(sdata->keys[i]); | ||
1021 | sdata->keys[i] = NULL; | ||
1022 | } | ||
1023 | sdata->default_key = NULL; | ||
1024 | } | ||
1025 | read_unlock(&local->sub_if_lock); | ||
1026 | |||
1027 | spin_lock_bh(&local->sta_lock); | ||
1028 | list_for_each_entry(sta, &local->sta_list, list) { | ||
1029 | keyconf = NULL; | ||
1030 | if (sta->key && !sta->key->force_sw_encrypt && | ||
1031 | local->ops->set_key && | ||
1032 | (keyconf = ieee80211_key_data2conf(local, sta->key))) | ||
1033 | local->ops->set_key(local_to_hw(local), DISABLE_KEY, | ||
1034 | sta->addr, keyconf, sta->aid); | ||
1035 | kfree(keyconf); | ||
1036 | ieee80211_key_free(sta->key); | ||
1037 | sta->key = NULL; | ||
1038 | } | ||
1039 | spin_unlock_bh(&local->sta_lock); | ||
1040 | |||
1041 | memset(&key, 0, sizeof(key)); | ||
1042 | if (local->ops->set_key && | ||
1043 | local->ops->set_key(local_to_hw(local), REMOVE_ALL_KEYS, | ||
1044 | NULL, &key, 0)) | ||
1045 | printk(KERN_DEBUG "%s: failed to remove hwaccel keys\n", | ||
1046 | dev->name); | ||
1047 | |||
1048 | return 0; | ||
1049 | } | ||
1050 | |||
1051 | |||
1052 | static int | ||
1053 | ieee80211_ioctl_force_unicast_rate(struct net_device *dev, | ||
1054 | struct ieee80211_sub_if_data *sdata, | ||
1055 | int rate) | ||
1056 | { | ||
1057 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
1058 | struct ieee80211_hw_mode *mode; | ||
1059 | int i; | ||
1060 | |||
1061 | if (sdata->type != IEEE80211_IF_TYPE_AP) | ||
1062 | return -ENOENT; | ||
1063 | |||
1064 | if (rate == 0) { | ||
1065 | sdata->u.ap.force_unicast_rateidx = -1; | ||
1066 | return 0; | ||
1067 | } | ||
1068 | |||
1069 | mode = local->oper_hw_mode; | ||
1070 | for (i = 0; i < mode->num_rates; i++) { | ||
1071 | if (mode->rates[i].rate == rate) { | ||
1072 | sdata->u.ap.force_unicast_rateidx = i; | ||
1073 | return 0; | ||
1074 | } | ||
1075 | } | ||
1076 | return -EINVAL; | ||
1077 | } | ||
1078 | |||
1079 | |||
1080 | static int | ||
1081 | ieee80211_ioctl_max_ratectrl_rate(struct net_device *dev, | ||
1082 | struct ieee80211_sub_if_data *sdata, | ||
1083 | int rate) | ||
1084 | { | ||
1085 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
1086 | struct ieee80211_hw_mode *mode; | ||
1087 | int i; | ||
1088 | |||
1089 | if (sdata->type != IEEE80211_IF_TYPE_AP) | ||
1090 | return -ENOENT; | ||
1091 | |||
1092 | if (rate == 0) { | ||
1093 | sdata->u.ap.max_ratectrl_rateidx = -1; | ||
1094 | return 0; | ||
1095 | } | ||
1096 | |||
1097 | mode = local->oper_hw_mode; | ||
1098 | for (i = 0; i < mode->num_rates; i++) { | ||
1099 | if (mode->rates[i].rate == rate) { | ||
1100 | sdata->u.ap.max_ratectrl_rateidx = i; | ||
1101 | return 0; | ||
1102 | } | ||
1103 | } | ||
1104 | return -EINVAL; | ||
1105 | } | ||
1106 | |||
1107 | |||
1108 | static void ieee80211_key_enable_hwaccel(struct ieee80211_local *local, | 1059 | static void ieee80211_key_enable_hwaccel(struct ieee80211_local *local, |
1109 | struct ieee80211_key *key) | 1060 | struct ieee80211_key *key) |
1110 | { | 1061 | { |
@@ -1228,24 +1179,11 @@ static int ieee80211_ioctl_prism2_param(struct net_device *dev, | |||
1228 | sdata->ieee802_1x = value; | 1179 | sdata->ieee802_1x = value; |
1229 | break; | 1180 | break; |
1230 | 1181 | ||
1231 | case PRISM2_PARAM_ANTSEL_TX: | ||
1232 | local->hw.conf.antenna_sel_tx = value; | ||
1233 | if (ieee80211_hw_config(local)) | ||
1234 | ret = -EINVAL; | ||
1235 | break; | ||
1236 | |||
1237 | case PRISM2_PARAM_ANTSEL_RX: | ||
1238 | local->hw.conf.antenna_sel_rx = value; | ||
1239 | if (ieee80211_hw_config(local)) | ||
1240 | ret = -EINVAL; | ||
1241 | break; | ||
1242 | |||
1243 | case PRISM2_PARAM_CTS_PROTECT_ERP_FRAMES: | 1182 | case PRISM2_PARAM_CTS_PROTECT_ERP_FRAMES: |
1244 | local->cts_protect_erp_frames = value; | 1183 | if (sdata->type != IEEE80211_IF_TYPE_AP) |
1245 | break; | 1184 | ret = -ENOENT; |
1246 | 1185 | else | |
1247 | case PRISM2_PARAM_DROP_UNENCRYPTED: | 1186 | sdata->use_protection = value; |
1248 | sdata->drop_unencrypted = value; | ||
1249 | break; | 1187 | break; |
1250 | 1188 | ||
1251 | case PRISM2_PARAM_PREAMBLE: | 1189 | case PRISM2_PARAM_PREAMBLE: |
@@ -1274,10 +1212,6 @@ static int ieee80211_ioctl_prism2_param(struct net_device *dev, | |||
1274 | local->next_mode = value; | 1212 | local->next_mode = value; |
1275 | break; | 1213 | break; |
1276 | 1214 | ||
1277 | case PRISM2_PARAM_CLEAR_KEYS: | ||
1278 | ret = ieee80211_ioctl_clear_keys(dev); | ||
1279 | break; | ||
1280 | |||
1281 | case PRISM2_PARAM_RADIO_ENABLED: | 1215 | case PRISM2_PARAM_RADIO_ENABLED: |
1282 | ret = ieee80211_ioctl_set_radio_enabled(dev, value); | 1216 | ret = ieee80211_ioctl_set_radio_enabled(dev, value); |
1283 | break; | 1217 | break; |
@@ -1292,22 +1226,6 @@ static int ieee80211_ioctl_prism2_param(struct net_device *dev, | |||
1292 | local->sta_antenna_sel = value; | 1226 | local->sta_antenna_sel = value; |
1293 | break; | 1227 | break; |
1294 | 1228 | ||
1295 | case PRISM2_PARAM_FORCE_UNICAST_RATE: | ||
1296 | ret = ieee80211_ioctl_force_unicast_rate(dev, sdata, value); | ||
1297 | break; | ||
1298 | |||
1299 | case PRISM2_PARAM_MAX_RATECTRL_RATE: | ||
1300 | ret = ieee80211_ioctl_max_ratectrl_rate(dev, sdata, value); | ||
1301 | break; | ||
1302 | |||
1303 | case PRISM2_PARAM_RATE_CTRL_NUM_UP: | ||
1304 | local->rate_ctrl_num_up = value; | ||
1305 | break; | ||
1306 | |||
1307 | case PRISM2_PARAM_RATE_CTRL_NUM_DOWN: | ||
1308 | local->rate_ctrl_num_down = value; | ||
1309 | break; | ||
1310 | |||
1311 | case PRISM2_PARAM_TX_POWER_REDUCTION: | 1229 | case PRISM2_PARAM_TX_POWER_REDUCTION: |
1312 | if (value < 0) | 1230 | if (value < 0) |
1313 | ret = -EINVAL; | 1231 | ret = -EINVAL; |
@@ -1387,20 +1305,8 @@ static int ieee80211_ioctl_get_prism2_param(struct net_device *dev, | |||
1387 | *param = sdata->ieee802_1x; | 1305 | *param = sdata->ieee802_1x; |
1388 | break; | 1306 | break; |
1389 | 1307 | ||
1390 | case PRISM2_PARAM_ANTSEL_TX: | ||
1391 | *param = local->hw.conf.antenna_sel_tx; | ||
1392 | break; | ||
1393 | |||
1394 | case PRISM2_PARAM_ANTSEL_RX: | ||
1395 | *param = local->hw.conf.antenna_sel_rx; | ||
1396 | break; | ||
1397 | |||
1398 | case PRISM2_PARAM_CTS_PROTECT_ERP_FRAMES: | 1308 | case PRISM2_PARAM_CTS_PROTECT_ERP_FRAMES: |
1399 | *param = local->cts_protect_erp_frames; | 1309 | *param = sdata->use_protection; |
1400 | break; | ||
1401 | |||
1402 | case PRISM2_PARAM_DROP_UNENCRYPTED: | ||
1403 | *param = sdata->drop_unencrypted; | ||
1404 | break; | 1310 | break; |
1405 | 1311 | ||
1406 | case PRISM2_PARAM_PREAMBLE: | 1312 | case PRISM2_PARAM_PREAMBLE: |
@@ -1426,14 +1332,6 @@ static int ieee80211_ioctl_get_prism2_param(struct net_device *dev, | |||
1426 | *param = local->sta_antenna_sel; | 1332 | *param = local->sta_antenna_sel; |
1427 | break; | 1333 | break; |
1428 | 1334 | ||
1429 | case PRISM2_PARAM_RATE_CTRL_NUM_UP: | ||
1430 | *param = local->rate_ctrl_num_up; | ||
1431 | break; | ||
1432 | |||
1433 | case PRISM2_PARAM_RATE_CTRL_NUM_DOWN: | ||
1434 | *param = local->rate_ctrl_num_down; | ||
1435 | break; | ||
1436 | |||
1437 | case PRISM2_PARAM_TX_POWER_REDUCTION: | 1335 | case PRISM2_PARAM_TX_POWER_REDUCTION: |
1438 | *param = local->hw.conf.tx_power_reduction; | 1336 | *param = local->hw.conf.tx_power_reduction; |
1439 | break; | 1337 | break; |
@@ -1801,7 +1699,7 @@ static const iw_handler ieee80211_handler[] = | |||
1801 | (iw_handler) NULL, /* SIOCGIWNICKN */ | 1699 | (iw_handler) NULL, /* SIOCGIWNICKN */ |
1802 | (iw_handler) NULL, /* -- hole -- */ | 1700 | (iw_handler) NULL, /* -- hole -- */ |
1803 | (iw_handler) NULL, /* -- hole -- */ | 1701 | (iw_handler) NULL, /* -- hole -- */ |
1804 | (iw_handler) NULL, /* SIOCSIWRATE */ | 1702 | (iw_handler) ieee80211_ioctl_siwrate, /* SIOCSIWRATE */ |
1805 | (iw_handler) ieee80211_ioctl_giwrate, /* SIOCGIWRATE */ | 1703 | (iw_handler) ieee80211_ioctl_giwrate, /* SIOCGIWRATE */ |
1806 | (iw_handler) ieee80211_ioctl_siwrts, /* SIOCSIWRTS */ | 1704 | (iw_handler) ieee80211_ioctl_siwrts, /* SIOCSIWRTS */ |
1807 | (iw_handler) ieee80211_ioctl_giwrts, /* SIOCGIWRTS */ | 1705 | (iw_handler) ieee80211_ioctl_giwrts, /* SIOCGIWRTS */ |
diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index 91b545c144c1..ba2bf8f0a347 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c | |||
@@ -76,33 +76,36 @@ static int ieee80211_sta_config_auth(struct net_device *dev, | |||
76 | 76 | ||
77 | /* Parsed Information Elements */ | 77 | /* Parsed Information Elements */ |
78 | struct ieee802_11_elems { | 78 | struct ieee802_11_elems { |
79 | /* pointers to IEs */ | ||
79 | u8 *ssid; | 80 | u8 *ssid; |
80 | u8 ssid_len; | ||
81 | u8 *supp_rates; | 81 | u8 *supp_rates; |
82 | u8 supp_rates_len; | ||
83 | u8 *fh_params; | 82 | u8 *fh_params; |
84 | u8 fh_params_len; | ||
85 | u8 *ds_params; | 83 | u8 *ds_params; |
86 | u8 ds_params_len; | ||
87 | u8 *cf_params; | 84 | u8 *cf_params; |
88 | u8 cf_params_len; | ||
89 | u8 *tim; | 85 | u8 *tim; |
90 | u8 tim_len; | ||
91 | u8 *ibss_params; | 86 | u8 *ibss_params; |
92 | u8 ibss_params_len; | ||
93 | u8 *challenge; | 87 | u8 *challenge; |
94 | u8 challenge_len; | ||
95 | u8 *wpa; | 88 | u8 *wpa; |
96 | u8 wpa_len; | ||
97 | u8 *rsn; | 89 | u8 *rsn; |
98 | u8 rsn_len; | ||
99 | u8 *erp_info; | 90 | u8 *erp_info; |
100 | u8 erp_info_len; | ||
101 | u8 *ext_supp_rates; | 91 | u8 *ext_supp_rates; |
102 | u8 ext_supp_rates_len; | ||
103 | u8 *wmm_info; | 92 | u8 *wmm_info; |
104 | u8 wmm_info_len; | ||
105 | u8 *wmm_param; | 93 | u8 *wmm_param; |
94 | |||
95 | /* length of them, respectively */ | ||
96 | u8 ssid_len; | ||
97 | u8 supp_rates_len; | ||
98 | u8 fh_params_len; | ||
99 | u8 ds_params_len; | ||
100 | u8 cf_params_len; | ||
101 | u8 tim_len; | ||
102 | u8 ibss_params_len; | ||
103 | u8 challenge_len; | ||
104 | u8 wpa_len; | ||
105 | u8 rsn_len; | ||
106 | u8 erp_info_len; | ||
107 | u8 ext_supp_rates_len; | ||
108 | u8 wmm_info_len; | ||
106 | u8 wmm_param_len; | 109 | u8 wmm_param_len; |
107 | }; | 110 | }; |
108 | 111 | ||
@@ -311,6 +314,25 @@ static void ieee80211_sta_wmm_params(struct net_device *dev, | |||
311 | } | 314 | } |
312 | 315 | ||
313 | 316 | ||
317 | static void ieee80211_handle_erp_ie(struct net_device *dev, u8 erp_value) | ||
318 | { | ||
319 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
320 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | ||
321 | int use_protection = (erp_value & WLAN_ERP_USE_PROTECTION) != 0; | ||
322 | |||
323 | if (use_protection != sdata->use_protection) { | ||
324 | if (net_ratelimit()) { | ||
325 | printk(KERN_DEBUG "%s: CTS protection %s (BSSID=" | ||
326 | MAC_FMT ")\n", | ||
327 | dev->name, | ||
328 | use_protection ? "enabled" : "disabled", | ||
329 | MAC_ARG(ifsta->bssid)); | ||
330 | } | ||
331 | sdata->use_protection = use_protection; | ||
332 | } | ||
333 | } | ||
334 | |||
335 | |||
314 | static void ieee80211_sta_send_associnfo(struct net_device *dev, | 336 | static void ieee80211_sta_send_associnfo(struct net_device *dev, |
315 | struct ieee80211_if_sta *ifsta) | 337 | struct ieee80211_if_sta *ifsta) |
316 | { | 338 | { |
@@ -366,6 +388,7 @@ static void ieee80211_set_associated(struct net_device *dev, | |||
366 | struct ieee80211_if_sta *ifsta, int assoc) | 388 | struct ieee80211_if_sta *ifsta, int assoc) |
367 | { | 389 | { |
368 | union iwreq_data wrqu; | 390 | union iwreq_data wrqu; |
391 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
369 | 392 | ||
370 | if (ifsta->associated == assoc) | 393 | if (ifsta->associated == assoc) |
371 | return; | 394 | return; |
@@ -374,9 +397,18 @@ static void ieee80211_set_associated(struct net_device *dev, | |||
374 | 397 | ||
375 | if (assoc) { | 398 | if (assoc) { |
376 | struct ieee80211_sub_if_data *sdata; | 399 | struct ieee80211_sub_if_data *sdata; |
400 | struct ieee80211_sta_bss *bss; | ||
377 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 401 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
378 | if (sdata->type != IEEE80211_IF_TYPE_STA) | 402 | if (sdata->type != IEEE80211_IF_TYPE_STA) |
379 | return; | 403 | return; |
404 | |||
405 | bss = ieee80211_rx_bss_get(dev, ifsta->bssid); | ||
406 | if (bss) { | ||
407 | if (bss->has_erp_value) | ||
408 | ieee80211_handle_erp_ie(dev, bss->erp_value); | ||
409 | ieee80211_rx_bss_put(dev, bss); | ||
410 | } | ||
411 | |||
380 | netif_carrier_on(dev); | 412 | netif_carrier_on(dev); |
381 | ifsta->prev_bssid_set = 1; | 413 | ifsta->prev_bssid_set = 1; |
382 | memcpy(ifsta->prev_bssid, sdata->u.sta.bssid, ETH_ALEN); | 414 | memcpy(ifsta->prev_bssid, sdata->u.sta.bssid, ETH_ALEN); |
@@ -384,6 +416,7 @@ static void ieee80211_set_associated(struct net_device *dev, | |||
384 | ieee80211_sta_send_associnfo(dev, ifsta); | 416 | ieee80211_sta_send_associnfo(dev, ifsta); |
385 | } else { | 417 | } else { |
386 | netif_carrier_off(dev); | 418 | netif_carrier_off(dev); |
419 | sdata->use_protection = 0; | ||
387 | memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); | 420 | memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); |
388 | } | 421 | } |
389 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | 422 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; |
@@ -1174,6 +1207,18 @@ static void ieee80211_rx_mgmt_assoc_resp(struct net_device *dev, | |||
1174 | return; | 1207 | return; |
1175 | } | 1208 | } |
1176 | 1209 | ||
1210 | /* it probably doesn't, but if the frame includes an ERP value then | ||
1211 | * update our stored copy */ | ||
1212 | if (elems.erp_info && elems.erp_info_len >= 1) { | ||
1213 | struct ieee80211_sta_bss *bss | ||
1214 | = ieee80211_rx_bss_get(dev, ifsta->bssid); | ||
1215 | if (bss) { | ||
1216 | bss->erp_value = elems.erp_info[0]; | ||
1217 | bss->has_erp_value = 1; | ||
1218 | ieee80211_rx_bss_put(dev, bss); | ||
1219 | } | ||
1220 | } | ||
1221 | |||
1177 | printk(KERN_DEBUG "%s: associated\n", dev->name); | 1222 | printk(KERN_DEBUG "%s: associated\n", dev->name); |
1178 | ifsta->aid = aid; | 1223 | ifsta->aid = aid; |
1179 | ifsta->ap_capab = capab_info; | 1224 | ifsta->ap_capab = capab_info; |
@@ -1496,6 +1541,12 @@ static void ieee80211_rx_bss_info(struct net_device *dev, | |||
1496 | return; | 1541 | return; |
1497 | } | 1542 | } |
1498 | 1543 | ||
1544 | /* save the ERP value so that it is available at association time */ | ||
1545 | if (elems.erp_info && elems.erp_info_len >= 1) { | ||
1546 | bss->erp_value = elems.erp_info[0]; | ||
1547 | bss->has_erp_value = 1; | ||
1548 | } | ||
1549 | |||
1499 | bss->beacon_int = le16_to_cpu(mgmt->u.beacon.beacon_int); | 1550 | bss->beacon_int = le16_to_cpu(mgmt->u.beacon.beacon_int); |
1500 | bss->capability = le16_to_cpu(mgmt->u.beacon.capab_info); | 1551 | bss->capability = le16_to_cpu(mgmt->u.beacon.capab_info); |
1501 | if (elems.ssid && elems.ssid_len <= IEEE80211_MAX_SSID_LEN) { | 1552 | if (elems.ssid && elems.ssid_len <= IEEE80211_MAX_SSID_LEN) { |
@@ -1611,10 +1662,8 @@ static void ieee80211_rx_mgmt_beacon(struct net_device *dev, | |||
1611 | size_t len, | 1662 | size_t len, |
1612 | struct ieee80211_rx_status *rx_status) | 1663 | struct ieee80211_rx_status *rx_status) |
1613 | { | 1664 | { |
1614 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
1615 | struct ieee80211_sub_if_data *sdata; | 1665 | struct ieee80211_sub_if_data *sdata; |
1616 | struct ieee80211_if_sta *ifsta; | 1666 | struct ieee80211_if_sta *ifsta; |
1617 | int use_protection; | ||
1618 | size_t baselen; | 1667 | size_t baselen; |
1619 | struct ieee802_11_elems elems; | 1668 | struct ieee802_11_elems elems; |
1620 | 1669 | ||
@@ -1638,23 +1687,8 @@ static void ieee80211_rx_mgmt_beacon(struct net_device *dev, | |||
1638 | &elems) == ParseFailed) | 1687 | &elems) == ParseFailed) |
1639 | return; | 1688 | return; |
1640 | 1689 | ||
1641 | use_protection = 0; | 1690 | if (elems.erp_info && elems.erp_info_len >= 1) |
1642 | if (elems.erp_info && elems.erp_info_len >= 1) { | 1691 | ieee80211_handle_erp_ie(dev, elems.erp_info[0]); |
1643 | use_protection = | ||
1644 | (elems.erp_info[0] & ERP_INFO_USE_PROTECTION) != 0; | ||
1645 | } | ||
1646 | |||
1647 | if (use_protection != !!ifsta->use_protection) { | ||
1648 | if (net_ratelimit()) { | ||
1649 | printk(KERN_DEBUG "%s: CTS protection %s (BSSID=" | ||
1650 | MAC_FMT ")\n", | ||
1651 | dev->name, | ||
1652 | use_protection ? "enabled" : "disabled", | ||
1653 | MAC_ARG(ifsta->bssid)); | ||
1654 | } | ||
1655 | ifsta->use_protection = use_protection ? 1 : 0; | ||
1656 | local->cts_protect_erp_frames = use_protection; | ||
1657 | } | ||
1658 | 1692 | ||
1659 | if (elems.wmm_param && ifsta->wmm_enabled) { | 1693 | if (elems.wmm_param && ifsta->wmm_enabled) { |
1660 | ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param, | 1694 | ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param, |
diff --git a/net/mac80211/rc80211_simple.c b/net/mac80211/rc80211_simple.c index 5ae7fc454665..f6780d63b342 100644 --- a/net/mac80211/rc80211_simple.c +++ b/net/mac80211/rc80211_simple.c | |||
@@ -187,9 +187,13 @@ static void rate_control_simple_tx_status(void *priv, struct net_device *dev, | |||
187 | } | 187 | } |
188 | #endif | 188 | #endif |
189 | 189 | ||
190 | if (per_failed > local->rate_ctrl_num_down) { | 190 | /* |
191 | * XXX: Make these configurable once we have an | ||
192 | * interface to the rate control algorithms | ||
193 | */ | ||
194 | if (per_failed > RATE_CONTROL_NUM_DOWN) { | ||
191 | rate_control_rate_dec(local, sta); | 195 | rate_control_rate_dec(local, sta); |
192 | } else if (per_failed < local->rate_ctrl_num_up) { | 196 | } else if (per_failed < RATE_CONTROL_NUM_UP) { |
193 | rate_control_rate_inc(local, sta); | 197 | rate_control_rate_inc(local, sta); |
194 | } | 198 | } |
195 | srctrl->tx_avg_rate_sum += status->control.rate->rate; | 199 | srctrl->tx_avg_rate_sum += status->control.rate->rate; |
diff --git a/net/wireless/Makefile b/net/wireless/Makefile index 3a96ae60271c..092116e390b6 100644 --- a/net/wireless/Makefile +++ b/net/wireless/Makefile | |||
@@ -1,4 +1,4 @@ | |||
1 | obj-$(CONFIG_WIRELESS_EXT) += wext.o | 1 | obj-$(CONFIG_WIRELESS_EXT) += wext.o |
2 | obj-$(CONFIG_CFG80211) += cfg80211.o | 2 | obj-$(CONFIG_CFG80211) += cfg80211.o |
3 | 3 | ||
4 | cfg80211-y += core.o sysfs.o | 4 | cfg80211-y += core.o sysfs.o radiotap.o |
diff --git a/net/wireless/radiotap.c b/net/wireless/radiotap.c new file mode 100644 index 000000000000..68c11d099917 --- /dev/null +++ b/net/wireless/radiotap.c | |||
@@ -0,0 +1,257 @@ | |||
1 | /* | ||
2 | * Radiotap parser | ||
3 | * | ||
4 | * Copyright 2007 Andy Green <andy@warmcat.com> | ||
5 | */ | ||
6 | |||
7 | #include <net/cfg80211.h> | ||
8 | #include <net/ieee80211_radiotap.h> | ||
9 | #include <asm/unaligned.h> | ||
10 | |||
11 | /* function prototypes and related defs are in include/net/cfg80211.h */ | ||
12 | |||
13 | /** | ||
14 | * ieee80211_radiotap_iterator_init - radiotap parser iterator initialization | ||
15 | * @iterator: radiotap_iterator to initialize | ||
16 | * @radiotap_header: radiotap header to parse | ||
17 | * @max_length: total length we can parse into (eg, whole packet length) | ||
18 | * | ||
19 | * Returns: 0 or a negative error code if there is a problem. | ||
20 | * | ||
21 | * This function initializes an opaque iterator struct which can then | ||
22 | * be passed to ieee80211_radiotap_iterator_next() to visit every radiotap | ||
23 | * argument which is present in the header. It knows about extended | ||
24 | * present headers and handles them. | ||
25 | * | ||
26 | * How to use: | ||
27 | * call __ieee80211_radiotap_iterator_init() to init a semi-opaque iterator | ||
28 | * struct ieee80211_radiotap_iterator (no need to init the struct beforehand) | ||
29 | * checking for a good 0 return code. Then loop calling | ||
30 | * __ieee80211_radiotap_iterator_next()... it returns either 0, | ||
31 | * -ENOENT if there are no more args to parse, or -EINVAL if there is a problem. | ||
32 | * The iterator's @this_arg member points to the start of the argument | ||
33 | * associated with the current argument index that is present, which can be | ||
34 | * found in the iterator's @this_arg_index member. This arg index corresponds | ||
35 | * to the IEEE80211_RADIOTAP_... defines. | ||
36 | * | ||
37 | * Radiotap header length: | ||
38 | * You can find the CPU-endian total radiotap header length in | ||
39 | * iterator->max_length after executing ieee80211_radiotap_iterator_init() | ||
40 | * successfully. | ||
41 | * | ||
42 | * Alignment Gotcha: | ||
43 | * You must take care when dereferencing iterator.this_arg | ||
44 | * for multibyte types... the pointer is not aligned. Use | ||
45 | * get_unaligned((type *)iterator.this_arg) to dereference | ||
46 | * iterator.this_arg for type "type" safely on all arches. | ||
47 | * | ||
48 | * Example code: | ||
49 | * See Documentation/networking/radiotap-headers.txt | ||
50 | */ | ||
51 | |||
52 | int ieee80211_radiotap_iterator_init( | ||
53 | struct ieee80211_radiotap_iterator *iterator, | ||
54 | struct ieee80211_radiotap_header *radiotap_header, | ||
55 | int max_length) | ||
56 | { | ||
57 | /* Linux only supports version 0 radiotap format */ | ||
58 | if (radiotap_header->it_version) | ||
59 | return -EINVAL; | ||
60 | |||
61 | /* sanity check for allowed length and radiotap length field */ | ||
62 | if (max_length < le16_to_cpu(get_unaligned(&radiotap_header->it_len))) | ||
63 | return -EINVAL; | ||
64 | |||
65 | iterator->rtheader = radiotap_header; | ||
66 | iterator->max_length = le16_to_cpu(get_unaligned( | ||
67 | &radiotap_header->it_len)); | ||
68 | iterator->arg_index = 0; | ||
69 | iterator->bitmap_shifter = le32_to_cpu(get_unaligned( | ||
70 | &radiotap_header->it_present)); | ||
71 | iterator->arg = (u8 *)radiotap_header + sizeof(*radiotap_header); | ||
72 | iterator->this_arg = NULL; | ||
73 | |||
74 | /* find payload start allowing for extended bitmap(s) */ | ||
75 | |||
76 | if (unlikely(iterator->bitmap_shifter & (1<<IEEE80211_RADIOTAP_EXT))) { | ||
77 | while (le32_to_cpu(get_unaligned((__le32 *)iterator->arg)) & | ||
78 | (1<<IEEE80211_RADIOTAP_EXT)) { | ||
79 | iterator->arg += sizeof(u32); | ||
80 | |||
81 | /* | ||
82 | * check for insanity where the present bitmaps | ||
83 | * keep claiming to extend up to or even beyond the | ||
84 | * stated radiotap header length | ||
85 | */ | ||
86 | |||
87 | if (((ulong)iterator->arg - | ||
88 | (ulong)iterator->rtheader) > iterator->max_length) | ||
89 | return -EINVAL; | ||
90 | } | ||
91 | |||
92 | iterator->arg += sizeof(u32); | ||
93 | |||
94 | /* | ||
95 | * no need to check again for blowing past stated radiotap | ||
96 | * header length, because ieee80211_radiotap_iterator_next | ||
97 | * checks it before it is dereferenced | ||
98 | */ | ||
99 | } | ||
100 | |||
101 | /* we are all initialized happily */ | ||
102 | |||
103 | return 0; | ||
104 | } | ||
105 | EXPORT_SYMBOL(ieee80211_radiotap_iterator_init); | ||
106 | |||
107 | |||
108 | /** | ||
109 | * ieee80211_radiotap_iterator_next - return next radiotap parser iterator arg | ||
110 | * @iterator: radiotap_iterator to move to next arg (if any) | ||
111 | * | ||
112 | * Returns: 0 if there is an argument to handle, | ||
113 | * -ENOENT if there are no more args or -EINVAL | ||
114 | * if there is something else wrong. | ||
115 | * | ||
116 | * This function provides the next radiotap arg index (IEEE80211_RADIOTAP_*) | ||
117 | * in @this_arg_index and sets @this_arg to point to the | ||
118 | * payload for the field. It takes care of alignment handling and extended | ||
119 | * present fields. @this_arg can be changed by the caller (eg, | ||
120 | * incremented to move inside a compound argument like | ||
121 | * IEEE80211_RADIOTAP_CHANNEL). The args pointed to are in | ||
122 | * little-endian format whatever the endianess of your CPU. | ||
123 | * | ||
124 | * Alignment Gotcha: | ||
125 | * You must take care when dereferencing iterator.this_arg | ||
126 | * for multibyte types... the pointer is not aligned. Use | ||
127 | * get_unaligned((type *)iterator.this_arg) to dereference | ||
128 | * iterator.this_arg for type "type" safely on all arches. | ||
129 | */ | ||
130 | |||
131 | int ieee80211_radiotap_iterator_next( | ||
132 | struct ieee80211_radiotap_iterator *iterator) | ||
133 | { | ||
134 | |||
135 | /* | ||
136 | * small length lookup table for all radiotap types we heard of | ||
137 | * starting from b0 in the bitmap, so we can walk the payload | ||
138 | * area of the radiotap header | ||
139 | * | ||
140 | * There is a requirement to pad args, so that args | ||
141 | * of a given length must begin at a boundary of that length | ||
142 | * -- but note that compound args are allowed (eg, 2 x u16 | ||
143 | * for IEEE80211_RADIOTAP_CHANNEL) so total arg length is not | ||
144 | * a reliable indicator of alignment requirement. | ||
145 | * | ||
146 | * upper nybble: content alignment for arg | ||
147 | * lower nybble: content length for arg | ||
148 | */ | ||
149 | |||
150 | static const u8 rt_sizes[] = { | ||
151 | [IEEE80211_RADIOTAP_TSFT] = 0x88, | ||
152 | [IEEE80211_RADIOTAP_FLAGS] = 0x11, | ||
153 | [IEEE80211_RADIOTAP_RATE] = 0x11, | ||
154 | [IEEE80211_RADIOTAP_CHANNEL] = 0x24, | ||
155 | [IEEE80211_RADIOTAP_FHSS] = 0x22, | ||
156 | [IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = 0x11, | ||
157 | [IEEE80211_RADIOTAP_DBM_ANTNOISE] = 0x11, | ||
158 | [IEEE80211_RADIOTAP_LOCK_QUALITY] = 0x22, | ||
159 | [IEEE80211_RADIOTAP_TX_ATTENUATION] = 0x22, | ||
160 | [IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = 0x22, | ||
161 | [IEEE80211_RADIOTAP_DBM_TX_POWER] = 0x11, | ||
162 | [IEEE80211_RADIOTAP_ANTENNA] = 0x11, | ||
163 | [IEEE80211_RADIOTAP_DB_ANTSIGNAL] = 0x11, | ||
164 | [IEEE80211_RADIOTAP_DB_ANTNOISE] = 0x11 | ||
165 | /* | ||
166 | * add more here as they are defined in | ||
167 | * include/net/ieee80211_radiotap.h | ||
168 | */ | ||
169 | }; | ||
170 | |||
171 | /* | ||
172 | * for every radiotap entry we can at | ||
173 | * least skip (by knowing the length)... | ||
174 | */ | ||
175 | |||
176 | while (iterator->arg_index < sizeof(rt_sizes)) { | ||
177 | int hit = 0; | ||
178 | int pad; | ||
179 | |||
180 | if (!(iterator->bitmap_shifter & 1)) | ||
181 | goto next_entry; /* arg not present */ | ||
182 | |||
183 | /* | ||
184 | * arg is present, account for alignment padding | ||
185 | * 8-bit args can be at any alignment | ||
186 | * 16-bit args must start on 16-bit boundary | ||
187 | * 32-bit args must start on 32-bit boundary | ||
188 | * 64-bit args must start on 64-bit boundary | ||
189 | * | ||
190 | * note that total arg size can differ from alignment of | ||
191 | * elements inside arg, so we use upper nybble of length | ||
192 | * table to base alignment on | ||
193 | * | ||
194 | * also note: these alignments are ** relative to the | ||
195 | * start of the radiotap header **. There is no guarantee | ||
196 | * that the radiotap header itself is aligned on any | ||
197 | * kind of boundary. | ||
198 | * | ||
199 | * the above is why get_unaligned() is used to dereference | ||
200 | * multibyte elements from the radiotap area | ||
201 | */ | ||
202 | |||
203 | pad = (((ulong)iterator->arg) - | ||
204 | ((ulong)iterator->rtheader)) & | ||
205 | ((rt_sizes[iterator->arg_index] >> 4) - 1); | ||
206 | |||
207 | if (pad) | ||
208 | iterator->arg += | ||
209 | (rt_sizes[iterator->arg_index] >> 4) - pad; | ||
210 | |||
211 | /* | ||
212 | * this is what we will return to user, but we need to | ||
213 | * move on first so next call has something fresh to test | ||
214 | */ | ||
215 | iterator->this_arg_index = iterator->arg_index; | ||
216 | iterator->this_arg = iterator->arg; | ||
217 | hit = 1; | ||
218 | |||
219 | /* internally move on the size of this arg */ | ||
220 | iterator->arg += rt_sizes[iterator->arg_index] & 0x0f; | ||
221 | |||
222 | /* | ||
223 | * check for insanity where we are given a bitmap that | ||
224 | * claims to have more arg content than the length of the | ||
225 | * radiotap section. We will normally end up equalling this | ||
226 | * max_length on the last arg, never exceeding it. | ||
227 | */ | ||
228 | |||
229 | if (((ulong)iterator->arg - (ulong)iterator->rtheader) > | ||
230 | iterator->max_length) | ||
231 | return -EINVAL; | ||
232 | |||
233 | next_entry: | ||
234 | iterator->arg_index++; | ||
235 | if (unlikely((iterator->arg_index & 31) == 0)) { | ||
236 | /* completed current u32 bitmap */ | ||
237 | if (iterator->bitmap_shifter & 1) { | ||
238 | /* b31 was set, there is more */ | ||
239 | /* move to next u32 bitmap */ | ||
240 | iterator->bitmap_shifter = le32_to_cpu( | ||
241 | get_unaligned(iterator->next_bitmap)); | ||
242 | iterator->next_bitmap++; | ||
243 | } else | ||
244 | /* no more bitmaps: end */ | ||
245 | iterator->arg_index = sizeof(rt_sizes); | ||
246 | } else /* just try the next bit */ | ||
247 | iterator->bitmap_shifter >>= 1; | ||
248 | |||
249 | /* if we found a valid arg earlier, return it now */ | ||
250 | if (hit) | ||
251 | return 0; | ||
252 | } | ||
253 | |||
254 | /* we don't know how to handle any more args, we're done */ | ||
255 | return -ENOENT; | ||
256 | } | ||
257 | EXPORT_SYMBOL(ieee80211_radiotap_iterator_next); | ||