/* 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 */