--- /dev/null
+/* 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 */