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