nexmon – Rev 1

Subversion Repositories:
Rev:
/* Note : this particular snipset of code is available under
 * the LGPL, MPL or BSD license (at your choice).
 * Jean II
 */

// Require Wireless Tools 25 for sub-ioctl and addr support

/* --------------------------- INCLUDE --------------------------- */

#if WIRELESS_EXT <= 12
/* Wireless extensions backward compatibility */

/* We need the full definition for private ioctls */
struct iw_request_info
{
        __u16           cmd;            /* Wireless Extension command */
        __u16           flags;          /* More to come ;-) */
};
#endif /* WIRELESS_EXT <= 12 */

#ifndef IW_PRIV_TYPE_ADDR
#define IW_PRIV_TYPE_ADDR       0x6000
#endif  /* IW_PRIV_TYPE_ADDR */

/* --------------------------- HANDLERS --------------------------- */

/* First method : using sub-ioctls.
 * Note that sizeof(int + struct sockaddr) = 20 > 16, therefore the
 * data is passed in (char *) extra, and sub-ioctl in data->flags. */
static int sample_ioctl_set_mac(struct net_device *dev,
                                struct iw_request_info *info,
                                struct iw_point *data,
                                struct sockaddr *mac_addr)
{
        unsigned char * addr = (char *) &mac_addr->sa_data;

