This source file includes following definitions.
- iw_handler_get_private
- get_priv_size
- adjust_priv_size
- get_priv_descr_and_size
- ioctl_private_iw_point
- ioctl_private_call
- compat_private_call
   1 
   2 
   3 
   4 
   5 
   6 
   7 
   8 
   9 
  10 #include <linux/slab.h>
  11 #include <linux/wireless.h>
  12 #include <linux/netdevice.h>
  13 #include <net/iw_handler.h>
  14 #include <net/wext.h>
  15 
  16 int iw_handler_get_private(struct net_device *          dev,
  17                            struct iw_request_info *     info,
  18                            union iwreq_data *           wrqu,
  19                            char *                       extra)
  20 {
  21         
  22         if ((dev->wireless_handlers->num_private_args == 0) ||
  23            (dev->wireless_handlers->private_args == NULL))
  24                 return -EOPNOTSUPP;
  25 
  26         
  27         if (wrqu->data.length < dev->wireless_handlers->num_private_args) {
  28                 
  29 
  30 
  31                 wrqu->data.length = dev->wireless_handlers->num_private_args;
  32                 return -E2BIG;
  33         }
  34 
  35         
  36         wrqu->data.length = dev->wireless_handlers->num_private_args;
  37 
  38         
  39         memcpy(extra, dev->wireless_handlers->private_args,
  40                sizeof(struct iw_priv_args) * wrqu->data.length);
  41 
  42         return 0;
  43 }
  44 
  45 
  46 static const char iw_priv_type_size[] = {
  47         0,                              
  48         1,                              
  49         1,                              
  50         0,                              
  51         sizeof(__u32),                  
  52         sizeof(struct iw_freq),         
  53         sizeof(struct sockaddr),        
  54         0,                              
  55 };
  56 
  57 static int get_priv_size(__u16 args)
  58 {
  59         int     num = args & IW_PRIV_SIZE_MASK;
  60         int     type = (args & IW_PRIV_TYPE_MASK) >> 12;
  61 
  62         return num * iw_priv_type_size[type];
  63 }
  64 
  65 static int adjust_priv_size(__u16 args, struct iw_point *iwp)
  66 {
  67         int     num = iwp->length;
  68         int     max = args & IW_PRIV_SIZE_MASK;
  69         int     type = (args & IW_PRIV_TYPE_MASK) >> 12;
  70 
  71         
  72         if (max < num)
  73                 num = max;
  74 
  75         return num * iw_priv_type_size[type];
  76 }
  77 
  78 
  79 
  80 
  81 
  82 
  83 
  84 
  85 
  86 
  87 
  88 
  89 
  90 
  91 
  92 
  93 static int get_priv_descr_and_size(struct net_device *dev, unsigned int cmd,
  94                                    const struct iw_priv_args **descrp)
  95 {
  96         const struct iw_priv_args *descr;
  97         int i, extra_size;
  98 
  99         descr = NULL;
 100         for (i = 0; i < dev->wireless_handlers->num_private_args; i++) {
 101                 if (cmd == dev->wireless_handlers->private_args[i].cmd) {
 102                         descr = &dev->wireless_handlers->private_args[i];
 103                         break;
 104                 }
 105         }
 106 
 107         extra_size = 0;
 108         if (descr) {
 109                 if (IW_IS_SET(cmd)) {
 110                         int     offset = 0;     
 111                         
 112                         if (descr->name[0] == '\0')
 113                                 
 114                                 offset = sizeof(__u32);
 115 
 116                         
 117                         extra_size = get_priv_size(descr->set_args);
 118 
 119                         
 120                         if ((descr->set_args & IW_PRIV_SIZE_FIXED) &&
 121                            ((extra_size + offset) <= IFNAMSIZ))
 122                                 extra_size = 0;
 123                 } else {
 124                         
 125                         extra_size = get_priv_size(descr->get_args);
 126 
 127                         
 128                         if ((descr->get_args & IW_PRIV_SIZE_FIXED) &&
 129                            (extra_size <= IFNAMSIZ))
 130                                 extra_size = 0;
 131                 }
 132         }
 133         *descrp = descr;
 134         return extra_size;
 135 }
 136 
 137 static int ioctl_private_iw_point(struct iw_point *iwp, unsigned int cmd,
 138                                   const struct iw_priv_args *descr,
 139                                   iw_handler handler, struct net_device *dev,
 140                                   struct iw_request_info *info, int extra_size)
 141 {
 142         char *extra;
 143         int err;
 144 
 145         
 146         if (IW_IS_SET(cmd)) {
 147                 if (!iwp->pointer && iwp->length != 0)
 148                         return -EFAULT;
 149 
 150                 if (iwp->length > (descr->set_args & IW_PRIV_SIZE_MASK))
 151                         return -E2BIG;
 152         } else if (!iwp->pointer)
 153                 return -EFAULT;
 154 
 155         extra = kzalloc(extra_size, GFP_KERNEL);
 156         if (!extra)
 157                 return -ENOMEM;
 158 
 159         
 160         if (IW_IS_SET(cmd) && (iwp->length != 0)) {
 161                 if (copy_from_user(extra, iwp->pointer, extra_size)) {
 162                         err = -EFAULT;
 163                         goto out;
 164                 }
 165         }
 166 
 167         
 168         err = handler(dev, info, (union iwreq_data *) iwp, extra);
 169 
 170         
 171         if (!err && IW_IS_GET(cmd)) {
 172                 
 173 
 174 
 175                 if (!(descr->get_args & IW_PRIV_SIZE_FIXED))
 176                         extra_size = adjust_priv_size(descr->get_args, iwp);
 177 
 178                 if (copy_to_user(iwp->pointer, extra, extra_size))
 179                         err =  -EFAULT;
 180         }
 181 
 182 out:
 183         kfree(extra);
 184         return err;
 185 }
 186 
 187 int ioctl_private_call(struct net_device *dev, struct iwreq *iwr,
 188                        unsigned int cmd, struct iw_request_info *info,
 189                        iw_handler handler)
 190 {
 191         int extra_size = 0, ret = -EINVAL;
 192         const struct iw_priv_args *descr;
 193 
 194         extra_size = get_priv_descr_and_size(dev, cmd, &descr);
 195 
 196         
 197         if (extra_size == 0) {
 198                 
 199                 ret = handler(dev, info, &(iwr->u), (char *) &(iwr->u));
 200         } else {
 201                 ret = ioctl_private_iw_point(&iwr->u.data, cmd, descr,
 202                                              handler, dev, info, extra_size);
 203         }
 204 
 205         
 206         if (ret == -EIWCOMMIT)
 207                 ret = call_commit_handler(dev);
 208 
 209         return ret;
 210 }
 211 
 212 #ifdef CONFIG_COMPAT
 213 int compat_private_call(struct net_device *dev, struct iwreq *iwr,
 214                         unsigned int cmd, struct iw_request_info *info,
 215                         iw_handler handler)
 216 {
 217         const struct iw_priv_args *descr;
 218         int ret, extra_size;
 219 
 220         extra_size = get_priv_descr_and_size(dev, cmd, &descr);
 221 
 222         
 223         if (extra_size == 0) {
 224                 
 225                 ret = handler(dev, info, &(iwr->u), (char *) &(iwr->u));
 226         } else {
 227                 struct compat_iw_point *iwp_compat;
 228                 struct iw_point iwp;
 229 
 230                 iwp_compat = (struct compat_iw_point *) &iwr->u.data;
 231                 iwp.pointer = compat_ptr(iwp_compat->pointer);
 232                 iwp.length = iwp_compat->length;
 233                 iwp.flags = iwp_compat->flags;
 234 
 235                 ret = ioctl_private_iw_point(&iwp, cmd, descr,
 236                                              handler, dev, info, extra_size);
 237 
 238                 iwp_compat->pointer = ptr_to_compat(iwp.pointer);
 239                 iwp_compat->length = iwp.length;
 240                 iwp_compat->flags = iwp.flags;
 241         }
 242 
 243         
 244         if (ret == -EIWCOMMIT)
 245                 ret = call_commit_handler(dev);
 246 
 247         return ret;
 248 }
 249 #endif