Commit | Line | Data |
---|---|---|
00b3ed16 GKH |
1 | /* src/p80211/p80211knetdev.c |
2 | * | |
3 | * Linux Kernel net device interface | |
4 | * | |
5 | * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. | |
6 | * -------------------------------------------------------------------- | |
7 | * | |
8 | * linux-wlan | |
9 | * | |
10 | * The contents of this file are subject to the Mozilla Public | |
11 | * License Version 1.1 (the "License"); you may not use this file | |
12 | * except in compliance with the License. You may obtain a copy of | |
13 | * the License at http://www.mozilla.org/MPL/ | |
14 | * | |
15 | * Software distributed under the License is distributed on an "AS | |
16 | * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or | |
17 | * implied. See the License for the specific language governing | |
18 | * rights and limitations under the License. | |
19 | * | |
20 | * Alternatively, the contents of this file may be used under the | |
21 | * terms of the GNU Public License version 2 (the "GPL"), in which | |
22 | * case the provisions of the GPL are applicable instead of the | |
23 | * above. If you wish to allow the use of your version of this file | |
24 | * only under the terms of the GPL and not to allow others to use | |
25 | * your version of this file under the MPL, indicate your decision | |
26 | * by deleting the provisions above and replace them with the notice | |
27 | * and other provisions required by the GPL. If you do not delete | |
28 | * the provisions above, a recipient may use your version of this | |
29 | * file under either the MPL or the GPL. | |
30 | * | |
31 | * -------------------------------------------------------------------- | |
32 | * | |
33 | * Inquiries regarding the linux-wlan Open Source project can be | |
34 | * made directly to: | |
35 | * | |
36 | * AbsoluteValue Systems Inc. | |
37 | * info@linux-wlan.com | |
38 | * http://www.linux-wlan.com | |
39 | * | |
40 | * -------------------------------------------------------------------- | |
41 | * | |
42 | * Portions of the development of this software were funded by | |
43 | * Intersil Corporation as part of PRISM(R) chipset product development. | |
44 | * | |
45 | * -------------------------------------------------------------------- | |
46 | * | |
47 | * The functions required for a Linux network device are defined here. | |
48 | * | |
49 | * -------------------------------------------------------------------- | |
50 | */ | |
51 | ||
00b3ed16 GKH |
52 | #include <linux/module.h> |
53 | #include <linux/kernel.h> | |
54 | #include <linux/sched.h> | |
55 | #include <linux/types.h> | |
56 | #include <linux/skbuff.h> | |
57 | #include <linux/slab.h> | |
58 | #include <linux/proc_fs.h> | |
59 | #include <linux/interrupt.h> | |
60 | #include <linux/netdevice.h> | |
61 | #include <linux/kmod.h> | |
62 | #include <linux/if_arp.h> | |
63 | #include <linux/wireless.h> | |
64 | #include <linux/sockios.h> | |
65 | #include <linux/etherdevice.h> | |
28b17a4b | 66 | #include <linux/if_ether.h> |
ae26230b | 67 | #include <linux/byteorder/generic.h> |
b4b3f0da MM |
68 | #include <linux/bitops.h> |
69 | #include <linux/uaccess.h> | |
00b3ed16 GKH |
70 | #include <asm/byteorder.h> |
71 | ||
72 | #ifdef SIOCETHTOOL | |
73 | #include <linux/ethtool.h> | |
74 | #endif | |
75 | ||
00b3ed16 | 76 | #include <net/iw_handler.h> |
00b3ed16 | 77 | #include <net/net_namespace.h> |
cb3126e6 | 78 | #include <net/cfg80211.h> |
00b3ed16 | 79 | |
00b3ed16 GKH |
80 | #include "p80211types.h" |
81 | #include "p80211hdr.h" | |
82 | #include "p80211conv.h" | |
83 | #include "p80211mgmt.h" | |
84 | #include "p80211msg.h" | |
85 | #include "p80211netdev.h" | |
86 | #include "p80211ioctl.h" | |
87 | #include "p80211req.h" | |
88 | #include "p80211metastruct.h" | |
89 | #include "p80211metadef.h" | |
90 | ||
cb3126e6 KR |
91 | #include "cfg80211.c" |
92 | ||
00b3ed16 | 93 | /* netdevice method functions */ |
297f06ce MT |
94 | static int p80211knetdev_init(netdevice_t *netdev); |
95 | static struct net_device_stats *p80211knetdev_get_stats(netdevice_t *netdev); | |
96 | static int p80211knetdev_open(netdevice_t *netdev); | |
97 | static int p80211knetdev_stop(netdevice_t *netdev); | |
b4b3f0da | 98 | static int p80211knetdev_hard_start_xmit(struct sk_buff *skb, |
297f06ce MT |
99 | netdevice_t *netdev); |
100 | static void p80211knetdev_set_multicast_list(netdevice_t *dev); | |
101 | static int p80211knetdev_do_ioctl(netdevice_t *dev, struct ifreq *ifr, | |
b4b3f0da | 102 | int cmd); |
297f06ce MT |
103 | static int p80211knetdev_set_mac_address(netdevice_t *dev, void *addr); |
104 | static void p80211knetdev_tx_timeout(netdevice_t *netdev); | |
105 | static int p80211_rx_typedrop(wlandevice_t *wlandev, u16 fc); | |
00b3ed16 | 106 | |
e02c69b8 SP |
107 | int wlan_watchdog = 5000; |
108 | module_param(wlan_watchdog, int, 0644); | |
109 | MODULE_PARM_DESC(wlan_watchdog, "transmit timeout in milliseconds"); | |
00b3ed16 | 110 | |
e02c69b8 SP |
111 | int wlan_wext_write = 1; |
112 | module_param(wlan_wext_write, int, 0644); | |
113 | MODULE_PARM_DESC(wlan_wext_write, "enable write wireless extensions"); | |
00b3ed16 | 114 | |
00b3ed16 GKH |
115 | /*---------------------------------------------------------------- |
116 | * p80211knetdev_init | |
117 | * | |
118 | * Init method for a Linux netdevice. Called in response to | |
119 | * register_netdev. | |
120 | * | |
121 | * Arguments: | |
122 | * none | |
123 | * | |
124 | * Returns: | |
125 | * nothing | |
126 | ----------------------------------------------------------------*/ | |
297f06ce | 127 | static int p80211knetdev_init(netdevice_t *netdev) |
00b3ed16 | 128 | { |
00b3ed16 GKH |
129 | /* Called in response to register_netdev */ |
130 | /* This is usually the probe function, but the probe has */ | |
131 | /* already been done by the MSD and the create_kdev */ | |
132 | /* function. All we do here is return success */ | |
00b3ed16 GKH |
133 | return 0; |
134 | } | |
135 | ||
00b3ed16 GKH |
136 | /*---------------------------------------------------------------- |
137 | * p80211knetdev_get_stats | |
138 | * | |
139 | * Statistics retrieval for linux netdevices. Here we're reporting | |
140 | * the Linux i/f level statistics. Hence, for the primary numbers, | |
141 | * we don't want to report the numbers from the MIB. Eventually, | |
142 | * it might be useful to collect some of the error counters though. | |
143 | * | |
144 | * Arguments: | |
145 | * netdev Linux netdevice | |
146 | * | |
147 | * Returns: | |
148 | * the address of the statistics structure | |
149 | ----------------------------------------------------------------*/ | |
aa8c2a03 | 150 | static struct net_device_stats *p80211knetdev_get_stats(netdevice_t *netdev) |
00b3ed16 | 151 | { |
b4b3f0da | 152 | wlandevice_t *wlandev = netdev->ml_priv; |
00b3ed16 GKH |
153 | |
154 | /* TODO: review the MIB stats for items that correspond to | |
b4b3f0da | 155 | linux stats */ |
00b3ed16 | 156 | |
00b3ed16 GKH |
157 | return &(wlandev->linux_stats); |
158 | } | |
159 | ||
00b3ed16 GKH |
160 | /*---------------------------------------------------------------- |
161 | * p80211knetdev_open | |
162 | * | |
163 | * Linux netdevice open method. Following a successful call here, | |
164 | * the device is supposed to be ready for tx and rx. In our | |
165 | * situation that may not be entirely true due to the state of the | |
166 | * MAC below. | |
167 | * | |
168 | * Arguments: | |
169 | * netdev Linux network device structure | |
170 | * | |
171 | * Returns: | |
172 | * zero on success, non-zero otherwise | |
173 | ----------------------------------------------------------------*/ | |
297f06ce | 174 | static int p80211knetdev_open(netdevice_t *netdev) |
00b3ed16 | 175 | { |
b4b3f0da MM |
176 | int result = 0; /* success */ |
177 | wlandevice_t *wlandev = netdev->ml_priv; | |
00b3ed16 | 178 | |
00b3ed16 | 179 | /* Check to make sure the MSD is running */ |
b4b3f0da | 180 | if (wlandev->msdstate != WLAN_MSD_RUNNING) |
00b3ed16 | 181 | return -ENODEV; |
00b3ed16 GKH |
182 | |
183 | /* Tell the MSD to open */ | |
b4b3f0da | 184 | if (wlandev->open != NULL) { |
00b3ed16 | 185 | result = wlandev->open(wlandev); |
b4b3f0da | 186 | if (result == 0) { |
cbec30c4 | 187 | netif_start_queue(wlandev->netdev); |
00b3ed16 GKH |
188 | wlandev->state = WLAN_DEVICE_OPEN; |
189 | } | |
190 | } else { | |
191 | result = -EAGAIN; | |
192 | } | |
193 | ||
00b3ed16 GKH |
194 | return result; |
195 | } | |
196 | ||
00b3ed16 GKH |
197 | /*---------------------------------------------------------------- |
198 | * p80211knetdev_stop | |
199 | * | |
200 | * Linux netdevice stop (close) method. Following this call, | |
201 | * no frames should go up or down through this interface. | |
202 | * | |
203 | * Arguments: | |
204 | * netdev Linux network device structure | |
205 | * | |
206 | * Returns: | |
207 | * zero on success, non-zero otherwise | |
208 | ----------------------------------------------------------------*/ | |
297f06ce | 209 | static int p80211knetdev_stop(netdevice_t *netdev) |
00b3ed16 | 210 | { |
b4b3f0da MM |
211 | int result = 0; |
212 | wlandevice_t *wlandev = netdev->ml_priv; | |
00b3ed16 | 213 | |
b4b3f0da | 214 | if (wlandev->close != NULL) |
00b3ed16 | 215 | result = wlandev->close(wlandev); |
00b3ed16 | 216 | |
cbec30c4 | 217 | netif_stop_queue(wlandev->netdev); |
00b3ed16 GKH |
218 | wlandev->state = WLAN_DEVICE_CLOSED; |
219 | ||
00b3ed16 GKH |
220 | return result; |
221 | } | |
222 | ||
223 | /*---------------------------------------------------------------- | |
224 | * p80211netdev_rx | |
225 | * | |
226 | * Frame receive function called by the mac specific driver. | |
227 | * | |
228 | * Arguments: | |
229 | * wlandev WLAN network device structure | |
230 | * skb skbuff containing a full 802.11 frame. | |
231 | * Returns: | |
232 | * nothing | |
233 | * Side effects: | |
234 | * | |
235 | ----------------------------------------------------------------*/ | |
297f06ce | 236 | void p80211netdev_rx(wlandevice_t *wlandev, struct sk_buff *skb) |
00b3ed16 | 237 | { |
00b3ed16 GKH |
238 | /* Enqueue for post-irq processing */ |
239 | skb_queue_tail(&wlandev->nsd_rxq, skb); | |
00b3ed16 | 240 | tasklet_schedule(&wlandev->rx_bh); |
00b3ed16 GKH |
241 | } |
242 | ||
ccc3a598 DP |
243 | #define CONV_TO_ETHER_SKIPPED 0x01 |
244 | #define CONV_TO_ETHER_FAILED 0x02 | |
245 | ||
246 | /** | |
ae4af9ad | 247 | * p80211_convert_to_ether - conversion from 802.11 frame to ethernet frame |
ccc3a598 DP |
248 | * @wlandev: pointer to WLAN device |
249 | * @skb: pointer to socket buffer | |
250 | * | |
251 | * Returns: 0 if conversion succeeded | |
252 | * CONV_TO_ETHER_FAILED if conversion failed | |
253 | * CONV_TO_ETHER_SKIPPED if frame is ignored | |
254 | */ | |
ae4af9ad | 255 | static int p80211_convert_to_ether(wlandevice_t *wlandev, struct sk_buff *skb) |
ccc3a598 DP |
256 | { |
257 | struct p80211_hdr_a3 *hdr; | |
258 | ||
259 | hdr = (struct p80211_hdr_a3 *) skb->data; | |
260 | if (p80211_rx_typedrop(wlandev, hdr->fc)) | |
261 | return CONV_TO_ETHER_SKIPPED; | |
262 | ||
95c9668d DP |
263 | /* perform mcast filtering: allow my local address through but reject |
264 | * anything else that isn't multicast | |
265 | */ | |
ccc3a598 | 266 | if (wlandev->netdev->flags & IFF_ALLMULTI) { |
9b3ac7a8 DP |
267 | if (!ether_addr_equal_unaligned(wlandev->netdev->dev_addr, |
268 | hdr->a1)) { | |
02b3b53a | 269 | if (!is_multicast_ether_addr(hdr->a1)) |
ccc3a598 DP |
270 | return CONV_TO_ETHER_SKIPPED; |
271 | } | |
272 | } | |
273 | ||
274 | if (skb_p80211_to_ether(wlandev, wlandev->ethconv, skb) == 0) { | |
275 | skb->dev->last_rx = jiffies; | |
276 | wlandev->linux_stats.rx_packets++; | |
277 | wlandev->linux_stats.rx_bytes += skb->len; | |
278 | netif_rx_ni(skb); | |
279 | return 0; | |
280 | } | |
281 | ||
79f9e634 | 282 | netdev_dbg(wlandev->netdev, "p80211_convert_to_ether failed.\n"); |
ccc3a598 DP |
283 | return CONV_TO_ETHER_FAILED; |
284 | } | |
285 | ||
67c4ded5 DP |
286 | /** |
287 | * p80211netdev_rx_bh - deferred processing of all received frames | |
288 | * | |
289 | * @arg: pointer to WLAN network device structure (cast to unsigned long) | |
290 | */ | |
00b3ed16 GKH |
291 | static void p80211netdev_rx_bh(unsigned long arg) |
292 | { | |
293 | wlandevice_t *wlandev = (wlandevice_t *) arg; | |
294 | struct sk_buff *skb = NULL; | |
b4b3f0da | 295 | netdevice_t *dev = wlandev->netdev; |
00b3ed16 | 296 | |
00b3ed16 | 297 | /* Let's empty our our queue */ |
b4b3f0da | 298 | while ((skb = skb_dequeue(&wlandev->nsd_rxq))) { |
00b3ed16 GKH |
299 | if (wlandev->state == WLAN_DEVICE_OPEN) { |
300 | ||
301 | if (dev->type != ARPHRD_ETHER) { | |
302 | /* RAW frame; we shouldn't convert it */ | |
b4b3f0da | 303 | /* XXX Append the Prism Header here instead. */ |
00b3ed16 GKH |
304 | |
305 | /* set up various data fields */ | |
306 | skb->dev = dev; | |
307 | skb_reset_mac_header(skb); | |
308 | skb->ip_summed = CHECKSUM_NONE; | |
309 | skb->pkt_type = PACKET_OTHERHOST; | |
310 | skb->protocol = htons(ETH_P_80211_RAW); | |
311 | dev->last_rx = jiffies; | |
312 | ||
313 | wlandev->linux_stats.rx_packets++; | |
314 | wlandev->linux_stats.rx_bytes += skb->len; | |
315 | netif_rx_ni(skb); | |
316 | continue; | |
317 | } else { | |
ae4af9ad | 318 | if (!p80211_convert_to_ether(wlandev, skb)) |
00b3ed16 | 319 | continue; |
00b3ed16 GKH |
320 | } |
321 | } | |
322 | dev_kfree_skb(skb); | |
323 | } | |
00b3ed16 GKH |
324 | } |
325 | ||
00b3ed16 GKH |
326 | /*---------------------------------------------------------------- |
327 | * p80211knetdev_hard_start_xmit | |
328 | * | |
329 | * Linux netdevice method for transmitting a frame. | |
330 | * | |
331 | * Arguments: | |
332 | * skb Linux sk_buff containing the frame. | |
333 | * netdev Linux netdevice. | |
334 | * | |
335 | * Side effects: | |
336 | * If the lower layers report that buffers are full. netdev->tbusy | |
337 | * will be set to prevent higher layers from sending more traffic. | |
338 | * | |
339 | * Note: If this function returns non-zero, higher layers retain | |
340 | * ownership of the skb. | |
341 | * | |
342 | * Returns: | |
343 | * zero on success, non-zero on failure. | |
344 | ----------------------------------------------------------------*/ | |
b4b3f0da | 345 | static int p80211knetdev_hard_start_xmit(struct sk_buff *skb, |
297f06ce | 346 | netdevice_t *netdev) |
00b3ed16 | 347 | { |
b4b3f0da MM |
348 | int result = 0; |
349 | int txresult = -1; | |
350 | wlandevice_t *wlandev = netdev->ml_priv; | |
93df38e5 | 351 | union p80211_hdr p80211_hdr; |
51e4896a | 352 | struct p80211_metawep p80211_wep; |
00b3ed16 | 353 | |
fae7e4d3 PH |
354 | p80211_wep.data = NULL; |
355 | ||
b4b3f0da | 356 | if (skb == NULL) |
ec634fe3 | 357 | return NETDEV_TX_OK; |
00b3ed16 | 358 | |
b4b3f0da | 359 | if (wlandev->state != WLAN_DEVICE_OPEN) { |
00b3ed16 GKH |
360 | result = 1; |
361 | goto failed; | |
362 | } | |
363 | ||
93df38e5 | 364 | memset(&p80211_hdr, 0, sizeof(union p80211_hdr)); |
51e4896a | 365 | memset(&p80211_wep, 0, sizeof(struct p80211_metawep)); |
00b3ed16 | 366 | |
b4b3f0da | 367 | if (netif_queue_stopped(netdev)) { |
79f9e634 | 368 | netdev_dbg(netdev, "called when queue stopped.\n"); |
00b3ed16 GKH |
369 | result = 1; |
370 | goto failed; | |
371 | } | |
372 | ||
373 | netif_stop_queue(netdev); | |
374 | ||
00b3ed16 | 375 | /* Check to see that a valid mode is set */ |
b4b3f0da | 376 | switch (wlandev->macmode) { |
00b3ed16 GKH |
377 | case WLAN_MACMODE_IBSS_STA: |
378 | case WLAN_MACMODE_ESS_STA: | |
379 | case WLAN_MACMODE_ESS_AP: | |
380 | break; | |
381 | default: | |
382 | /* Mode isn't set yet, just drop the frame | |
383 | * and return success . | |
384 | * TODO: we need a saner way to handle this | |
385 | */ | |
b4b3f0da | 386 | if (skb->protocol != ETH_P_80211_RAW) { |
cbec30c4 | 387 | netif_start_queue(wlandev->netdev); |
79f9e634 | 388 | netdev_notice(netdev, "Tx attempt prior to association, frame dropped.\n"); |
00b3ed16 GKH |
389 | wlandev->linux_stats.tx_dropped++; |
390 | result = 0; | |
391 | goto failed; | |
392 | } | |
393 | break; | |
394 | } | |
395 | ||
396 | /* Check for raw transmits */ | |
b4b3f0da | 397 | if (skb->protocol == ETH_P_80211_RAW) { |
00b3ed16 GKH |
398 | if (!capable(CAP_NET_ADMIN)) { |
399 | result = 1; | |
400 | goto failed; | |
401 | } | |
402 | /* move the header over */ | |
93df38e5 EH |
403 | memcpy(&p80211_hdr, skb->data, sizeof(union p80211_hdr)); |
404 | skb_pull(skb, sizeof(union p80211_hdr)); | |
00b3ed16 | 405 | } else { |
b4b3f0da MM |
406 | if (skb_ether_to_p80211 |
407 | (wlandev, wlandev->ethconv, skb, &p80211_hdr, | |
408 | &p80211_wep) != 0) { | |
00b3ed16 | 409 | /* convert failed */ |
79f9e634 DP |
410 | netdev_dbg(netdev, "ether_to_80211(%d) failed.\n", |
411 | wlandev->ethconv); | |
00b3ed16 GKH |
412 | result = 1; |
413 | goto failed; | |
414 | } | |
415 | } | |
b4b3f0da | 416 | if (wlandev->txframe == NULL) { |
00b3ed16 GKH |
417 | result = 1; |
418 | goto failed; | |
419 | } | |
420 | ||
421 | netdev->trans_start = jiffies; | |
422 | ||
423 | wlandev->linux_stats.tx_packets++; | |
424 | /* count only the packet payload */ | |
425 | wlandev->linux_stats.tx_bytes += skb->len; | |
426 | ||
427 | txresult = wlandev->txframe(wlandev, skb, &p80211_hdr, &p80211_wep); | |
428 | ||
b4b3f0da | 429 | if (txresult == 0) { |
00b3ed16 GKH |
430 | /* success and more buf */ |
431 | /* avail, re: hw_txdata */ | |
cbec30c4 | 432 | netif_wake_queue(wlandev->netdev); |
5b548140 | 433 | result = NETDEV_TX_OK; |
b4b3f0da | 434 | } else if (txresult == 1) { |
00b3ed16 | 435 | /* success, no more avail */ |
79f9e634 | 436 | netdev_dbg(netdev, "txframe success, no more bufs\n"); |
00b3ed16 GKH |
437 | /* netdev->tbusy = 1; don't set here, irqhdlr */ |
438 | /* may have already cleared it */ | |
5b548140 | 439 | result = NETDEV_TX_OK; |
b4b3f0da | 440 | } else if (txresult == 2) { |
00b3ed16 | 441 | /* alloc failure, drop frame */ |
79f9e634 | 442 | netdev_dbg(netdev, "txframe returned alloc_fail\n"); |
5b548140 | 443 | result = NETDEV_TX_BUSY; |
00b3ed16 GKH |
444 | } else { |
445 | /* buffer full or queue busy, drop frame. */ | |
79f9e634 | 446 | netdev_dbg(netdev, "txframe returned full or busy\n"); |
5b548140 | 447 | result = NETDEV_TX_BUSY; |
00b3ed16 GKH |
448 | } |
449 | ||
b4b3f0da | 450 | failed: |
00b3ed16 GKH |
451 | /* Free up the WEP buffer if it's not the same as the skb */ |
452 | if ((p80211_wep.data) && (p80211_wep.data != skb->data)) | |
2f585191 | 453 | kzfree(p80211_wep.data); |
00b3ed16 GKH |
454 | |
455 | /* we always free the skb here, never in a lower level. */ | |
456 | if (!result) | |
457 | dev_kfree_skb(skb); | |
458 | ||
00b3ed16 GKH |
459 | return result; |
460 | } | |
461 | ||
00b3ed16 GKH |
462 | /*---------------------------------------------------------------- |
463 | * p80211knetdev_set_multicast_list | |
464 | * | |
d34602de | 465 | * Called from higher layers whenever there's a need to set/clear |
00b3ed16 GKH |
466 | * promiscuous mode or rewrite the multicast list. |
467 | * | |
468 | * Arguments: | |
469 | * none | |
470 | * | |
471 | * Returns: | |
472 | * nothing | |
473 | ----------------------------------------------------------------*/ | |
297f06ce | 474 | static void p80211knetdev_set_multicast_list(netdevice_t *dev) |
00b3ed16 | 475 | { |
b4b3f0da | 476 | wlandevice_t *wlandev = dev->ml_priv; |
00b3ed16 | 477 | |
00b3ed16 GKH |
478 | /* TODO: real multicast support as well */ |
479 | ||
480 | if (wlandev->set_multicast_list) | |
481 | wlandev->set_multicast_list(wlandev, dev); | |
482 | ||
00b3ed16 GKH |
483 | } |
484 | ||
485 | #ifdef SIOCETHTOOL | |
486 | ||
297f06ce | 487 | static int p80211netdev_ethtool(wlandevice_t *wlandev, void __user *useraddr) |
00b3ed16 | 488 | { |
aaad4303 | 489 | u32 ethcmd; |
00b3ed16 GKH |
490 | struct ethtool_drvinfo info; |
491 | struct ethtool_value edata; | |
492 | ||
493 | memset(&info, 0, sizeof(info)); | |
494 | memset(&edata, 0, sizeof(edata)); | |
495 | ||
496 | if (copy_from_user(ðcmd, useraddr, sizeof(ethcmd))) | |
497 | return -EFAULT; | |
498 | ||
499 | switch (ethcmd) { | |
500 | case ETHTOOL_GDRVINFO: | |
501 | info.cmd = ethcmd; | |
502 | snprintf(info.driver, sizeof(info.driver), "p80211_%s", | |
503 | wlandev->nsdname); | |
504 | snprintf(info.version, sizeof(info.version), "%s", | |
505 | WLAN_RELEASE); | |
506 | ||
00b3ed16 GKH |
507 | if (copy_to_user(useraddr, &info, sizeof(info))) |
508 | return -EFAULT; | |
509 | return 0; | |
510 | #ifdef ETHTOOL_GLINK | |
511 | case ETHTOOL_GLINK: | |
512 | edata.cmd = ethcmd; | |
513 | ||
514 | if (wlandev->linkstatus && | |
515 | (wlandev->macmode != WLAN_MACMODE_NONE)) { | |
516 | edata.data = 1; | |
517 | } else { | |
518 | edata.data = 0; | |
519 | } | |
520 | ||
521 | if (copy_to_user(useraddr, &edata, sizeof(edata))) | |
b4b3f0da | 522 | return -EFAULT; |
00b3ed16 | 523 | return 0; |
00b3ed16 | 524 | #endif |
c3444e50 | 525 | } |
00b3ed16 GKH |
526 | |
527 | return -EOPNOTSUPP; | |
528 | } | |
529 | ||
530 | #endif | |
531 | ||
532 | /*---------------------------------------------------------------- | |
533 | * p80211knetdev_do_ioctl | |
534 | * | |
535 | * Handle an ioctl call on one of our devices. Everything Linux | |
536 | * ioctl specific is done here. Then we pass the contents of the | |
537 | * ifr->data to the request message handler. | |
538 | * | |
539 | * Arguments: | |
540 | * dev Linux kernel netdevice | |
541 | * ifr Our private ioctl request structure, typed for the | |
542 | * generic struct ifreq so we can use ptr to func | |
543 | * w/o cast. | |
544 | * | |
545 | * Returns: | |
546 | * zero on success, a negative errno on failure. Possible values: | |
547 | * -ENETDOWN Device isn't up. | |
548 | * -EBUSY cmd already in progress | |
549 | * -ETIME p80211 cmd timed out (MSD may have its own timers) | |
550 | * -EFAULT memory fault copying msg from user buffer | |
551 | * -ENOMEM unable to allocate kernel msg buffer | |
552 | * -ENOSYS bad magic, it the cmd really for us? | |
aaad4303 | 553 | * -EintR sleeping on cmd, awakened by signal, cmd cancelled. |
00b3ed16 GKH |
554 | * |
555 | * Call Context: | |
556 | * Process thread (ioctl caller). TODO: SMP support may require | |
557 | * locks. | |
558 | ----------------------------------------------------------------*/ | |
297f06ce | 559 | static int p80211knetdev_do_ioctl(netdevice_t *dev, struct ifreq *ifr, int cmd) |
00b3ed16 | 560 | { |
b4b3f0da | 561 | int result = 0; |
e5bdbb90 | 562 | struct p80211ioctl_req *req = (struct p80211ioctl_req *) ifr; |
b4b3f0da MM |
563 | wlandevice_t *wlandev = dev->ml_priv; |
564 | u8 *msgbuf; | |
00b3ed16 | 565 | |
79f9e634 | 566 | netdev_dbg(dev, "rx'd ioctl, cmd=%d, len=%d\n", cmd, req->len); |
00b3ed16 | 567 | |
00b3ed16 GKH |
568 | #ifdef SIOCETHTOOL |
569 | if (cmd == SIOCETHTOOL) { | |
b4b3f0da MM |
570 | result = |
571 | p80211netdev_ethtool(wlandev, (void __user *)ifr->ifr_data); | |
00b3ed16 GKH |
572 | goto bail; |
573 | } | |
574 | #endif | |
575 | ||
576 | /* Test the magic, assume ifr is good if it's there */ | |
b4b3f0da | 577 | if (req->magic != P80211_IOCTL_MAGIC) { |
00b3ed16 GKH |
578 | result = -ENOSYS; |
579 | goto bail; | |
580 | } | |
581 | ||
b4b3f0da | 582 | if (cmd == P80211_IFTEST) { |
00b3ed16 GKH |
583 | result = 0; |
584 | goto bail; | |
b4b3f0da | 585 | } else if (cmd != P80211_IFREQ) { |
00b3ed16 GKH |
586 | result = -ENOSYS; |
587 | goto bail; | |
588 | } | |
589 | ||
590 | /* Allocate a buf of size req->len */ | |
5dd8acc8 SK |
591 | msgbuf = kmalloc(req->len, GFP_KERNEL); |
592 | if (msgbuf) { | |
b4b3f0da | 593 | if (copy_from_user(msgbuf, (void __user *)req->data, req->len)) |
00b3ed16 | 594 | result = -EFAULT; |
b4b3f0da MM |
595 | else |
596 | result = p80211req_dorequest(wlandev, msgbuf); | |
00b3ed16 | 597 | |
b4b3f0da MM |
598 | if (result == 0) { |
599 | if (copy_to_user | |
600 | ((void __user *)req->data, msgbuf, req->len)) { | |
00b3ed16 GKH |
601 | result = -EFAULT; |
602 | } | |
603 | } | |
604 | kfree(msgbuf); | |
605 | } else { | |
606 | result = -ENOMEM; | |
607 | } | |
608 | bail: | |
b6bb56e6 EH |
609 | /* If allocate,copyfrom or copyto fails, return errno */ |
610 | return result; | |
00b3ed16 GKH |
611 | } |
612 | ||
613 | /*---------------------------------------------------------------- | |
614 | * p80211knetdev_set_mac_address | |
615 | * | |
616 | * Handles the ioctl for changing the MACAddress of a netdevice | |
617 | * | |
618 | * references: linux/netdevice.h and drivers/net/net_init.c | |
619 | * | |
620 | * NOTE: [MSM] We only prevent address changes when the netdev is | |
621 | * up. We don't control anything based on dot11 state. If the | |
622 | * address is changed on a STA that's currently associated, you | |
623 | * will probably lose the ability to send and receive data frames. | |
624 | * Just be aware. Therefore, this should usually only be done | |
625 | * prior to scan/join/auth/assoc. | |
626 | * | |
627 | * Arguments: | |
628 | * dev netdevice struct | |
629 | * addr the new MACAddress (a struct) | |
630 | * | |
631 | * Returns: | |
632 | * zero on success, a negative errno on failure. Possible values: | |
633 | * -EBUSY device is bussy (cmd not possible) | |
634 | * -and errors returned by: p80211req_dorequest(..) | |
635 | * | |
636 | * by: Collin R. Mulliner <collin@mulliner.org> | |
637 | ----------------------------------------------------------------*/ | |
297f06ce | 638 | static int p80211knetdev_set_mac_address(netdevice_t *dev, void *addr) |
00b3ed16 | 639 | { |
b4b3f0da | 640 | struct sockaddr *new_addr = addr; |
b6bb56e6 | 641 | struct p80211msg_dot11req_mibset dot11req; |
b4b3f0da MM |
642 | p80211item_unk392_t *mibattr; |
643 | p80211item_pstr6_t *macaddr; | |
644 | p80211item_uint32_t *resultcode; | |
909ff710 | 645 | int result; |
00b3ed16 | 646 | |
00b3ed16 | 647 | /* If we're running, we don't allow MAC address changes */ |
b4b3f0da | 648 | if (netif_running(dev)) |
00b3ed16 | 649 | return -EBUSY; |
00b3ed16 GKH |
650 | |
651 | /* Set up some convenience pointers. */ | |
652 | mibattr = &dot11req.mibattribute; | |
5dd8acc8 | 653 | macaddr = (p80211item_pstr6_t *) &mibattr->data; |
00b3ed16 GKH |
654 | resultcode = &dot11req.resultcode; |
655 | ||
656 | /* Set up a dot11req_mibset */ | |
b6bb56e6 | 657 | memset(&dot11req, 0, sizeof(struct p80211msg_dot11req_mibset)); |
00b3ed16 | 658 | dot11req.msgcode = DIDmsg_dot11req_mibset; |
b6bb56e6 | 659 | dot11req.msglen = sizeof(struct p80211msg_dot11req_mibset); |
00b3ed16 | 660 | memcpy(dot11req.devname, |
b4b3f0da | 661 | ((wlandevice_t *) dev->ml_priv)->name, WLAN_DEVNAMELEN_MAX - 1); |
00b3ed16 GKH |
662 | |
663 | /* Set up the mibattribute argument */ | |
664 | mibattr->did = DIDmsg_dot11req_mibset_mibattribute; | |
665 | mibattr->status = P80211ENUM_msgitem_status_data_ok; | |
666 | mibattr->len = sizeof(mibattr->data); | |
667 | ||
668 | macaddr->did = DIDmib_dot11mac_dot11OperationTable_dot11MACAddress; | |
669 | macaddr->status = P80211ENUM_msgitem_status_data_ok; | |
670 | macaddr->len = sizeof(macaddr->data); | |
28b17a4b MM |
671 | macaddr->data.len = ETH_ALEN; |
672 | memcpy(&macaddr->data.data, new_addr->sa_data, ETH_ALEN); | |
00b3ed16 GKH |
673 | |
674 | /* Set up the resultcode argument */ | |
675 | resultcode->did = DIDmsg_dot11req_mibset_resultcode; | |
676 | resultcode->status = P80211ENUM_msgitem_status_no_value; | |
677 | resultcode->len = sizeof(resultcode->data); | |
678 | resultcode->data = 0; | |
679 | ||
680 | /* now fire the request */ | |
5dd8acc8 | 681 | result = p80211req_dorequest(dev->ml_priv, (u8 *) &dot11req); |
00b3ed16 GKH |
682 | |
683 | /* If the request wasn't successful, report an error and don't | |
684 | * change the netdev address | |
685 | */ | |
b4b3f0da | 686 | if (result != 0 || resultcode->data != P80211ENUM_resultcode_success) { |
79f9e634 | 687 | netdev_err(dev, "Low-level driver failed dot11req_mibset(dot11MACAddress).\n"); |
00b3ed16 GKH |
688 | result = -EADDRNOTAVAIL; |
689 | } else { | |
690 | /* everything's ok, change the addr in netdev */ | |
691 | memcpy(dev->dev_addr, new_addr->sa_data, dev->addr_len); | |
692 | } | |
693 | ||
00b3ed16 GKH |
694 | return result; |
695 | } | |
696 | ||
297f06ce | 697 | static int wlan_change_mtu(netdevice_t *dev, int new_mtu) |
00b3ed16 | 698 | { |
b4b3f0da MM |
699 | /* 2312 is max 802.11 payload, 20 is overhead, (ether + llc +snap) |
700 | and another 8 for wep. */ | |
701 | if ((new_mtu < 68) || (new_mtu > (2312 - 20 - 8))) | |
702 | return -EINVAL; | |
00b3ed16 | 703 | |
b4b3f0da | 704 | dev->mtu = new_mtu; |
00b3ed16 | 705 | |
b4b3f0da | 706 | return 0; |
00b3ed16 GKH |
707 | } |
708 | ||
cea96778 | 709 | static const struct net_device_ops p80211_netdev_ops = { |
75f49e07 MT |
710 | .ndo_init = p80211knetdev_init, |
711 | .ndo_open = p80211knetdev_open, | |
712 | .ndo_stop = p80211knetdev_stop, | |
713 | .ndo_get_stats = p80211knetdev_get_stats, | |
714 | .ndo_start_xmit = p80211knetdev_hard_start_xmit, | |
afc4b13d | 715 | .ndo_set_rx_mode = p80211knetdev_set_multicast_list, |
75f49e07 MT |
716 | .ndo_do_ioctl = p80211knetdev_do_ioctl, |
717 | .ndo_set_mac_address = p80211knetdev_set_mac_address, | |
718 | .ndo_tx_timeout = p80211knetdev_tx_timeout, | |
719 | .ndo_change_mtu = wlan_change_mtu, | |
720 | .ndo_validate_addr = eth_validate_addr, | |
cea96778 AB |
721 | }; |
722 | ||
00b3ed16 GKH |
723 | /*---------------------------------------------------------------- |
724 | * wlan_setup | |
725 | * | |
726 | * Roughly matches the functionality of ether_setup. Here | |
727 | * we set up any members of the wlandevice structure that are common | |
728 | * to all devices. Additionally, we allocate a linux 'struct device' | |
729 | * and perform the same setup as ether_setup. | |
730 | * | |
731 | * Note: It's important that the caller have setup the wlandev->name | |
732 | * ptr prior to calling this function. | |
733 | * | |
734 | * Arguments: | |
735 | * wlandev ptr to the wlandev structure for the | |
736 | * interface. | |
cb3126e6 | 737 | * physdev ptr to usb device |
00b3ed16 GKH |
738 | * Returns: |
739 | * zero on success, non-zero otherwise. | |
740 | * Call Context: | |
741 | * Should be process thread. We'll assume it might be | |
742 | * interrupt though. When we add support for statically | |
743 | * compiled drivers, this function will be called in the | |
744 | * context of the kernel startup code. | |
745 | ----------------------------------------------------------------*/ | |
cb3126e6 | 746 | int wlan_setup(wlandevice_t *wlandev, struct device *physdev) |
00b3ed16 | 747 | { |
b4b3f0da | 748 | int result = 0; |
cb3126e6 KR |
749 | netdevice_t *netdev; |
750 | struct wiphy *wiphy; | |
751 | struct wireless_dev *wdev; | |
00b3ed16 | 752 | |
00b3ed16 GKH |
753 | /* Set up the wlandev */ |
754 | wlandev->state = WLAN_DEVICE_CLOSED; | |
755 | wlandev->ethconv = WLAN_ETHCONV_8021h; | |
756 | wlandev->macmode = WLAN_MACMODE_NONE; | |
757 | ||
758 | /* Set up the rx queue */ | |
759 | skb_queue_head_init(&wlandev->nsd_rxq); | |
760 | tasklet_init(&wlandev->rx_bh, | |
b4b3f0da | 761 | p80211netdev_rx_bh, (unsigned long)wlandev); |
00b3ed16 | 762 | |
cb3126e6 KR |
763 | /* Allocate and initialize the wiphy struct */ |
764 | wiphy = wlan_create_wiphy(physdev, wlandev); | |
765 | if (wiphy == NULL) { | |
79f9e634 | 766 | dev_err(physdev, "Failed to alloc wiphy.\n"); |
cb3126e6 KR |
767 | return 1; |
768 | } | |
769 | ||
00b3ed16 | 770 | /* Allocate and initialize the struct device */ |
6f710907 | 771 | netdev = alloc_netdev(sizeof(struct wireless_dev), "wlan%d", |
c835a677 | 772 | NET_NAME_UNKNOWN, ether_setup); |
cb3126e6 | 773 | if (netdev == NULL) { |
79f9e634 | 774 | dev_err(physdev, "Failed to alloc netdev.\n"); |
cb3126e6 | 775 | wlan_free_wiphy(wiphy); |
00b3ed16 GKH |
776 | result = 1; |
777 | } else { | |
cb3126e6 KR |
778 | wlandev->netdev = netdev; |
779 | netdev->ml_priv = wlandev; | |
780 | netdev->netdev_ops = &p80211_netdev_ops; | |
781 | wdev = netdev_priv(netdev); | |
782 | wdev->wiphy = wiphy; | |
783 | wdev->iftype = NL80211_IFTYPE_STATION; | |
784 | netdev->ieee80211_ptr = wdev; | |
785 | ||
786 | netif_stop_queue(netdev); | |
787 | netif_carrier_off(netdev); | |
00b3ed16 GKH |
788 | } |
789 | ||
00b3ed16 GKH |
790 | return result; |
791 | } | |
792 | ||
793 | /*---------------------------------------------------------------- | |
794 | * wlan_unsetup | |
795 | * | |
796 | * This function is paired with the wlan_setup routine. It should | |
797 | * be called after unregister_wlandev. Basically, all it does is | |
798 | * free the 'struct device' that's associated with the wlandev. | |
799 | * We do it here because the 'struct device' isn't allocated | |
800 | * explicitly in the driver code, it's done in wlan_setup. To | |
801 | * do the free in the driver might seem like 'magic'. | |
802 | * | |
803 | * Arguments: | |
804 | * wlandev ptr to the wlandev structure for the | |
805 | * interface. | |
00b3ed16 GKH |
806 | * Call Context: |
807 | * Should be process thread. We'll assume it might be | |
808 | * interrupt though. When we add support for statically | |
809 | * compiled drivers, this function will be called in the | |
810 | * context of the kernel startup code. | |
811 | ----------------------------------------------------------------*/ | |
3f459327 | 812 | void wlan_unsetup(wlandevice_t *wlandev) |
00b3ed16 | 813 | { |
cb3126e6 | 814 | struct wireless_dev *wdev; |
00b3ed16 | 815 | |
00b3ed16 GKH |
816 | tasklet_kill(&wlandev->rx_bh); |
817 | ||
cb3126e6 KR |
818 | if (wlandev->netdev) { |
819 | wdev = netdev_priv(wlandev->netdev); | |
f34e3e7b EH |
820 | if (wdev->wiphy) |
821 | wlan_free_wiphy(wdev->wiphy); | |
00b3ed16 GKH |
822 | free_netdev(wlandev->netdev); |
823 | wlandev->netdev = NULL; | |
824 | } | |
00b3ed16 GKH |
825 | } |
826 | ||
00b3ed16 GKH |
827 | /*---------------------------------------------------------------- |
828 | * register_wlandev | |
829 | * | |
830 | * Roughly matches the functionality of register_netdev. This function | |
831 | * is called after the driver has successfully probed and set up the | |
832 | * resources for the device. It's now ready to become a named device | |
833 | * in the Linux system. | |
834 | * | |
835 | * First we allocate a name for the device (if not already set), then | |
836 | * we call the Linux function register_netdevice. | |
837 | * | |
838 | * Arguments: | |
839 | * wlandev ptr to the wlandev structure for the | |
840 | * interface. | |
841 | * Returns: | |
842 | * zero on success, non-zero otherwise. | |
843 | * Call Context: | |
844 | * Can be either interrupt or not. | |
845 | ----------------------------------------------------------------*/ | |
297f06ce | 846 | int register_wlandev(wlandevice_t *wlandev) |
00b3ed16 | 847 | { |
50d6b9ba | 848 | return register_netdev(wlandev->netdev); |
00b3ed16 GKH |
849 | } |
850 | ||
00b3ed16 GKH |
851 | /*---------------------------------------------------------------- |
852 | * unregister_wlandev | |
853 | * | |
854 | * Roughly matches the functionality of unregister_netdev. This | |
855 | * function is called to remove a named device from the system. | |
856 | * | |
857 | * First we tell linux that the device should no longer exist. | |
858 | * Then we remove it from the list of known wlan devices. | |
859 | * | |
860 | * Arguments: | |
861 | * wlandev ptr to the wlandev structure for the | |
862 | * interface. | |
863 | * Returns: | |
864 | * zero on success, non-zero otherwise. | |
865 | * Call Context: | |
866 | * Can be either interrupt or not. | |
867 | ----------------------------------------------------------------*/ | |
297f06ce | 868 | int unregister_wlandev(wlandevice_t *wlandev) |
00b3ed16 GKH |
869 | { |
870 | struct sk_buff *skb; | |
871 | ||
00b3ed16 GKH |
872 | unregister_netdev(wlandev->netdev); |
873 | ||
874 | /* Now to clean out the rx queue */ | |
b4b3f0da | 875 | while ((skb = skb_dequeue(&wlandev->nsd_rxq))) |
00b3ed16 | 876 | dev_kfree_skb(skb); |
00b3ed16 | 877 | |
00b3ed16 GKH |
878 | return 0; |
879 | } | |
880 | ||
00b3ed16 GKH |
881 | /*---------------------------------------------------------------- |
882 | * p80211netdev_hwremoved | |
883 | * | |
884 | * Hardware removed notification. This function should be called | |
885 | * immediately after an MSD has detected that the underlying hardware | |
886 | * has been yanked out from under us. The primary things we need | |
887 | * to do are: | |
888 | * - Mark the wlandev | |
889 | * - Prevent any further traffic from the knetdev i/f | |
890 | * - Prevent any further requests from mgmt i/f | |
891 | * - If there are any waitq'd mgmt requests or mgmt-frame exchanges, | |
892 | * shut them down. | |
893 | * - Call the MSD hwremoved function. | |
894 | * | |
895 | * The remainder of the cleanup will be handled by unregister(). | |
896 | * Our primary goal here is to prevent as much tickling of the MSD | |
897 | * as possible since the MSD is already in a 'wounded' state. | |
898 | * | |
899 | * TODO: As new features are added, this function should be | |
900 | * updated. | |
901 | * | |
902 | * Arguments: | |
903 | * wlandev WLAN network device structure | |
904 | * Returns: | |
905 | * nothing | |
906 | * Side effects: | |
907 | * | |
908 | * Call context: | |
909 | * Usually interrupt. | |
910 | ----------------------------------------------------------------*/ | |
297f06ce | 911 | void p80211netdev_hwremoved(wlandevice_t *wlandev) |
00b3ed16 | 912 | { |
00b3ed16 | 913 | wlandev->hwremoved = 1; |
b4b3f0da | 914 | if (wlandev->state == WLAN_DEVICE_OPEN) |
cbec30c4 | 915 | netif_stop_queue(wlandev->netdev); |
00b3ed16 GKH |
916 | |
917 | netif_device_detach(wlandev->netdev); | |
00b3ed16 GKH |
918 | } |
919 | ||
00b3ed16 GKH |
920 | /*---------------------------------------------------------------- |
921 | * p80211_rx_typedrop | |
922 | * | |
923 | * Classifies the frame, increments the appropriate counter, and | |
924 | * returns 0|1|2 indicating whether the driver should handle, ignore, or | |
925 | * drop the frame | |
926 | * | |
927 | * Arguments: | |
928 | * wlandev wlan device structure | |
929 | * fc frame control field | |
930 | * | |
931 | * Returns: | |
932 | * zero if the frame should be handled by the driver, | |
933 | * one if the frame should be ignored | |
934 | * anything else means we drop it. | |
935 | * | |
936 | * Side effects: | |
937 | * | |
938 | * Call context: | |
939 | * interrupt | |
940 | ----------------------------------------------------------------*/ | |
297f06ce | 941 | static int p80211_rx_typedrop(wlandevice_t *wlandev, u16 fc) |
00b3ed16 | 942 | { |
b4b3f0da MM |
943 | u16 ftype; |
944 | u16 fstype; | |
945 | int drop = 0; | |
00b3ed16 GKH |
946 | /* Classify frame, increment counter */ |
947 | ftype = WLAN_GET_FC_FTYPE(fc); | |
948 | fstype = WLAN_GET_FC_FSTYPE(fc); | |
949 | #if 0 | |
79f9e634 DP |
950 | netdev_dbg(wlandev->netdev, "rx_typedrop : ftype=%d fstype=%d.\n", |
951 | ftype, fstype); | |
00b3ed16 | 952 | #endif |
b4b3f0da | 953 | switch (ftype) { |
00b3ed16 GKH |
954 | case WLAN_FTYPE_MGMT: |
955 | if ((wlandev->netdev->flags & IFF_PROMISC) || | |
b4b3f0da | 956 | (wlandev->netdev->flags & IFF_ALLMULTI)) { |
00b3ed16 GKH |
957 | drop = 1; |
958 | break; | |
959 | } | |
79f9e634 | 960 | netdev_dbg(wlandev->netdev, "rx'd mgmt:\n"); |
00b3ed16 | 961 | wlandev->rx.mgmt++; |
b4b3f0da | 962 | switch (fstype) { |
00b3ed16 GKH |
963 | case WLAN_FSTYPE_ASSOCREQ: |
964 | /* printk("assocreq"); */ | |
965 | wlandev->rx.assocreq++; | |
966 | break; | |
967 | case WLAN_FSTYPE_ASSOCRESP: | |
968 | /* printk("assocresp"); */ | |
969 | wlandev->rx.assocresp++; | |
970 | break; | |
971 | case WLAN_FSTYPE_REASSOCREQ: | |
972 | /* printk("reassocreq"); */ | |
973 | wlandev->rx.reassocreq++; | |
974 | break; | |
975 | case WLAN_FSTYPE_REASSOCRESP: | |
976 | /* printk("reassocresp"); */ | |
977 | wlandev->rx.reassocresp++; | |
978 | break; | |
979 | case WLAN_FSTYPE_PROBEREQ: | |
980 | /* printk("probereq"); */ | |
981 | wlandev->rx.probereq++; | |
982 | break; | |
983 | case WLAN_FSTYPE_PROBERESP: | |
984 | /* printk("proberesp"); */ | |
985 | wlandev->rx.proberesp++; | |
986 | break; | |
987 | case WLAN_FSTYPE_BEACON: | |
988 | /* printk("beacon"); */ | |
989 | wlandev->rx.beacon++; | |
990 | break; | |
991 | case WLAN_FSTYPE_ATIM: | |
992 | /* printk("atim"); */ | |
993 | wlandev->rx.atim++; | |
994 | break; | |
995 | case WLAN_FSTYPE_DISASSOC: | |
996 | /* printk("disassoc"); */ | |
997 | wlandev->rx.disassoc++; | |
998 | break; | |
999 | case WLAN_FSTYPE_AUTHEN: | |
1000 | /* printk("authen"); */ | |
1001 | wlandev->rx.authen++; | |
1002 | break; | |
1003 | case WLAN_FSTYPE_DEAUTHEN: | |
1004 | /* printk("deauthen"); */ | |
1005 | wlandev->rx.deauthen++; | |
1006 | break; | |
1007 | default: | |
1008 | /* printk("unknown"); */ | |
1009 | wlandev->rx.mgmt_unknown++; | |
1010 | break; | |
1011 | } | |
1012 | /* printk("\n"); */ | |
1013 | drop = 2; | |
1014 | break; | |
1015 | ||
1016 | case WLAN_FTYPE_CTL: | |
1017 | if ((wlandev->netdev->flags & IFF_PROMISC) || | |
b4b3f0da | 1018 | (wlandev->netdev->flags & IFF_ALLMULTI)) { |
00b3ed16 GKH |
1019 | drop = 1; |
1020 | break; | |
1021 | } | |
79f9e634 | 1022 | netdev_dbg(wlandev->netdev, "rx'd ctl:\n"); |
00b3ed16 | 1023 | wlandev->rx.ctl++; |
b4b3f0da | 1024 | switch (fstype) { |
00b3ed16 GKH |
1025 | case WLAN_FSTYPE_PSPOLL: |
1026 | /* printk("pspoll"); */ | |
1027 | wlandev->rx.pspoll++; | |
1028 | break; | |
1029 | case WLAN_FSTYPE_RTS: | |
1030 | /* printk("rts"); */ | |
1031 | wlandev->rx.rts++; | |
1032 | break; | |
1033 | case WLAN_FSTYPE_CTS: | |
1034 | /* printk("cts"); */ | |
1035 | wlandev->rx.cts++; | |
1036 | break; | |
1037 | case WLAN_FSTYPE_ACK: | |
1038 | /* printk("ack"); */ | |
1039 | wlandev->rx.ack++; | |
1040 | break; | |
1041 | case WLAN_FSTYPE_CFEND: | |
1042 | /* printk("cfend"); */ | |
1043 | wlandev->rx.cfend++; | |
1044 | break; | |
1045 | case WLAN_FSTYPE_CFENDCFACK: | |
1046 | /* printk("cfendcfack"); */ | |
1047 | wlandev->rx.cfendcfack++; | |
1048 | break; | |
1049 | default: | |
1050 | /* printk("unknown"); */ | |
1051 | wlandev->rx.ctl_unknown++; | |
1052 | break; | |
1053 | } | |
1054 | /* printk("\n"); */ | |
1055 | drop = 2; | |
1056 | break; | |
1057 | ||
1058 | case WLAN_FTYPE_DATA: | |
1059 | wlandev->rx.data++; | |
b4b3f0da | 1060 | switch (fstype) { |
00b3ed16 GKH |
1061 | case WLAN_FSTYPE_DATAONLY: |
1062 | wlandev->rx.dataonly++; | |
1063 | break; | |
1064 | case WLAN_FSTYPE_DATA_CFACK: | |
1065 | wlandev->rx.data_cfack++; | |
1066 | break; | |
1067 | case WLAN_FSTYPE_DATA_CFPOLL: | |
1068 | wlandev->rx.data_cfpoll++; | |
1069 | break; | |
1070 | case WLAN_FSTYPE_DATA_CFACK_CFPOLL: | |
1071 | wlandev->rx.data__cfack_cfpoll++; | |
1072 | break; | |
1073 | case WLAN_FSTYPE_NULL: | |
79f9e634 | 1074 | netdev_dbg(wlandev->netdev, "rx'd data:null\n"); |
00b3ed16 GKH |
1075 | wlandev->rx.null++; |
1076 | break; | |
1077 | case WLAN_FSTYPE_CFACK: | |
79f9e634 | 1078 | netdev_dbg(wlandev->netdev, "rx'd data:cfack\n"); |
00b3ed16 GKH |
1079 | wlandev->rx.cfack++; |
1080 | break; | |
1081 | case WLAN_FSTYPE_CFPOLL: | |
79f9e634 | 1082 | netdev_dbg(wlandev->netdev, "rx'd data:cfpoll\n"); |
00b3ed16 GKH |
1083 | wlandev->rx.cfpoll++; |
1084 | break; | |
1085 | case WLAN_FSTYPE_CFACK_CFPOLL: | |
79f9e634 | 1086 | netdev_dbg(wlandev->netdev, "rx'd data:cfack_cfpoll\n"); |
00b3ed16 GKH |
1087 | wlandev->rx.cfack_cfpoll++; |
1088 | break; | |
1089 | default: | |
1090 | /* printk("unknown"); */ | |
1091 | wlandev->rx.data_unknown++; | |
1092 | break; | |
1093 | } | |
1094 | ||
1095 | break; | |
1096 | } | |
1097 | return drop; | |
1098 | } | |
1099 | ||
297f06ce | 1100 | static void p80211knetdev_tx_timeout(netdevice_t *netdev) |
00b3ed16 | 1101 | { |
b4b3f0da | 1102 | wlandevice_t *wlandev = netdev->ml_priv; |
00b3ed16 GKH |
1103 | |
1104 | if (wlandev->tx_timeout) { | |
1105 | wlandev->tx_timeout(wlandev); | |
1106 | } else { | |
79f9e634 DP |
1107 | netdev_warn(netdev, "Implement tx_timeout for %s\n", |
1108 | wlandev->nsdname); | |
cbec30c4 | 1109 | netif_wake_queue(wlandev->netdev); |
00b3ed16 | 1110 | } |
00b3ed16 | 1111 | } |