        switch(data->flags) {
        case 0:
                printk(KERN_DEBUG "%s: mac_add %02X:%02X:%02X:%02X:%02X:%02X\n", dev->name, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
                break;
        case 1:
                printk(KERN_DEBUG "%s: mac_del %02X:%02X:%02X:%02X:%02X:%02X\n", dev->name, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
                break;
        case 2:
                printk(KERN_DEBUG "%s: mac_kick %02X:%02X:%02X:%02X:%02X:%02X\n", dev->name, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
                break;
        default:
                printk(KERN_DEBUG "%s: mac_undefined %02X:%02X:%02X:%02X:%02X:%02X\n", dev->name, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
                break;
        }

        return 0;
}

/* Second method : bind single handler to multiple ioctls.
 * Note that sizeof(struct sockaddr) = 16 <= 16, therefore the
 * data is passed in (struct iwreq) (and also mapped in extra).
 */
static int sample_ioctl_set_addr(struct net_device *dev,
                                 struct iw_request_info *info,
                                 struct sockaddr *mac_addr, char *extra)
{
        unsigned char * addr = (char *) &mac_addr->sa_data;

        switch(info->cmd) {
        case SIOCIWFIRSTPRIV + 28:
                printk(KERN_DEBUG "%s: addr_add %02X:%02X:%02X:%02X:%02X:%02X\n", dev->name, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
                break;
        case SIOCIWFIRSTPRIV + 30:
                printk(KERN_DEBUG "%s: addr_del %02X:%02X:%02X:%02X:%02X:%02X\n", dev->name, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
                break;
        default:
                printk(KERN_DEBUG "%s: mac_undefined %02X:%02X:%02X:%02X:%02X:%02X\n", dev->name, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
                break;
        }

        return 0;
}

// Extra fun for testing
static int sample_ioctl_get_mac(struct net_device *dev,
                                struct iw_request_info *info,
                                struct iw_point *data,
                                struct sockaddr *mac_addr)
{
        unsigned char   fake_addr[6];
        int             i;
        int             j;

        for(i = 0; i < 16; i++) {
                /* Create a fake address */
                for(j = 0; j < 6; j++)
                        fake_addr[j] = (unsigned char) ((j << 4) + i);
                /* Put in in the table */
                memcpy(&(mac_addr[i]).sa_data, fake_addr, ETH_ALEN);
                mac_addr[i].sa_family = ARPHRD_ETHER;
        }
        data->length = 16;

        return 0;
}

static int sample_ioctl_set_float(struct net_device *dev,
                                  struct iw_request_info *info,
                                  struct iw_freq *freq, char *extra)
{
        printk(KERN_DEBUG "%s: set_float %d;%d\n",
               dev->name, freq->m, freq->e);

        return 0;
}

/* --------------------------- BINDING --------------------------- */

static const struct iw_priv_args sample_priv[] = {
        // *** Method 1 : using sub-ioctls ***
        /* --- sub-ioctls handler --- */
        { SIOCIWFIRSTPRIV + 0,
          IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "" },
        /* --- sub-ioctls definitions --- */
        { 0,
          IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "macadd" },
        { 1,
          IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "macdel" },
        { 2,
          IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "mackick" },
        // *** Method 2 : binding one handler to multiple ioctls ***
        { SIOCIWFIRSTPRIV + 2,
          IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "addradd" },
        { SIOCIWFIRSTPRIV + 4,
          IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "addrdel" },
        // *** Extra fun ***
        { SIOCIWFIRSTPRIV + 1,
          0, IW_PRIV_TYPE_ADDR | 16, "macget" },
        { SIOCIWFIRSTPRIV + 6,
          IW_PRIV_TYPE_FLOAT | IW_PRIV_SIZE_FIXED | 1, 0, "setfloat" },
};

static const iw_handler sample_private_handler[] =
{                                                       /* SIOCIWFIRSTPRIV + */
#if WIRELESS_EXT >= 15
        /* Various little annoying bugs in the new API before
         * version 15 make it difficult to use the new API for those ioctls.
         * For example, it doesn't know about the new data type.
         * Rather than littering the code with workarounds,
         * let's use the regular ioctl handler. - Jean II */
        (iw_handler) sample_ioctl_set_mac,              /* 0 */
        (iw_handler) sample_ioctl_get_mac,              /* 1 */
        (iw_handler) sample_ioctl_set_addr,             /* 2 */
        (iw_handler) NULL,                              /* 3 */
        (iw_handler) sample_ioctl_set_addr,             /* 4 */
        (iw_handler) NULL,                              /* 5 */
        (iw_handler) sample_ioctl_set_float,            /* 6 */
#endif  /* WIRELESS_EXT >= 15 */
};

#if WIRELESS_EXT < 15
                /* Various little annoying bugs in the new API before
                 * version 15 make it difficult to use those ioctls.
                 * For example, it doesn't know about the new data type.
                 * Rather than littering the code with workarounds,
                 * let's use this code that just works. - Jean II */
        case SIOCIWFIRSTPRIV + 0:
                if (wrq->u.data.length > 1)
                        ret = -E2BIG;
                else if (wrq->u.data.pointer) {
                        struct sockaddr mac_addr;
                        if (copy_from_user(&mac_addr, wrq->u.data.pointer,
                                           sizeof(struct sockaddr))) {
                                ret = -EFAULT;
                                break;
                        }
                        ret = sample_ioctl_set_mac(dev, NULL, &wrq->u.data,
                                                   &mac_addr);
                }
                break;
        case SIOCIWFIRSTPRIV + 2:
        case SIOCIWFIRSTPRIV + 4:
                if (!capable(CAP_NET_ADMIN))
                        ret = -EPERM;
                else {
                        struct iw_request_info info;
                        info.cmd = cmd;
                        ret = sample_ioctl_set_addr(dev, &info,
                                                    &wrq->u.ap_addr,
                                                    NULL);
                }
                break;
        case SIOCIWFIRSTPRIV + 1:
                if (wrq->u.essid.pointer) {
                        struct sockaddr mac_addr[16];
                        char nickbuf[IW_ESSID_MAX_SIZE + 1];
                        ret = sample_ioctl_get_mac(dev, NULL, &wrq->u.data,
                                                   mac_addr);
                        if (copy_to_user(wrq->u.data.pointer, nickbuf,
                                         wrq->u.data.length *
                                         sizeof(struct sockaddr)))
                                ret = -EFAULT;
                }
                break;
        case SIOCIWFIRSTPRIV + 6:
                if (!capable(CAP_NET_ADMIN))
                        ret = -EPERM;
                else {
                        ret = sample_ioctl_set_float(dev, NULL,
                                                     &wrq->u.freq,
                                                     NULL);
                }
                break;
#endif  /* WIRELESS_EXT < 15 */