/********************************************************************************************************* ** 函数名称: ioctl_private_iw_point ** 功能描述: ioctl priv call ** 输 入 : ** 输 出 : OK or ERROR ** 全局变量: ** 调用模块: *********************************************************************************************************/ int ioctl_private_call (struct netif *dev, struct iwreq *iwr, unsigned int cmd, struct iw_request_info *info, iw_handler handler) { int extra_size = 0, ret = -EINVAL; const struct iw_priv_args *descr; extra_size = get_priv_descr_and_size(dev, cmd, &descr); /* 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 { ret = ioctl_private_iw_point(&iwr->u.data, cmd, descr, handler, dev, info, extra_size); } /* Call commit handler if needed and defined */ if (ret == -EIWCOMMIT) { ret = call_commit_handler(dev); } return (ret); }
/* * 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 int ioctl_standard_call(struct net_device * dev, struct iwreq *iwr, unsigned int cmd, struct iw_request_info *info, iw_handler handler) { const struct iw_ioctl_description * descr; int ret = -EINVAL; /* Get the description of the IOCTL */ if ((cmd - SIOCIWFIRST) >= standard_ioctl_num) return -EOPNOTSUPP; descr = &(standard_ioctl[cmd - SIOCIWFIRST]); /* 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); /* 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); } else { ret = ioctl_standard_iw_point(&iwr->u.data, cmd, descr, handler, dev, info); } /* 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; }
int compat_private_call(struct net_device *dev, struct iwreq *iwr, unsigned int cmd, struct iw_request_info *info, iw_handler handler) { const struct iw_priv_args *descr; int ret, extra_size; extra_size = get_priv_descr_and_size(dev, cmd, &descr); /* 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 { struct compat_iw_point *iwp_compat; struct iw_point iwp; iwp_compat = (struct compat_iw_point *) &iwr->u.data; iwp.pointer = compat_ptr(iwp_compat->pointer); iwp.length = iwp_compat->length; iwp.flags = iwp_compat->flags; ret = ioctl_private_iw_point(&iwp, cmd, descr, handler, dev, info, extra_size); iwp_compat->pointer = ptr_to_compat(iwp.pointer); iwp_compat->length = iwp.length; iwp_compat->flags = iwp.flags; } /* Call commit handler if needed and defined */ if (ret == -EIWCOMMIT) ret = call_commit_handler(dev); 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; }
/* * 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 standard Wireless Extension handler. * We do various checks and also take care of moving data between * user space and kernel space. */ static 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; /* Get the description of the IOCTL */ if ((cmd - SIOCIWFIRST) >= standard_ioctl_num) return -EOPNOTSUPP; descr = &(standard_ioctl[cmd - SIOCIWFIRST]); /* 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); /* 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); } else { char * extra; int extra_size; int user_length = 0; int err; int essid_compat = 0; /* Calculate space needed by arguments. Always allocate * for max space. Easier, and won't last long... */ extra_size = descr->max_tokens * descr->token_size; /* Check need for ESSID compatibility for WE < 21 */ switch (cmd) { case SIOCSIWESSID: case SIOCGIWESSID: case SIOCSIWNICKN: case SIOCGIWNICKN: if (iwr->u.data.length == descr->max_tokens + 1) essid_compat = 1; else if (IW_IS_SET(cmd) && (iwr->u.data.length != 0)) { char essid[IW_ESSID_MAX_SIZE + 1]; err = copy_from_user(essid, iwr->u.data.pointer, iwr->u.data.length * descr->token_size); if (err) return -EFAULT; if (essid[iwr->u.data.length - 1] == '\0') essid_compat = 1; } break; default: break; } iwr->u.data.length -= essid_compat; /* 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_length = iwr->u.data.length; /* Don't check if user_length > max to allow forward * compatibility. The test user_length < min is * implied by the test at the end. */ /* Support for very large requests */ if ((descr->flags & IW_DESCR_FLAG_NOMAX) && (user_length > descr->max_tokens)) { /* Allow userspace to GET more than max so * we can support any size GET requests. * There is still a limit : -ENOMEM. */ extra_size = user_length * descr->token_size; /* Note : user_length is originally a __u16, * and token_size is controlled by us, * so extra_size won't get negative and * won't overflow... */ } } /* Create the kernel buffer */ /* kzalloc ensures NULL-termination for essid_compat */ extra = kzalloc(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, iwr->u.data.length * descr->token_size); if (err) { kfree(extra); return -EFAULT; } } /* Call the handler */ ret = handler(dev, &info, &(iwr->u), extra); iwr->u.data.length += essid_compat; /* If we have something to return to the user */ if (!ret && IW_IS_GET(cmd)) { /* Check if there is enough buffer up there */ if (user_length < iwr->u.data.length) { kfree(extra); return -E2BIG; } err = copy_to_user(iwr->u.data.pointer, extra, iwr->u.data.length * descr->token_size); if (err) ret = -EFAULT; } /* 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); } /* 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 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; /* Get the description of the IOCTL */ descr = &(standard_ioctl[cmd - SIOCIWFIRST]); #ifdef WE_IOCTL_DEBUG printk(KERN_DEBUG "%s : Found standard handler for 0x%04X\n", ifr->ifr_name, cmd); printk(KERN_DEBUG "Header type : %d, token type : %d, token_size : %d, max_token : %d\n", 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); } 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; #ifdef WE_STRICT_WRITE /* Check if there is enough buffer up there */ if(iwr->u.data.length < descr->max_tokens) return -E2BIG; #endif /* WE_STRICT_WRITE */ } #ifdef WE_IOCTL_DEBUG printk(KERN_DEBUG "Malloc %d bytes\n", 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 "Got %d bytes\n", 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)) { 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 "Wrote %d bytes\n", iwr->u.data.length * descr->token_size); #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); /* Here, we will generate the appropriate event if needed */ return ret; }