]> pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/staging/wlan-ng/p80211netdev.c
Staging: wlan-ng: Eliminate more <2.6 kernel support.
[linux-2.6-omap-h63xx.git] / drivers / staging / wlan-ng / p80211netdev.c
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
52
53 /*================================================================*/
54 /* System Includes */
55
56
57 #include <linux/version.h>
58
59 #include <linux/module.h>
60 #include <linux/kernel.h>
61 #include <linux/sched.h>
62 #include <linux/types.h>
63 #include <linux/skbuff.h>
64 #include <linux/slab.h>
65 #include <linux/proc_fs.h>
66 #include <linux/interrupt.h>
67 #include <linux/netdevice.h>
68 #include <linux/kmod.h>
69 #include <linux/if_arp.h>
70 #include <linux/wireless.h>
71 #include <linux/sockios.h>
72 #include <linux/etherdevice.h>
73
74 #include <asm/bitops.h>
75 #include <asm/uaccess.h>
76 #include <asm/byteorder.h>
77
78 #ifdef SIOCETHTOOL
79 #include <linux/ethtool.h>
80 #endif
81
82 #if WIRELESS_EXT > 12
83 #include <net/iw_handler.h>
84 #endif
85 #include <net/net_namespace.h>
86
87 /*================================================================*/
88 /* Project Includes */
89
90 #include "version.h"
91 #include "wlan_compat.h"
92 #include "p80211types.h"
93 #include "p80211hdr.h"
94 #include "p80211conv.h"
95 #include "p80211mgmt.h"
96 #include "p80211msg.h"
97 #include "p80211netdev.h"
98 #include "p80211ioctl.h"
99 #include "p80211req.h"
100 #include "p80211metastruct.h"
101 #include "p80211metadef.h"
102
103 /*================================================================*/
104 /* Local Constants */
105
106 /*================================================================*/
107 /* Local Macros */
108
109
110 /*================================================================*/
111 /* Local Types */
112
113 /*================================================================*/
114 /* Local Static Definitions */
115
116 #define __NO_VERSION__          /* prevent the static definition */
117
118 #ifdef CONFIG_PROC_FS
119 static struct proc_dir_entry    *proc_p80211;
120 #endif
121
122 /*================================================================*/
123 /* Local Function Declarations */
124
125 /* Support functions */
126 static void p80211netdev_rx_bh(unsigned long arg);
127
128 /* netdevice method functions */
129 static int p80211knetdev_init( netdevice_t *netdev);
130 static struct net_device_stats* p80211knetdev_get_stats(netdevice_t *netdev);
131 static int p80211knetdev_open( netdevice_t *netdev);
132 static int p80211knetdev_stop( netdevice_t *netdev );
133 static int p80211knetdev_hard_start_xmit( struct sk_buff *skb, netdevice_t *netdev);
134 static void p80211knetdev_set_multicast_list(netdevice_t *dev);
135 static int p80211knetdev_do_ioctl(netdevice_t *dev, struct ifreq *ifr, int cmd);
136 static int p80211knetdev_set_mac_address(netdevice_t *dev, void *addr);
137 static void p80211knetdev_tx_timeout(netdevice_t *netdev);
138 static int p80211_rx_typedrop( wlandevice_t *wlandev, UINT16 fc);
139
140 #ifdef CONFIG_PROC_FS
141 static int
142 p80211netdev_proc_read(
143         char    *page,
144         char    **start,
145         off_t   offset,
146         int     count,
147         int     *eof,
148         void    *data);
149 #endif
150
151 /*================================================================*/
152 /* Function Definitions */
153
154 /*----------------------------------------------------------------
155 * p80211knetdev_startup
156 *
157 * Initialize the wlandevice/netdevice part of 802.11 services at
158 * load time.
159 *
160 * Arguments:
161 *       none
162 *
163 * Returns:
164 *       nothing
165 ----------------------------------------------------------------*/
166 void p80211netdev_startup(void)
167 {
168         DBFENTER;
169
170 #ifdef CONFIG_PROC_FS
171         if (init_net.proc_net != NULL) {
172                 proc_p80211 = create_proc_entry(
173                                 "p80211",
174                                 (S_IFDIR|S_IRUGO|S_IXUGO),
175                                 init_net.proc_net);
176         }
177 #endif
178         DBFEXIT;
179         return;
180 }
181
182 /*----------------------------------------------------------------
183 * p80211knetdev_shutdown
184 *
185 * Shutdown the wlandevice/netdevice part of 802.11 services at
186 * unload time.
187 *
188 * Arguments:
189 *       none
190 *
191 * Returns:
192 *       nothing
193 ----------------------------------------------------------------*/
194 void
195 p80211netdev_shutdown(void)
196 {
197         DBFENTER;
198 #ifdef CONFIG_PROC_FS
199         if (proc_p80211 != NULL) {
200                 remove_proc_entry("p80211", init_net.proc_net);
201         }
202 #endif
203         DBFEXIT;
204 }
205
206 /*----------------------------------------------------------------
207 * p80211knetdev_init
208 *
209 * Init method for a Linux netdevice.  Called in response to
210 * register_netdev.
211 *
212 * Arguments:
213 *       none
214 *
215 * Returns:
216 *       nothing
217 ----------------------------------------------------------------*/
218 static int p80211knetdev_init( netdevice_t *netdev)
219 {
220         DBFENTER;
221         /* Called in response to register_netdev */
222         /* This is usually the probe function, but the probe has */
223         /* already been done by the MSD and the create_kdev */
224         /* function.  All we do here is return success */
225         DBFEXIT;
226         return 0;
227 }
228
229
230 /*----------------------------------------------------------------
231 * p80211knetdev_get_stats
232 *
233 * Statistics retrieval for linux netdevices.  Here we're reporting
234 * the Linux i/f level statistics.  Hence, for the primary numbers,
235 * we don't want to report the numbers from the MIB.  Eventually,
236 * it might be useful to collect some of the error counters though.
237 *
238 * Arguments:
239 *       netdev          Linux netdevice
240 *
241 * Returns:
242 *       the address of the statistics structure
243 ----------------------------------------------------------------*/
244 static struct net_device_stats*
245 p80211knetdev_get_stats(netdevice_t *netdev)
246 {
247         wlandevice_t    *wlandev = netdev->ml_priv;
248         DBFENTER;
249
250         /* TODO: review the MIB stats for items that correspond to
251                 linux stats */
252
253         DBFEXIT;
254         return &(wlandev->linux_stats);
255 }
256
257
258 /*----------------------------------------------------------------
259 * p80211knetdev_open
260 *
261 * Linux netdevice open method.  Following a successful call here,
262 * the device is supposed to be ready for tx and rx.  In our
263 * situation that may not be entirely true due to the state of the
264 * MAC below.
265 *
266 * Arguments:
267 *       netdev          Linux network device structure
268 *
269 * Returns:
270 *       zero on success, non-zero otherwise
271 ----------------------------------------------------------------*/
272 static int p80211knetdev_open( netdevice_t *netdev )
273 {
274         int             result = 0; /* success */
275         wlandevice_t    *wlandev = netdev->ml_priv;
276
277         DBFENTER;
278
279         /* Check to make sure the MSD is running */
280         if ( wlandev->msdstate != WLAN_MSD_RUNNING ) {
281                 return -ENODEV;
282         }
283
284         /* Tell the MSD to open */
285         if ( wlandev->open != NULL) {
286                 result = wlandev->open(wlandev);
287                 if ( result == 0 ) {
288                         p80211netdev_start_queue(wlandev);
289                         wlandev->state = WLAN_DEVICE_OPEN;
290                 }
291         } else {
292                 result = -EAGAIN;
293         }
294
295         DBFEXIT;
296         return result;
297 }
298
299
300 /*----------------------------------------------------------------
301 * p80211knetdev_stop
302 *
303 * Linux netdevice stop (close) method.  Following this call,
304 * no frames should go up or down through this interface.
305 *
306 * Arguments:
307 *       netdev          Linux network device structure
308 *
309 * Returns:
310 *       zero on success, non-zero otherwise
311 ----------------------------------------------------------------*/
312 static int p80211knetdev_stop( netdevice_t *netdev )
313 {
314         int             result = 0;
315         wlandevice_t    *wlandev = netdev->ml_priv;
316
317         DBFENTER;
318
319         if ( wlandev->close != NULL ) {
320                 result = wlandev->close(wlandev);
321         }
322
323         p80211netdev_stop_queue(wlandev);
324         wlandev->state = WLAN_DEVICE_CLOSED;
325
326         DBFEXIT;
327         return result;
328 }
329
330 /*----------------------------------------------------------------
331 * p80211netdev_rx
332 *
333 * Frame receive function called by the mac specific driver.
334 *
335 * Arguments:
336 *       wlandev         WLAN network device structure
337 *       skb             skbuff containing a full 802.11 frame.
338 * Returns:
339 *       nothing
340 * Side effects:
341 *
342 ----------------------------------------------------------------*/
343 void
344 p80211netdev_rx(wlandevice_t *wlandev, struct sk_buff *skb )
345 {
346         DBFENTER;
347
348         /* Enqueue for post-irq processing */
349         skb_queue_tail(&wlandev->nsd_rxq, skb);
350
351         tasklet_schedule(&wlandev->rx_bh);
352
353         DBFEXIT;
354         return;
355 }
356
357 /*----------------------------------------------------------------
358 * p80211netdev_rx_bh
359 *
360 * Deferred processing of all received frames.
361 *
362 * Arguments:
363 *       wlandev         WLAN network device structure
364 *       skb             skbuff containing a full 802.11 frame.
365 * Returns:
366 *       nothing
367 * Side effects:
368 *
369 ----------------------------------------------------------------*/
370 static void p80211netdev_rx_bh(unsigned long arg)
371 {
372         wlandevice_t *wlandev = (wlandevice_t *) arg;
373         struct sk_buff *skb = NULL;
374         netdevice_t     *dev = wlandev->netdev;
375         p80211_hdr_a3_t *hdr;
376         UINT16 fc;
377
378         DBFENTER;
379
380         /* Let's empty our our queue */
381         while ( (skb = skb_dequeue(&wlandev->nsd_rxq)) ) {
382                 if (wlandev->state == WLAN_DEVICE_OPEN) {
383
384                         if (dev->type != ARPHRD_ETHER) {
385                                 /* RAW frame; we shouldn't convert it */
386                                 // XXX Append the Prism Header here instead.
387
388                                 /* set up various data fields */
389                                 skb->dev = dev;
390                                 skb_reset_mac_header(skb);
391                                 skb->ip_summed = CHECKSUM_NONE;
392                                 skb->pkt_type = PACKET_OTHERHOST;
393                                 skb->protocol = htons(ETH_P_80211_RAW);
394                                 dev->last_rx = jiffies;
395
396                                 wlandev->linux_stats.rx_packets++;
397                                 wlandev->linux_stats.rx_bytes += skb->len;
398                                 netif_rx_ni(skb);
399                                 continue;
400                         } else {
401                                 hdr = (p80211_hdr_a3_t *)skb->data;
402                                 fc = ieee2host16(hdr->fc);
403                                 if (p80211_rx_typedrop(wlandev, fc)) {
404                                         dev_kfree_skb(skb);
405                                         continue;
406                                 }
407
408                                 /* perform mcast filtering */
409                                 if (wlandev->netdev->flags & IFF_ALLMULTI) {
410                                         /* allow my local address through */
411                                         if (memcmp(hdr->a1, wlandev->netdev->dev_addr, WLAN_ADDR_LEN) != 0) {
412                                                 /* but reject anything else that isn't multicast */
413                                                 if (!(hdr->a1[0] & 0x01)) {
414                                                         dev_kfree_skb(skb);
415                                                         continue;
416                                                 }
417                                         }
418                                 }
419
420                                 if ( skb_p80211_to_ether(wlandev, wlandev->ethconv, skb) == 0 ) {
421                                         skb->dev->last_rx = jiffies;
422                                         wlandev->linux_stats.rx_packets++;
423                                         wlandev->linux_stats.rx_bytes += skb->len;
424                                         netif_rx_ni(skb);
425                                         continue;
426                                 }
427                                 WLAN_LOG_DEBUG(1, "p80211_to_ether failed.\n");
428                         }
429                 }
430                 dev_kfree_skb(skb);
431         }
432
433         DBFEXIT;
434 }
435
436
437 /*----------------------------------------------------------------
438 * p80211knetdev_hard_start_xmit
439 *
440 * Linux netdevice method for transmitting a frame.
441 *
442 * Arguments:
443 *       skb     Linux sk_buff containing the frame.
444 *       netdev  Linux netdevice.
445 *
446 * Side effects:
447 *       If the lower layers report that buffers are full. netdev->tbusy
448 *       will be set to prevent higher layers from sending more traffic.
449 *
450 *       Note: If this function returns non-zero, higher layers retain
451 *             ownership of the skb.
452 *
453 * Returns:
454 *       zero on success, non-zero on failure.
455 ----------------------------------------------------------------*/
456 static int p80211knetdev_hard_start_xmit( struct sk_buff *skb, netdevice_t *netdev)
457 {
458         int             result = 0;
459         int             txresult = -1;
460         wlandevice_t    *wlandev = netdev->ml_priv;
461         p80211_hdr_t    p80211_hdr;
462         p80211_metawep_t p80211_wep;
463
464         DBFENTER;
465
466         if (skb == NULL) {
467                 return 0;
468         }
469
470         if (wlandev->state != WLAN_DEVICE_OPEN) {
471                 result = 1;
472                 goto failed;
473         }
474
475         memset(&p80211_hdr, 0, sizeof(p80211_hdr_t));
476         memset(&p80211_wep, 0, sizeof(p80211_metawep_t));
477
478         if ( netif_queue_stopped(netdev) ) {
479                 WLAN_LOG_DEBUG(1, "called when queue stopped.\n");
480                 result = 1;
481                 goto failed;
482         }
483
484         netif_stop_queue(netdev);
485
486         /* Check to see that a valid mode is set */
487         switch( wlandev->macmode ) {
488         case WLAN_MACMODE_IBSS_STA:
489         case WLAN_MACMODE_ESS_STA:
490         case WLAN_MACMODE_ESS_AP:
491                 break;
492         default:
493                 /* Mode isn't set yet, just drop the frame
494                  * and return success .
495                  * TODO: we need a saner way to handle this
496                  */
497                 if(skb->protocol != ETH_P_80211_RAW) {
498                         p80211netdev_start_queue(wlandev);
499                         WLAN_LOG_NOTICE(
500                                 "Tx attempt prior to association, frame dropped.\n");
501                         wlandev->linux_stats.tx_dropped++;
502                         result = 0;
503                         goto failed;
504                 }
505                 break;
506         }
507
508         /* Check for raw transmits */
509         if(skb->protocol == ETH_P_80211_RAW) {
510                 if (!capable(CAP_NET_ADMIN)) {
511                         result = 1;
512                         goto failed;
513                 }
514                 /* move the header over */
515                 memcpy(&p80211_hdr, skb->data, sizeof(p80211_hdr_t));
516                 skb_pull(skb, sizeof(p80211_hdr_t));
517         } else {
518                 if ( skb_ether_to_p80211(wlandev, wlandev->ethconv, skb, &p80211_hdr, &p80211_wep) != 0 ) {
519                         /* convert failed */
520                         WLAN_LOG_DEBUG(1, "ether_to_80211(%d) failed.\n",
521                                         wlandev->ethconv);
522                         result = 1;
523                         goto failed;
524                 }
525         }
526         if ( wlandev->txframe == NULL ) {
527                 result = 1;
528                 goto failed;
529         }
530
531         netdev->trans_start = jiffies;
532
533         wlandev->linux_stats.tx_packets++;
534         /* count only the packet payload */
535         wlandev->linux_stats.tx_bytes += skb->len;
536
537         txresult = wlandev->txframe(wlandev, skb, &p80211_hdr, &p80211_wep);
538
539         if ( txresult == 0) {
540                 /* success and more buf */
541                 /* avail, re: hw_txdata */
542                 p80211netdev_wake_queue(wlandev);
543                 result = 0;
544         } else if ( txresult == 1 ) {
545                 /* success, no more avail */
546                 WLAN_LOG_DEBUG(3, "txframe success, no more bufs\n");
547                 /* netdev->tbusy = 1;  don't set here, irqhdlr */
548                 /*   may have already cleared it */
549                 result = 0;
550         } else if ( txresult == 2 ) {
551                 /* alloc failure, drop frame */
552                 WLAN_LOG_DEBUG(3, "txframe returned alloc_fail\n");
553                 result = 1;
554         } else {
555                 /* buffer full or queue busy, drop frame. */
556                 WLAN_LOG_DEBUG(3, "txframe returned full or busy\n");
557                 result = 1;
558         }
559
560  failed:
561         /* Free up the WEP buffer if it's not the same as the skb */
562         if ((p80211_wep.data) && (p80211_wep.data != skb->data))
563                 kfree(p80211_wep.data);
564
565         /* we always free the skb here, never in a lower level. */
566         if (!result)
567                 dev_kfree_skb(skb);
568
569         DBFEXIT;
570         return result;
571 }
572
573
574 /*----------------------------------------------------------------
575 * p80211knetdev_set_multicast_list
576 *
577 * Called from higher lavers whenever there's a need to set/clear
578 * promiscuous mode or rewrite the multicast list.
579 *
580 * Arguments:
581 *       none
582 *
583 * Returns:
584 *       nothing
585 ----------------------------------------------------------------*/
586 static void p80211knetdev_set_multicast_list(netdevice_t *dev)
587 {
588         wlandevice_t    *wlandev = dev->ml_priv;
589
590         DBFENTER;
591
592         /* TODO:  real multicast support as well */
593
594         if (wlandev->set_multicast_list)
595                 wlandev->set_multicast_list(wlandev, dev);
596
597         DBFEXIT;
598 }
599
600 #ifdef SIOCETHTOOL
601
602 static int p80211netdev_ethtool(wlandevice_t *wlandev, void __user *useraddr)
603 {
604         UINT32 ethcmd;
605         struct ethtool_drvinfo info;
606         struct ethtool_value edata;
607
608         memset(&info, 0, sizeof(info));
609         memset(&edata, 0, sizeof(edata));
610
611         if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
612                 return -EFAULT;
613
614         switch (ethcmd) {
615         case ETHTOOL_GDRVINFO:
616                 info.cmd = ethcmd;
617                 snprintf(info.driver, sizeof(info.driver), "p80211_%s",
618                          wlandev->nsdname);
619                 snprintf(info.version, sizeof(info.version), "%s",
620                          WLAN_RELEASE);
621
622                 // info.fw_version
623                 // info.bus_info
624
625                 if (copy_to_user(useraddr, &info, sizeof(info)))
626                         return -EFAULT;
627                 return 0;
628 #ifdef ETHTOOL_GLINK
629         case ETHTOOL_GLINK:
630                 edata.cmd = ethcmd;
631
632                 if (wlandev->linkstatus &&
633                     (wlandev->macmode != WLAN_MACMODE_NONE)) {
634                         edata.data = 1;
635                 } else {
636                         edata.data = 0;
637                 }
638
639                 if (copy_to_user(useraddr, &edata, sizeof(edata)))
640                         return -EFAULT;
641                 return 0;
642         }
643 #endif
644
645         return -EOPNOTSUPP;
646 }
647
648 #endif
649
650 /*----------------------------------------------------------------
651 * p80211knetdev_do_ioctl
652 *
653 * Handle an ioctl call on one of our devices.  Everything Linux
654 * ioctl specific is done here.  Then we pass the contents of the
655 * ifr->data to the request message handler.
656 *
657 * Arguments:
658 *       dev     Linux kernel netdevice
659 *       ifr     Our private ioctl request structure, typed for the
660 *               generic struct ifreq so we can use ptr to func
661 *               w/o cast.
662 *
663 * Returns:
664 *       zero on success, a negative errno on failure.  Possible values:
665 *               -ENETDOWN Device isn't up.
666 *               -EBUSY  cmd already in progress
667 *               -ETIME  p80211 cmd timed out (MSD may have its own timers)
668 *               -EFAULT memory fault copying msg from user buffer
669 *               -ENOMEM unable to allocate kernel msg buffer
670 *               -ENOSYS bad magic, it the cmd really for us?
671 *               -EINTR  sleeping on cmd, awakened by signal, cmd cancelled.
672 *
673 * Call Context:
674 *       Process thread (ioctl caller).  TODO: SMP support may require
675 *       locks.
676 ----------------------------------------------------------------*/
677 static int p80211knetdev_do_ioctl(netdevice_t *dev, struct ifreq *ifr, int cmd)
678 {
679         int                     result = 0;
680         p80211ioctl_req_t       *req = (p80211ioctl_req_t*)ifr;
681         wlandevice_t            *wlandev = dev->ml_priv;
682         UINT8                   *msgbuf;
683         DBFENTER;
684
685         WLAN_LOG_DEBUG(2, "rx'd ioctl, cmd=%d, len=%d\n", cmd, req->len);
686
687 #if WIRELESS_EXT < 13
688         /* Is this a wireless extensions ioctl? */
689         if ((cmd >= SIOCIWFIRST) && (cmd <= SIOCIWLAST)) {
690                 if ((result = p80211wext_support_ioctl(dev, ifr, cmd))
691                     != (-EOPNOTSUPP)) {
692                         goto bail;
693                 }
694         }
695 #endif
696
697 #ifdef SIOCETHTOOL
698         if (cmd == SIOCETHTOOL) {
699                 result = p80211netdev_ethtool(wlandev, (void __user *) ifr->ifr_data);
700                 goto bail;
701         }
702 #endif
703
704         /* Test the magic, assume ifr is good if it's there */
705         if ( req->magic != P80211_IOCTL_MAGIC ) {
706                 result = -ENOSYS;
707                 goto bail;
708         }
709
710         if ( cmd == P80211_IFTEST ) {
711                 result = 0;
712                 goto bail;
713         } else if ( cmd != P80211_IFREQ ) {
714                 result = -ENOSYS;
715                 goto bail;
716         }
717
718         /* Allocate a buf of size req->len */
719         if ((msgbuf = kmalloc( req->len, GFP_KERNEL))) {
720                 if ( copy_from_user( msgbuf, (void __user *) req->data, req->len) ) {
721                         result = -EFAULT;
722                 } else {
723                         result = p80211req_dorequest( wlandev, msgbuf);
724                 }
725
726                 if ( result == 0 ) {
727                         if ( copy_to_user( (void __user *) req->data, msgbuf, req->len)) {
728                                 result = -EFAULT;
729                         }
730                 }
731                 kfree(msgbuf);
732         } else {
733                 result = -ENOMEM;
734         }
735 bail:
736         DBFEXIT;
737
738         return result; /* If allocate,copyfrom or copyto fails, return errno */
739 }
740
741 /*----------------------------------------------------------------
742 * p80211knetdev_set_mac_address
743 *
744 * Handles the ioctl for changing the MACAddress of a netdevice
745 *
746 * references: linux/netdevice.h and drivers/net/net_init.c
747 *
748 * NOTE: [MSM] We only prevent address changes when the netdev is
749 * up.  We don't control anything based on dot11 state.  If the
750 * address is changed on a STA that's currently associated, you
751 * will probably lose the ability to send and receive data frames.
752 * Just be aware.  Therefore, this should usually only be done
753 * prior to scan/join/auth/assoc.
754 *
755 * Arguments:
756 *       dev     netdevice struct
757 *       addr    the new MACAddress (a struct)
758 *
759 * Returns:
760 *       zero on success, a negative errno on failure.  Possible values:
761 *               -EBUSY  device is bussy (cmd not possible)
762 *               -and errors returned by: p80211req_dorequest(..)
763 *
764 * by: Collin R. Mulliner <collin@mulliner.org>
765 ----------------------------------------------------------------*/
766 static int p80211knetdev_set_mac_address(netdevice_t *dev, void *addr)
767 {
768         struct sockaddr                 *new_addr = addr;
769         p80211msg_dot11req_mibset_t     dot11req;
770         p80211item_unk392_t             *mibattr;
771         p80211item_pstr6_t              *macaddr;
772         p80211item_uint32_t             *resultcode;
773         int result = 0;
774
775         DBFENTER;
776         /* If we're running, we don't allow MAC address changes */
777         if (netif_running(dev)) {
778                 return -EBUSY;
779         }
780
781         /* Set up some convenience pointers. */
782         mibattr = &dot11req.mibattribute;
783         macaddr = (p80211item_pstr6_t*)&mibattr->data;
784         resultcode = &dot11req.resultcode;
785
786         /* Set up a dot11req_mibset */
787         memset(&dot11req, 0, sizeof(p80211msg_dot11req_mibset_t));
788         dot11req.msgcode = DIDmsg_dot11req_mibset;
789         dot11req.msglen = sizeof(p80211msg_dot11req_mibset_t);
790         memcpy(dot11req.devname,
791                 ((wlandevice_t *)dev->ml_priv)->name,
792                 WLAN_DEVNAMELEN_MAX - 1);
793
794         /* Set up the mibattribute argument */
795         mibattr->did = DIDmsg_dot11req_mibset_mibattribute;
796         mibattr->status = P80211ENUM_msgitem_status_data_ok;
797         mibattr->len = sizeof(mibattr->data);
798
799         macaddr->did = DIDmib_dot11mac_dot11OperationTable_dot11MACAddress;
800         macaddr->status = P80211ENUM_msgitem_status_data_ok;
801         macaddr->len = sizeof(macaddr->data);
802         macaddr->data.len = WLAN_ADDR_LEN;
803         memcpy(&macaddr->data.data, new_addr->sa_data, WLAN_ADDR_LEN);
804
805         /* Set up the resultcode argument */
806         resultcode->did = DIDmsg_dot11req_mibset_resultcode;
807         resultcode->status = P80211ENUM_msgitem_status_no_value;
808         resultcode->len = sizeof(resultcode->data);
809         resultcode->data = 0;
810
811         /* now fire the request */
812         result = p80211req_dorequest(dev->ml_priv, (UINT8 *)&dot11req);
813
814         /* If the request wasn't successful, report an error and don't
815          * change the netdev address
816          */
817         if ( result != 0 || resultcode->data != P80211ENUM_resultcode_success) {
818                 WLAN_LOG_ERROR(
819                 "Low-level driver failed dot11req_mibset(dot11MACAddress).\n");
820                 result = -EADDRNOTAVAIL;
821         } else {
822                 /* everything's ok, change the addr in netdev */
823                 memcpy(dev->dev_addr, new_addr->sa_data, dev->addr_len);
824         }
825
826         DBFEXIT;
827         return result;
828 }
829
830 static int wlan_change_mtu(netdevice_t *dev, int new_mtu)
831 {
832         DBFENTER;
833         // 2312 is max 802.11 payload, 20 is overhead, (ether + llc +snap)
834         // and another 8 for wep.
835         if ( (new_mtu < 68) || (new_mtu > (2312 - 20 - 8)))
836                 return -EINVAL;
837
838         dev->mtu = new_mtu;
839
840         DBFEXIT;
841
842         return 0;
843 }
844
845
846
847 /*----------------------------------------------------------------
848 * wlan_setup
849 *
850 * Roughly matches the functionality of ether_setup.  Here
851 * we set up any members of the wlandevice structure that are common
852 * to all devices.  Additionally, we allocate a linux 'struct device'
853 * and perform the same setup as ether_setup.
854 *
855 * Note: It's important that the caller have setup the wlandev->name
856 *       ptr prior to calling this function.
857 *
858 * Arguments:
859 *       wlandev         ptr to the wlandev structure for the
860 *                       interface.
861 * Returns:
862 *       zero on success, non-zero otherwise.
863 * Call Context:
864 *       Should be process thread.  We'll assume it might be
865 *       interrupt though.  When we add support for statically
866 *       compiled drivers, this function will be called in the
867 *       context of the kernel startup code.
868 ----------------------------------------------------------------*/
869 int wlan_setup(wlandevice_t *wlandev)
870 {
871         int             result = 0;
872         netdevice_t     *dev;
873
874         DBFENTER;
875
876         /* Set up the wlandev */
877         wlandev->state = WLAN_DEVICE_CLOSED;
878         wlandev->ethconv = WLAN_ETHCONV_8021h;
879         wlandev->macmode = WLAN_MACMODE_NONE;
880
881         /* Set up the rx queue */
882         skb_queue_head_init(&wlandev->nsd_rxq);
883         tasklet_init(&wlandev->rx_bh,
884                      p80211netdev_rx_bh,
885                      (unsigned long)wlandev);
886
887         /* Allocate and initialize the struct device */
888         dev = kmalloc(sizeof(netdevice_t), GFP_ATOMIC);
889         if ( dev == NULL ) {
890                 WLAN_LOG_ERROR("Failed to alloc netdev.\n");
891                 result = 1;
892         } else {
893                 memset( dev, 0, sizeof(netdevice_t));
894                 ether_setup(dev);
895                 wlandev->netdev = dev;
896                 dev->ml_priv = wlandev;
897                 dev->hard_start_xmit =  p80211knetdev_hard_start_xmit;
898                 dev->get_stats =        p80211knetdev_get_stats;
899 #ifdef HAVE_PRIVATE_IOCTL
900                 dev->do_ioctl =         p80211knetdev_do_ioctl;
901 #endif
902 #ifdef HAVE_MULTICAST
903                 dev->set_multicast_list = p80211knetdev_set_multicast_list;
904 #endif
905                 dev->init =             p80211knetdev_init;
906                 dev->open =             p80211knetdev_open;
907                 dev->stop =             p80211knetdev_stop;
908
909 #ifdef CONFIG_NET_WIRELESS
910 #if ((WIRELESS_EXT < 17) && (WIRELESS_EXT < 21))
911                 dev->get_wireless_stats = p80211wext_get_wireless_stats;
912 #endif
913 #if WIRELESS_EXT > 12
914                 dev->wireless_handlers = &p80211wext_handler_def;
915 #endif
916 #endif
917
918                 netif_stop_queue(dev);
919 #ifdef HAVE_CHANGE_MTU
920                 dev->change_mtu = wlan_change_mtu;
921 #endif
922 #ifdef HAVE_SET_MAC_ADDR
923                 dev->set_mac_address =  p80211knetdev_set_mac_address;
924 #endif
925 #ifdef HAVE_TX_TIMEOUT
926                 dev->tx_timeout      =  &p80211knetdev_tx_timeout;
927                 dev->watchdog_timeo  =  (wlan_watchdog * HZ) / 1000;
928 #endif
929                 netif_carrier_off(dev);
930         }
931
932         DBFEXIT;
933         return result;
934 }
935
936 /*----------------------------------------------------------------
937 * wlan_unsetup
938 *
939 * This function is paired with the wlan_setup routine.  It should
940 * be called after unregister_wlandev.  Basically, all it does is
941 * free the 'struct device' that's associated with the wlandev.
942 * We do it here because the 'struct device' isn't allocated
943 * explicitly in the driver code, it's done in wlan_setup.  To
944 * do the free in the driver might seem like 'magic'.
945 *
946 * Arguments:
947 *       wlandev         ptr to the wlandev structure for the
948 *                       interface.
949 * Returns:
950 *       zero on success, non-zero otherwise.
951 * Call Context:
952 *       Should be process thread.  We'll assume it might be
953 *       interrupt though.  When we add support for statically
954 *       compiled drivers, this function will be called in the
955 *       context of the kernel startup code.
956 ----------------------------------------------------------------*/
957 int wlan_unsetup(wlandevice_t *wlandev)
958 {
959         int             result = 0;
960
961         DBFENTER;
962
963         tasklet_kill(&wlandev->rx_bh);
964
965         if (wlandev->netdev == NULL ) {
966                 WLAN_LOG_ERROR("called without wlandev->netdev set.\n");
967                 result = 1;
968         } else {
969                 free_netdev(wlandev->netdev);
970                 wlandev->netdev = NULL;
971         }
972
973         DBFEXIT;
974         return 0;
975 }
976
977
978
979 /*----------------------------------------------------------------
980 * register_wlandev
981 *
982 * Roughly matches the functionality of register_netdev.  This function
983 * is called after the driver has successfully probed and set up the
984 * resources for the device.  It's now ready to become a named device
985 * in the Linux system.
986 *
987 * First we allocate a name for the device (if not already set), then
988 * we call the Linux function register_netdevice.
989 *
990 * Arguments:
991 *       wlandev         ptr to the wlandev structure for the
992 *                       interface.
993 * Returns:
994 *       zero on success, non-zero otherwise.
995 * Call Context:
996 *       Can be either interrupt or not.
997 ----------------------------------------------------------------*/
998 int register_wlandev(wlandevice_t *wlandev)
999 {
1000         int             i = 0;
1001         netdevice_t     *dev = wlandev->netdev;
1002
1003         DBFENTER;
1004
1005         i = dev_alloc_name(wlandev->netdev, "wlan%d");
1006         if (i >= 0) {
1007                 i = register_netdev(wlandev->netdev);
1008         }
1009         if (i != 0) {
1010                 return -EIO;
1011         }
1012
1013         strcpy(wlandev->name, dev->name);
1014
1015 #ifdef CONFIG_PROC_FS
1016         if (proc_p80211) {
1017                 wlandev->procdir = proc_mkdir(wlandev->name, proc_p80211);
1018                 if ( wlandev->procdir )
1019                         wlandev->procwlandev =
1020                                 create_proc_read_entry("wlandev", 0,
1021                                                        wlandev->procdir,
1022                                                        p80211netdev_proc_read,
1023                                                        wlandev);
1024                 if (wlandev->nsd_proc_read)
1025                         create_proc_read_entry("nsd", 0,
1026                                                wlandev->procdir,
1027                                                wlandev->nsd_proc_read,
1028                                                wlandev);
1029         }
1030 #endif
1031
1032         DBFEXIT;
1033         return 0;
1034 }
1035
1036
1037 /*----------------------------------------------------------------
1038 * unregister_wlandev
1039 *
1040 * Roughly matches the functionality of unregister_netdev.  This
1041 * function is called to remove a named device from the system.
1042 *
1043 * First we tell linux that the device should no longer exist.
1044 * Then we remove it from the list of known wlan devices.
1045 *
1046 * Arguments:
1047 *       wlandev         ptr to the wlandev structure for the
1048 *                       interface.
1049 * Returns:
1050 *       zero on success, non-zero otherwise.
1051 * Call Context:
1052 *       Can be either interrupt or not.
1053 ----------------------------------------------------------------*/
1054 int unregister_wlandev(wlandevice_t *wlandev)
1055 {
1056         struct sk_buff *skb;
1057
1058         DBFENTER;
1059
1060 #ifdef CONFIG_PROC_FS
1061         if ( wlandev->procwlandev ) {
1062                 remove_proc_entry("wlandev", wlandev->procdir);
1063         }
1064         if ( wlandev->nsd_proc_read ) {
1065                 remove_proc_entry("nsd", wlandev->procdir);
1066         }
1067         if (wlandev->procdir) {
1068                 remove_proc_entry(wlandev->name, proc_p80211);
1069         }
1070 #endif
1071
1072         unregister_netdev(wlandev->netdev);
1073
1074         /* Now to clean out the rx queue */
1075         while ( (skb = skb_dequeue(&wlandev->nsd_rxq)) ) {
1076                 dev_kfree_skb(skb);
1077         }
1078
1079         DBFEXIT;
1080         return 0;
1081 }
1082
1083 #ifdef CONFIG_PROC_FS
1084 /*----------------------------------------------------------------
1085 * proc_read
1086 *
1087 * Read function for /proc/net/p80211/<device>/wlandev
1088 *
1089 * Arguments:
1090 *       buf
1091 *       start
1092 *       offset
1093 *       count
1094 *       eof
1095 *       data
1096 * Returns:
1097 *       zero on success, non-zero otherwise.
1098 * Call Context:
1099 *       Can be either interrupt or not.
1100 ----------------------------------------------------------------*/
1101 static int
1102 p80211netdev_proc_read(
1103         char    *page,
1104         char    **start,
1105         off_t   offset,
1106         int     count,
1107         int     *eof,
1108         void    *data)
1109 {
1110         char     *p = page;
1111         wlandevice_t *wlandev = (wlandevice_t *) data;
1112
1113         DBFENTER;
1114         if (offset != 0) {
1115                 *eof = 1;
1116                 goto exit;
1117         }
1118
1119         p += sprintf(p, "p80211 version: %s (%s)\n\n",
1120                      WLAN_RELEASE, WLAN_BUILD_DATE);
1121         p += sprintf(p, "name       : %s\n", wlandev->name);
1122         p += sprintf(p, "nsd name   : %s\n", wlandev->nsdname);
1123         p += sprintf(p, "address    : %02x:%02x:%02x:%02x:%02x:%02x\n",
1124                      wlandev->netdev->dev_addr[0], wlandev->netdev->dev_addr[1], wlandev->netdev->dev_addr[2],
1125                      wlandev->netdev->dev_addr[3], wlandev->netdev->dev_addr[4], wlandev->netdev->dev_addr[5]);
1126         p += sprintf(p, "nsd caps   : %s%s%s%s%s%s%s%s%s%s\n",
1127                      (wlandev->nsdcaps & P80211_NSDCAP_HARDWAREWEP) ? "wep_hw " : "",
1128                      (wlandev->nsdcaps & P80211_NSDCAP_TIEDWEP) ? "wep_tied " : "",
1129                      (wlandev->nsdcaps & P80211_NSDCAP_NOHOSTWEP) ? "wep_hw_only " : "",
1130                      (wlandev->nsdcaps & P80211_NSDCAP_PBCC) ? "pbcc " : "",
1131                      (wlandev->nsdcaps & P80211_NSDCAP_SHORT_PREAMBLE) ? "short_preamble " : "",
1132                      (wlandev->nsdcaps & P80211_NSDCAP_AGILITY) ? "agility " : "",
1133                      (wlandev->nsdcaps & P80211_NSDCAP_AP_RETRANSMIT) ? "ap_retransmit " : "",
1134                      (wlandev->nsdcaps & P80211_NSDCAP_HWFRAGMENT) ? "hw_frag " : "",
1135                      (wlandev->nsdcaps & P80211_NSDCAP_AUTOJOIN) ? "autojoin " : "",
1136                      (wlandev->nsdcaps & P80211_NSDCAP_NOSCAN) ? "" : "scan ");
1137
1138
1139         p += sprintf(p, "bssid      : %02x:%02x:%02x:%02x:%02x:%02x\n",
1140                      wlandev->bssid[0], wlandev->bssid[1], wlandev->bssid[2],
1141                      wlandev->bssid[3], wlandev->bssid[4], wlandev->bssid[5]);
1142
1143         p += sprintf(p, "Enabled    : %s%s\n",
1144                      (wlandev->shortpreamble) ? "short_preamble " : "",
1145                      (wlandev->hostwep & HOSTWEP_PRIVACYINVOKED) ? "privacy" : "");
1146
1147
1148  exit:
1149         DBFEXIT;
1150         return (p - page);
1151 }
1152 #endif
1153
1154 /*----------------------------------------------------------------
1155 * p80211netdev_hwremoved
1156 *
1157 * Hardware removed notification. This function should be called
1158 * immediately after an MSD has detected that the underlying hardware
1159 * has been yanked out from under us.  The primary things we need
1160 * to do are:
1161 *   - Mark the wlandev
1162 *   - Prevent any further traffic from the knetdev i/f
1163 *   - Prevent any further requests from mgmt i/f
1164 *   - If there are any waitq'd mgmt requests or mgmt-frame exchanges,
1165 *     shut them down.
1166 *   - Call the MSD hwremoved function.
1167 *
1168 * The remainder of the cleanup will be handled by unregister().
1169 * Our primary goal here is to prevent as much tickling of the MSD
1170 * as possible since the MSD is already in a 'wounded' state.
1171 *
1172 * TODO: As new features are added, this function should be
1173 *       updated.
1174 *
1175 * Arguments:
1176 *       wlandev         WLAN network device structure
1177 * Returns:
1178 *       nothing
1179 * Side effects:
1180 *
1181 * Call context:
1182 *       Usually interrupt.
1183 ----------------------------------------------------------------*/
1184 void p80211netdev_hwremoved(wlandevice_t *wlandev)
1185 {
1186         DBFENTER;
1187         wlandev->hwremoved = 1;
1188         if ( wlandev->state == WLAN_DEVICE_OPEN) {
1189                 p80211netdev_stop_queue(wlandev);
1190         }
1191
1192         netif_device_detach(wlandev->netdev);
1193
1194         DBFEXIT;
1195 }
1196
1197
1198 /*----------------------------------------------------------------
1199 * p80211_rx_typedrop
1200 *
1201 * Classifies the frame, increments the appropriate counter, and
1202 * returns 0|1|2 indicating whether the driver should handle, ignore, or
1203 * drop the frame
1204 *
1205 * Arguments:
1206 *       wlandev         wlan device structure
1207 *       fc              frame control field
1208 *
1209 * Returns:
1210 *       zero if the frame should be handled by the driver,
1211 *       one if the frame should be ignored
1212 *       anything else means we drop it.
1213 *
1214 * Side effects:
1215 *
1216 * Call context:
1217 *       interrupt
1218 ----------------------------------------------------------------*/
1219 static int p80211_rx_typedrop( wlandevice_t *wlandev, UINT16 fc)
1220 {
1221         UINT16  ftype;
1222         UINT16  fstype;
1223         int     drop = 0;
1224         /* Classify frame, increment counter */
1225         ftype = WLAN_GET_FC_FTYPE(fc);
1226         fstype = WLAN_GET_FC_FSTYPE(fc);
1227 #if 0
1228         WLAN_LOG_DEBUG(4,
1229                 "rx_typedrop : ftype=%d fstype=%d.\n", ftype, fstype);
1230 #endif
1231         switch ( ftype ) {
1232         case WLAN_FTYPE_MGMT:
1233                 if ((wlandev->netdev->flags & IFF_PROMISC) ||
1234                         (wlandev->netdev->flags & IFF_ALLMULTI)) {
1235                         drop = 1;
1236                         break;
1237                 }
1238                 WLAN_LOG_DEBUG(3, "rx'd mgmt:\n");
1239                 wlandev->rx.mgmt++;
1240                 switch( fstype ) {
1241                 case WLAN_FSTYPE_ASSOCREQ:
1242                         /* printk("assocreq"); */
1243                         wlandev->rx.assocreq++;
1244                         break;
1245                 case WLAN_FSTYPE_ASSOCRESP:
1246                         /* printk("assocresp"); */
1247                         wlandev->rx.assocresp++;
1248                         break;
1249                 case WLAN_FSTYPE_REASSOCREQ:
1250                         /* printk("reassocreq"); */
1251                         wlandev->rx.reassocreq++;
1252                         break;
1253                 case WLAN_FSTYPE_REASSOCRESP:
1254                         /* printk("reassocresp"); */
1255                         wlandev->rx.reassocresp++;
1256                         break;
1257                 case WLAN_FSTYPE_PROBEREQ:
1258                         /* printk("probereq"); */
1259                         wlandev->rx.probereq++;
1260                         break;
1261                 case WLAN_FSTYPE_PROBERESP:
1262                         /* printk("proberesp"); */
1263                         wlandev->rx.proberesp++;
1264                         break;
1265                 case WLAN_FSTYPE_BEACON:
1266                         /* printk("beacon"); */
1267                         wlandev->rx.beacon++;
1268                         break;
1269                 case WLAN_FSTYPE_ATIM:
1270                         /* printk("atim"); */
1271                         wlandev->rx.atim++;
1272                         break;
1273                 case WLAN_FSTYPE_DISASSOC:
1274                         /* printk("disassoc"); */
1275                         wlandev->rx.disassoc++;
1276                         break;
1277                 case WLAN_FSTYPE_AUTHEN:
1278                         /* printk("authen"); */
1279                         wlandev->rx.authen++;
1280                         break;
1281                 case WLAN_FSTYPE_DEAUTHEN:
1282                         /* printk("deauthen"); */
1283                         wlandev->rx.deauthen++;
1284                         break;
1285                 default:
1286                         /* printk("unknown"); */
1287                         wlandev->rx.mgmt_unknown++;
1288                         break;
1289                 }
1290                 /* printk("\n"); */
1291                 drop = 2;
1292                 break;
1293
1294         case WLAN_FTYPE_CTL:
1295                 if ((wlandev->netdev->flags & IFF_PROMISC) ||
1296                         (wlandev->netdev->flags & IFF_ALLMULTI)) {
1297                         drop = 1;
1298                         break;
1299                 }
1300                 WLAN_LOG_DEBUG(3, "rx'd ctl:\n");
1301                 wlandev->rx.ctl++;
1302                 switch( fstype ) {
1303                 case WLAN_FSTYPE_PSPOLL:
1304                         /* printk("pspoll"); */
1305                         wlandev->rx.pspoll++;
1306                         break;
1307                 case WLAN_FSTYPE_RTS:
1308                         /* printk("rts"); */
1309                         wlandev->rx.rts++;
1310                         break;
1311                 case WLAN_FSTYPE_CTS:
1312                         /* printk("cts"); */
1313                         wlandev->rx.cts++;
1314                         break;
1315                 case WLAN_FSTYPE_ACK:
1316                         /* printk("ack"); */
1317                         wlandev->rx.ack++;
1318                         break;
1319                 case WLAN_FSTYPE_CFEND:
1320                         /* printk("cfend"); */
1321                         wlandev->rx.cfend++;
1322                         break;
1323                 case WLAN_FSTYPE_CFENDCFACK:
1324                         /* printk("cfendcfack"); */
1325                         wlandev->rx.cfendcfack++;
1326                         break;
1327                 default:
1328                         /* printk("unknown"); */
1329                         wlandev->rx.ctl_unknown++;
1330                         break;
1331                 }
1332                 /* printk("\n"); */
1333                 drop = 2;
1334                 break;
1335
1336         case WLAN_FTYPE_DATA:
1337                 wlandev->rx.data++;
1338                 switch( fstype ) {
1339                 case WLAN_FSTYPE_DATAONLY:
1340                         wlandev->rx.dataonly++;
1341                         break;
1342                 case WLAN_FSTYPE_DATA_CFACK:
1343                         wlandev->rx.data_cfack++;
1344                         break;
1345                 case WLAN_FSTYPE_DATA_CFPOLL:
1346                         wlandev->rx.data_cfpoll++;
1347                         break;
1348                 case WLAN_FSTYPE_DATA_CFACK_CFPOLL:
1349                         wlandev->rx.data__cfack_cfpoll++;
1350                         break;
1351                 case WLAN_FSTYPE_NULL:
1352                         WLAN_LOG_DEBUG(3, "rx'd data:null\n");
1353                         wlandev->rx.null++;
1354                         break;
1355                 case WLAN_FSTYPE_CFACK:
1356                         WLAN_LOG_DEBUG(3, "rx'd data:cfack\n");
1357                         wlandev->rx.cfack++;
1358                         break;
1359                 case WLAN_FSTYPE_CFPOLL:
1360                         WLAN_LOG_DEBUG(3, "rx'd data:cfpoll\n");
1361                         wlandev->rx.cfpoll++;
1362                         break;
1363                 case WLAN_FSTYPE_CFACK_CFPOLL:
1364                         WLAN_LOG_DEBUG(3, "rx'd data:cfack_cfpoll\n");
1365                         wlandev->rx.cfack_cfpoll++;
1366                         break;
1367                 default:
1368                         /* printk("unknown"); */
1369                         wlandev->rx.data_unknown++;
1370                         break;
1371                 }
1372
1373                 break;
1374         }
1375         return drop;
1376 }
1377
1378
1379 void    p80211_suspend(wlandevice_t *wlandev)
1380 {
1381         DBFENTER;
1382
1383         DBFEXIT;
1384 }
1385
1386 void    p80211_resume(wlandevice_t *wlandev)
1387 {
1388         DBFENTER;
1389
1390         DBFEXIT;
1391 }
1392
1393 static void p80211knetdev_tx_timeout( netdevice_t *netdev)
1394 {
1395         wlandevice_t    *wlandev = netdev->ml_priv;
1396         DBFENTER;
1397
1398         if (wlandev->tx_timeout) {
1399                 wlandev->tx_timeout(wlandev);
1400         } else {
1401                 WLAN_LOG_WARNING("Implement tx_timeout for %s\n",
1402                                  wlandev->nsdname);
1403                 p80211netdev_wake_queue(wlandev);
1404         }
1405
1406         DBFEXIT;
1407 }