📄 wireless.c
字号:
{ if (v == SEQ_START_TOKEN) seq_printf(seq, "Inter-| sta-| Quality | Discarded " "packets | Missed | WE\n" " face | tus | link level noise | nwid " "crypt frag retry misc | beacon | %d\n", WIRELESS_EXT); else wireless_seq_printf_stats(seq, v); return 0;}extern void *dev_seq_start(struct seq_file *seq, loff_t *pos);extern void *dev_seq_next(struct seq_file *seq, void *v, loff_t *pos);extern void dev_seq_stop(struct seq_file *seq, void *v);static struct seq_operations wireless_seq_ops = { .start = dev_seq_start, .next = dev_seq_next, .stop = dev_seq_stop, .show = wireless_seq_show,};static int wireless_seq_open(struct inode *inode, struct file *file){ return seq_open(file, &wireless_seq_ops);}static struct file_operations wireless_seq_fops = { .owner = THIS_MODULE, .open = wireless_seq_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release,};int __init wireless_proc_init(void){ if (!proc_net_fops_create("wireless", S_IRUGO, &wireless_seq_fops)) return -ENOMEM; return 0;}#endif /* CONFIG_PROC_FS *//************************** IOCTL SUPPORT **************************//* * The original user space API to configure all those Wireless Extensions * is through IOCTLs. * In there, we check if we need to call the new driver API (iw_handler) * or just call the driver ioctl handler. *//* ---------------------------------------------------------------- *//* * Allow programatic access to /proc/net/wireless even if /proc * doesn't exist... Also more efficient... */static inline int dev_iwstats(struct net_device *dev, struct ifreq *ifr){ /* Get stats from the driver */ struct iw_statistics *stats; stats = get_wireless_stats(dev); if (stats != (struct iw_statistics *) NULL) { struct iwreq * wrq = (struct iwreq *)ifr; /* Copy statistics to the user buffer */ if(copy_to_user(wrq->u.data.pointer, stats, sizeof(struct iw_statistics))) return -EFAULT; /* Check if we need to clear the update flag */ if(wrq->u.data.flags != 0) stats->qual.updated = 0; return 0; } else return -EOPNOTSUPP;}/* ---------------------------------------------------------------- *//* * Export the driver private handler definition * They will be picked up by tools like iwpriv... */static inline int ioctl_export_private(struct net_device * dev, struct ifreq * ifr){ struct iwreq * iwr = (struct iwreq *) ifr; /* Check if the driver has something to export */ if((dev->wireless_handlers->num_private_args == 0) || (dev->wireless_handlers->private_args == NULL)) return -EOPNOTSUPP; /* Check NULL pointer */ if(iwr->u.data.pointer == NULL) return -EFAULT;#ifdef WE_STRICT_WRITE /* Check if there is enough buffer up there */ if(iwr->u.data.length < dev->wireless_handlers->num_private_args) { printk(KERN_ERR "%s (WE) : Buffer for request SIOCGIWPRIV too small (%d<%d)\n", dev->name, iwr->u.data.length, dev->wireless_handlers->num_private_args); return -E2BIG; }#endif /* WE_STRICT_WRITE */ /* Set the number of available ioctls. */ iwr->u.data.length = dev->wireless_handlers->num_private_args; /* Copy structure to the user buffer. */ if (copy_to_user(iwr->u.data.pointer, dev->wireless_handlers->private_args, sizeof(struct iw_priv_args) * iwr->u.data.length)) return -EFAULT; return 0;}/* ---------------------------------------------------------------- *//* * Wrapper to call a standard Wireless Extension handler. * We do various checks and also take care of moving data between * user space and kernel space. */static inline int ioctl_standard_call(struct net_device * dev, struct ifreq * ifr, unsigned int cmd, iw_handler handler){ struct iwreq * iwr = (struct iwreq *) ifr; const struct iw_ioctl_description * descr; struct iw_request_info info; int ret = -EINVAL; int user_size = 0; /* Get the description of the IOCTL */ if((cmd - SIOCIWFIRST) >= standard_ioctl_num) return -EOPNOTSUPP; descr = &(standard_ioctl[cmd - SIOCIWFIRST]);#ifdef WE_IOCTL_DEBUG printk(KERN_DEBUG "%s (WE) : Found standard handler for 0x%04X\n", ifr->ifr_name, cmd); printk(KERN_DEBUG "%s (WE) : Header type : %d, Token type : %d, size : %d, token : %d\n", dev->name, descr->header_type, descr->token_type, descr->token_size, descr->max_tokens);#endif /* WE_IOCTL_DEBUG */ /* Prepare the call */ info.cmd = cmd; info.flags = 0; /* Check if we have a pointer to user space data or not */ if(descr->header_type != IW_HEADER_TYPE_POINT) { /* No extra arguments. Trivial to handle */ ret = handler(dev, &info, &(iwr->u), NULL);#ifdef WE_SET_EVENT /* Generate an event to notify listeners of the change */ if((descr->flags & IW_DESCR_FLAG_EVENT) && ((ret == 0) || (ret == -EIWCOMMIT))) wireless_send_event(dev, cmd, &(iwr->u), NULL);#endif /* WE_SET_EVENT */ } else { char * extra; int err; /* Check what user space is giving us */ if(IW_IS_SET(cmd)) { /* Check NULL pointer */ if((iwr->u.data.pointer == NULL) && (iwr->u.data.length != 0)) return -EFAULT; /* Check if number of token fits within bounds */ if(iwr->u.data.length > descr->max_tokens) return -E2BIG; if(iwr->u.data.length < descr->min_tokens) return -EINVAL; } else { /* Check NULL pointer */ if(iwr->u.data.pointer == NULL) return -EFAULT; /* Save user space buffer size for checking */ user_size = iwr->u.data.length; }#ifdef WE_IOCTL_DEBUG printk(KERN_DEBUG "%s (WE) : Malloc %d bytes\n", dev->name, descr->max_tokens * descr->token_size);#endif /* WE_IOCTL_DEBUG */ /* Always allocate for max space. Easier, and won't last * long... */ extra = kmalloc(descr->max_tokens * descr->token_size, GFP_KERNEL); if (extra == NULL) { return -ENOMEM; } /* If it is a SET, get all the extra data in here */ if(IW_IS_SET(cmd) && (iwr->u.data.length != 0)) { err = copy_from_user(extra, iwr->u.data.pointer, iwr->u.data.length * descr->token_size); if (err) { kfree(extra); return -EFAULT; }#ifdef WE_IOCTL_DEBUG printk(KERN_DEBUG "%s (WE) : Got %d bytes\n", dev->name, iwr->u.data.length * descr->token_size);#endif /* WE_IOCTL_DEBUG */ } /* Call the handler */ ret = handler(dev, &info, &(iwr->u), extra); /* If we have something to return to the user */ if (!ret && IW_IS_GET(cmd)) {#ifdef WE_STRICT_WRITE /* Check if there is enough buffer up there */ if(user_size < iwr->u.data.length) { printk(KERN_ERR "%s (WE) : Buffer for request %04X too small (%d<%d)\n", dev->name, cmd, user_size, iwr->u.data.length); kfree(extra); return -E2BIG; }#endif /* WE_STRICT_WRITE */ err = copy_to_user(iwr->u.data.pointer, extra, iwr->u.data.length * descr->token_size); if (err) ret = -EFAULT; #ifdef WE_IOCTL_DEBUG printk(KERN_DEBUG "%s (WE) : Wrote %d bytes\n", dev->name, iwr->u.data.length * descr->token_size);#endif /* WE_IOCTL_DEBUG */ }#ifdef WE_SET_EVENT /* Generate an event to notify listeners of the change */ if((descr->flags & IW_DESCR_FLAG_EVENT) && ((ret == 0) || (ret == -EIWCOMMIT))) { if(descr->flags & IW_DESCR_FLAG_RESTRICT) /* If the event is restricted, don't * export the payload */ wireless_send_event(dev, cmd, &(iwr->u), NULL); else wireless_send_event(dev, cmd, &(iwr->u), extra); }#endif /* WE_SET_EVENT */ /* Cleanup - I told you it wasn't that long ;-) */ kfree(extra); } /* Call commit handler if needed and defined */ if(ret == -EIWCOMMIT) ret = call_commit_handler(dev); /* Here, we will generate the appropriate event if needed */ return ret;}/* ---------------------------------------------------------------- *//* * Wrapper to call a private Wireless Extension handler. * We do various checks and also take care of moving data between * user space and kernel space. * It's not as nice and slimline as the standard wrapper. The cause * is struct iw_priv_args, which was not really designed for the * job we are going here. * * IMPORTANT : This function prevent to set and get data on the same * IOCTL and enforce the SET/GET convention. Not doing it would be * far too hairy... * If you need to set and get data at the same time, please don't use * a iw_handler but process it in your ioctl handler (i.e. use the * old driver API). */static inline int ioctl_private_call(struct net_device * dev, struct ifreq * ifr, unsigned int cmd, iw_handler handler){ struct iwreq * iwr = (struct iwreq *) ifr; struct iw_priv_args * descr = NULL; struct iw_request_info info; int extra_size = 0; int i; int ret = -EINVAL; /* Get the description of the IOCTL */ for(i = 0; i < dev->wireless_handlers->num_private_args; i++) if(cmd == dev->wireless_handlers->private_args[i].cmd) { descr = &(dev->wireless_handlers->private_args[i]); break; }#ifdef WE_IOCTL_DEBUG printk(KERN_DEBUG "%s (WE) : Found private handler for 0x%04X\n", ifr->ifr_name, cmd); if(descr) { printk(KERN_DEBUG "%s (WE) : Name %s, set %X, get %X\n", dev->name, descr->name, descr->set_args, descr->get_args); }#endif /* WE_IOCTL_DEBUG */ /* Compute the size of the set/get arguments */ if(descr != NULL) { if(IW_IS_SET(cmd)) { int offset = 0; /* For sub-ioctls */ /* Check for sub-ioctl handler */ if(descr->name[0] == '\0') /* Reserve one int for sub-ioctl index */ offset = sizeof(__u32); /* Size of set arguments */ extra_size = get_priv_size(descr->set_args); /* Does it fits in iwr ? */ if((descr->set_args & IW_PRIV_SIZE_FIXED) && ((extra_size + offset) <= IFNAMSIZ)) extra_size = 0; } else { /* Size of set arguments */ extra_size = get_priv_size(descr->get_args); /* Does it fits in iwr ? */ if((descr->get_args & IW_PRIV_SIZE_FIXED) && (extra_size <= IFNAMSIZ)) extra_size = 0; } } /* Prepare the call */ info.cmd = cmd; info.flags = 0; /* Check if we have a pointer to user space data or not. */ if(extra_size == 0) { /* No extra arguments. Trivial to handle */ ret = handler(dev, &info, &(iwr->u), (char *) &(iwr->u)); } else { char * extra; int err; /* Check what user space is giving us */ if(IW_IS_SET(cmd)) { /* Check NULL pointer */ if((iwr->u.data.pointer == NULL) && (iwr->u.data.length != 0)) return -EFAULT; /* Does it fits within bounds ? */ if(iwr->u.data.length > (descr->set_args & IW_PRIV_SIZE_MASK)) return -E2BIG; } else { /* Check NULL pointer */ if(iwr->u.data.pointer == NULL) return -EFAULT; }#ifdef WE_IOCTL_DEBUG printk(KERN_DEBUG "%s (WE) : Malloc %d bytes\n", dev->name, extra_size);#endif /* WE_IOCTL_DEBUG */ /* Always allocate for max space. Easier, and won't last * long... */ extra = kmalloc(extra_size, GFP_KERNEL); if (extra == NULL) { return -ENOMEM; } /* If it is a SET, get all the extra data in here */ if(IW_IS_SET(cmd) && (iwr->u.data.length != 0)) { err = copy_from_user(extra, iwr->u.data.pointer, extra_size); if (err) { kfree(extra); return -EFAULT; }#ifdef WE_IOCTL_DEBUG printk(KERN_DEBUG "%s (WE) : Got %d elem\n", dev->name, iwr->u.data.length);#endif /* WE_IOCTL_DEBUG */ } /* Call the handler */ ret = handler(dev, &info, &(iwr->u), extra); /* If we have something to return to the user */ if (!ret && IW_IS_GET(cmd)) { err = copy_to_user(iwr->u.data.pointer, extra, extra_size); if (err) ret = -EFAULT; #ifdef WE_IOCTL_DEBUG printk(KERN_DEBUG "%s (WE) : Wrote %d elem\n", dev->name, iwr->u.data.length);#endif /* WE_IOCTL_DEBUG */ } /* Cleanup - I told you it wasn't that long ;-) */ kfree(extra); } /* Call commit handler if needed and defined */ if(ret == -EIWCOMMIT) ret = call_commit_handler(dev); return ret;}/* ---------------------------------------------------------------- *//* * Main IOCTl dispatcher. Called from the main networking code * (dev_ioctl() in net/core/dev.c). * Check the type of IOCTL and call the appropriate wrapper... */int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd){ struct net_device *dev; iw_handler handler; /* Permissions are already checked in dev_ioctl() before calling us. * The copy_to/from_user() of ifr is also dealt with in there */ /* Make sure the device exist */ if ((dev = __dev_get_by_name(ifr->ifr_name)) == NULL) return -ENODEV; /* A bunch of special cases, then the generic case... * Note that 'cmd' is already filtered in dev_ioctl() with * (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) */ switch(cmd) { case SIOCGIWSTATS: /* Get Wireless Stats */ return dev_iwstats(dev, ifr); case SIOCGIWPRIV: /* Check if we have some wireless handlers defined */ if(dev->wireless_handlers != NULL) { /* We export to user space the definition of * the private handler ourselves */ return ioctl_export_private(dev, ifr); } // ## Fall-through for old API ## default: /* Generic IOCTL */ /* Basic check */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -