wireless.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:29k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * This file implement the Wireless Extensions APIs.
  3.  *
  4.  * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
  5.  * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved.
  6.  *
  7.  * (As all part of the Linux kernel, this file is GPL)
  8.  */
  9. /************************** DOCUMENTATION **************************/
  10. /*
  11.  * API definition :
  12.  * --------------
  13.  * See <linux/wireless.h> for details of the APIs and the rest.
  14.  *
  15.  * History :
  16.  * -------
  17.  *
  18.  * v1 - 5.12.01 - Jean II
  19.  * o Created this file.
  20.  *
  21.  * v2 - 13.12.01 - Jean II
  22.  * o Move /proc/net/wireless stuff from net/core/dev.c to here
  23.  * o Make Wireless Extension IOCTLs go through here
  24.  * o Added iw_handler handling ;-)
  25.  * o Added standard ioctl description
  26.  * o Initial dumb commit strategy based on orinoco.c
  27.  *
  28.  * v3 - 19.12.01 - Jean II
  29.  * o Make sure we don't go out of standard_ioctl[] in ioctl_standard_call
  30.  * o Add event dispatcher function
  31.  * o Add event description
  32.  * o Propagate events as rtnetlink IFLA_WIRELESS option
  33.  * o Generate event on selected SET requests
  34.  *
  35.  * v4 - 18.04.01 - Jean II
  36.  * o Fix stupid off by one in iw_ioctl_description : IW_ESSID_MAX_SIZE + 1
  37.  */
  38. /***************************** INCLUDES *****************************/
  39. #include <asm/uaccess.h> /* copy_to_user() */
  40. #include <linux/config.h> /* Not needed ??? */
  41. #include <linux/types.h> /* off_t */
  42. #include <linux/netdevice.h> /* struct ifreq, dev_get_by_name() */
  43. #include <linux/rtnetlink.h> /* rtnetlink stuff */
  44. #include <linux/wireless.h> /* Pretty obvious */
  45. #include <net/iw_handler.h> /* New driver API */
  46. /**************************** CONSTANTS ****************************/
  47. /* This will be turned on later on... */
  48. #undef WE_STRICT_WRITE /* Check write buffer size */
  49. /* Debuging stuff */
  50. #undef WE_IOCTL_DEBUG /* Debug IOCTL API */
  51. #undef WE_EVENT_DEBUG /* Debug Event dispatcher */
  52. /* Options */
  53. #define WE_EVENT_NETLINK /* Propagate events using rtnetlink */
  54. #define WE_SET_EVENT /* Generate an event on some set commands */
  55. /************************* GLOBAL VARIABLES *************************/
  56. /*
  57.  * You should not use global variables, because or re-entrancy.
  58.  * On our case, it's only const, so it's OK...
  59.  */
  60. /*
  61.  * Meta-data about all the standard Wireless Extension request we
  62.  * know about.
  63.  */
  64. static const struct iw_ioctl_description standard_ioctl[] = {
  65. /* SIOCSIWCOMMIT */
  66. { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
  67. /* SIOCGIWNAME */
  68. { IW_HEADER_TYPE_CHAR, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
  69. /* SIOCSIWNWID */
  70. { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, IW_DESCR_FLAG_EVENT},
  71. /* SIOCGIWNWID */
  72. { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
  73. /* SIOCSIWFREQ */
  74. { IW_HEADER_TYPE_FREQ, 0, 0, 0, 0, IW_DESCR_FLAG_EVENT},
  75. /* SIOCGIWFREQ */
  76. { IW_HEADER_TYPE_FREQ, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
  77. /* SIOCSIWMODE */
  78. { IW_HEADER_TYPE_UINT, 0, 0, 0, 0, IW_DESCR_FLAG_EVENT},
  79. /* SIOCGIWMODE */
  80. { IW_HEADER_TYPE_UINT, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
  81. /* SIOCSIWSENS */
  82. { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
  83. /* SIOCGIWSENS */
  84. { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
  85. /* SIOCSIWRANGE */
  86. { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
  87. /* SIOCGIWRANGE */
  88. { IW_HEADER_TYPE_POINT, 0, 1, 0, sizeof(struct iw_range), IW_DESCR_FLAG_DUMP},
  89. /* SIOCSIWPRIV */
  90. { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
  91. /* SIOCGIWPRIV (handled directly by us) */
  92. { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
  93. /* SIOCSIWSTATS */
  94. { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
  95. /* SIOCGIWSTATS (handled directly by us) */
  96. { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
  97. /* SIOCSIWSPY */
  98. { IW_HEADER_TYPE_POINT, 0, sizeof(struct sockaddr), 0, IW_MAX_SPY, 0},
  99. /* SIOCGIWSPY */
  100. { IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_SPY, 0},
  101. /* -- hole -- */
  102. { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
  103. /* -- hole -- */
  104. { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
  105. /* SIOCSIWAP */
  106. { IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0},
  107. /* SIOCGIWAP */
  108. { IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
  109. /* -- hole -- */
  110. { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
  111. /* SIOCGIWAPLIST */
  112. { IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_AP, 0},
  113. /* SIOCSIWSCAN */
  114. { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
  115. /* SIOCGIWSCAN */
  116. { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_SCAN_MAX_DATA, 0},
  117. /* SIOCSIWESSID */
  118. { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, IW_DESCR_FLAG_EVENT},
  119. /* SIOCGIWESSID */
  120. { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, IW_DESCR_FLAG_DUMP},
  121. /* SIOCSIWNICKN */
  122. { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, 0},
  123. /* SIOCGIWNICKN */
  124. { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, 0},
  125. /* -- hole -- */
  126. { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
  127. /* -- hole -- */
  128. { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
  129. /* SIOCSIWRATE */
  130. { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
  131. /* SIOCGIWRATE */
  132. { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
  133. /* SIOCSIWRTS */
  134. { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
  135. /* SIOCGIWRTS */
  136. { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
  137. /* SIOCSIWFRAG */
  138. { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
  139. /* SIOCGIWFRAG */
  140. { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
  141. /* SIOCSIWTXPOW */
  142. { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
  143. /* SIOCGIWTXPOW */
  144. { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
  145. /* SIOCSIWRETRY */
  146. { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
  147. /* SIOCGIWRETRY */
  148. { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
  149. /* SIOCSIWENCODE */
  150. { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT},
  151. /* SIOCGIWENCODE */
  152. { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_DUMP | IW_DESCR_FLAG_RESTRICT},
  153. /* SIOCSIWPOWER */
  154. { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
  155. /* SIOCGIWPOWER */
  156. { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
  157. };
  158. static const int standard_ioctl_num = (sizeof(standard_ioctl) /
  159.        sizeof(struct iw_ioctl_description));
  160. /*
  161.  * Meta-data about all the additional standard Wireless Extension events
  162.  * we know about.
  163.  */
  164. static const struct iw_ioctl_description standard_event[] = {
  165. /* IWEVTXDROP */
  166. { IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0},
  167. /* IWEVQUAL */
  168. { IW_HEADER_TYPE_QUAL, 0, 0, 0, 0, 0},
  169. };
  170. static const int standard_event_num = (sizeof(standard_event) /
  171.        sizeof(struct iw_ioctl_description));
  172. /* Size (in bytes) of the various private data types */
  173. static const char priv_type_size[] = { 0, 1, 1, 0, 4, 4, 0, 0 };
  174. /* Size (in bytes) of various events */
  175. static const int event_type_size[] = {
  176. IW_EV_LCP_LEN,
  177. 0,
  178. IW_EV_CHAR_LEN,
  179. 0,
  180. IW_EV_UINT_LEN,
  181. IW_EV_FREQ_LEN,
  182. IW_EV_POINT_LEN, /* Without variable payload */
  183. IW_EV_PARAM_LEN,
  184. IW_EV_ADDR_LEN,
  185. IW_EV_QUAL_LEN,
  186. };
  187. /************************ COMMON SUBROUTINES ************************/
  188. /*
  189.  * Stuff that may be used in various place or doesn't fit in one
  190.  * of the section below.
  191.  */
  192. /* ---------------------------------------------------------------- */
  193. /*
  194.  * Return the driver handler associated with a specific Wireless Extension.
  195.  * Called from various place, so make sure it remains efficient.
  196.  */
  197. static inline iw_handler get_handler(struct net_device *dev,
  198.      unsigned int cmd)
  199. {
  200. /* Don't "optimise" the following variable, it will crash */
  201. unsigned int index; /* *MUST* be unsigned */
  202. /* Check if we have some wireless handlers defined */
  203. if(dev->wireless_handlers == NULL)
  204. return NULL;
  205. /* Try as a standard command */
  206. index = cmd - SIOCIWFIRST;
  207. if(index < dev->wireless_handlers->num_standard)
  208. return dev->wireless_handlers->standard[index];
  209. /* Try as a private command */
  210. index = cmd - SIOCIWFIRSTPRIV;
  211. if(index < dev->wireless_handlers->num_private)
  212. return dev->wireless_handlers->private[index];
  213. /* Not found */
  214. return NULL;
  215. }
  216. /* ---------------------------------------------------------------- */
  217. /*
  218.  * Get statistics out of the driver
  219.  */
  220. static inline struct iw_statistics *get_wireless_stats(struct net_device *dev)
  221. {
  222. return (dev->get_wireless_stats ?
  223. dev->get_wireless_stats(dev) :
  224. (struct iw_statistics *) NULL);
  225. /* In the future, get_wireless_stats may move from 'struct net_device'
  226.  * to 'struct iw_handler_def', to de-bloat struct net_device.
  227.  * Definitely worse a thought... */
  228. }
  229. /* ---------------------------------------------------------------- */
  230. /*
  231.  * Call the commit handler in the driver
  232.  * (if exist and if conditions are right)
  233.  *
  234.  * Note : our current commit strategy is currently pretty dumb,
  235.  * but we will be able to improve on that...
  236.  * The goal is to try to agreagate as many changes as possible
  237.  * before doing the commit. Drivers that will define a commit handler
  238.  * are usually those that need a reset after changing parameters, so
  239.  * we want to minimise the number of reset.
  240.  * A cool idea is to use a timer : at each "set" command, we re-set the
  241.  * timer, when the timer eventually fires, we call the driver.
  242.  * Hopefully, more on that later.
  243.  *
  244.  * Also, I'm waiting to see how many people will complain about the
  245.  * netif_running(dev) test. I'm open on that one...
  246.  * Hopefully, the driver will remember to do a commit in "open()" ;-)
  247.  */
  248. static inline int call_commit_handler(struct net_device * dev)
  249. {
  250. if((netif_running(dev)) &&
  251.    (dev->wireless_handlers->standard[0] != NULL)) {
  252. /* Call the commit handler on the driver */
  253. return dev->wireless_handlers->standard[0](dev, NULL,
  254.    NULL, NULL);
  255. } else
  256. return 0; /* Command completed successfully */
  257. }
  258. /* ---------------------------------------------------------------- */
  259. /*
  260.  * Number of private arguments
  261.  */
  262. static inline int get_priv_size(__u16 args)
  263. {
  264. int num = args & IW_PRIV_SIZE_MASK;
  265. int type = (args & IW_PRIV_TYPE_MASK) >> 12;
  266. return num * priv_type_size[type];
  267. }
  268. /******************** /proc/net/wireless SUPPORT ********************/
  269. /*
  270.  * The /proc/net/wireless file is a human readable user-space interface
  271.  * exporting various wireless specific statistics from the wireless devices.
  272.  * This is the most popular part of the Wireless Extensions ;-)
  273.  *
  274.  * This interface is a pure clone of /proc/net/dev (in net/core/dev.c).
  275.  * The content of the file is basically the content of "struct iw_statistics".
  276.  */
  277. #ifdef CONFIG_PROC_FS
  278. /* ---------------------------------------------------------------- */
  279. /*
  280.  * Print one entry (line) of /proc/net/wireless
  281.  */
  282. static inline int sprintf_wireless_stats(char *buffer, struct net_device *dev)
  283. {
  284. /* Get stats from the driver */
  285. struct iw_statistics *stats;
  286. int size;
  287. stats = get_wireless_stats(dev);
  288. if (stats != (struct iw_statistics *) NULL) {
  289. size = sprintf(buffer,
  290.        "%6s: %04x  %3d%c  %3d%c  %3d%c  %6d %6d %6d %6d %6d   %6dn",
  291.        dev->name,
  292.        stats->status,
  293.        stats->qual.qual,
  294.        stats->qual.updated & 1 ? '.' : ' ',
  295.        ((__u8) stats->qual.level),
  296.        stats->qual.updated & 2 ? '.' : ' ',
  297.        ((__u8) stats->qual.noise),
  298.        stats->qual.updated & 4 ? '.' : ' ',
  299.        stats->discard.nwid,
  300.        stats->discard.code,
  301.        stats->discard.fragment,
  302.        stats->discard.retries,
  303.        stats->discard.misc,
  304.        stats->miss.beacon);
  305. stats->qual.updated = 0;
  306. }
  307. else
  308. size = 0;
  309. return size;
  310. }
  311. /* ---------------------------------------------------------------- */
  312. /*
  313.  * Print info for /proc/net/wireless (print all entries)
  314.  */
  315. int dev_get_wireless_info(char * buffer, char **start, off_t offset,
  316.   int length)
  317. {
  318. int len = 0;
  319. off_t begin = 0;
  320. off_t pos = 0;
  321. int size;
  322. struct net_device * dev;
  323. size = sprintf(buffer,
  324.        "Inter-| sta-|   Quality        |   Discarded packets               | Missedn"
  325.        " face | tus | link level noise |  nwid  crypt   frag  retry   misc | beaconn"
  326. );
  327. pos += size;
  328. len += size;
  329. read_lock(&dev_base_lock);
  330. for (dev = dev_base; dev != NULL; dev = dev->next) {
  331. size = sprintf_wireless_stats(buffer + len, dev);
  332. len += size;
  333. pos = begin + len;
  334. if (pos < offset) {
  335. len = 0;
  336. begin = pos;
  337. }
  338. if (pos > offset + length)
  339. break;
  340. }
  341. read_unlock(&dev_base_lock);
  342. *start = buffer + (offset - begin); /* Start of wanted data */
  343. len -= (offset - begin); /* Start slop */
  344. if (len > length)
  345. len = length; /* Ending slop */
  346. if (len < 0)
  347. len = 0;
  348. return len;
  349. }
  350. #endif /* CONFIG_PROC_FS */
  351. /************************** IOCTL SUPPORT **************************/
  352. /*
  353.  * The original user space API to configure all those Wireless Extensions
  354.  * is through IOCTLs.
  355.  * In there, we check if we need to call the new driver API (iw_handler)
  356.  * or just call the driver ioctl handler.
  357.  */
  358. /* ---------------------------------------------------------------- */
  359. /*
  360.  * Allow programatic access to /proc/net/wireless even if /proc
  361.  * doesn't exist... Also more efficient...
  362.  */
  363. static inline int dev_iwstats(struct net_device *dev, struct ifreq *ifr)
  364. {
  365. /* Get stats from the driver */
  366. struct iw_statistics *stats;
  367. stats = get_wireless_stats(dev);
  368. if (stats != (struct iw_statistics *) NULL) {
  369. struct iwreq * wrq = (struct iwreq *)ifr;
  370. /* Copy statistics to the user buffer */
  371. if(copy_to_user(wrq->u.data.pointer, stats,
  372. sizeof(struct iw_statistics)))
  373. return -EFAULT;
  374. /* Check if we need to clear the update flag */
  375. if(wrq->u.data.flags != 0)
  376. stats->qual.updated = 0;
  377. return 0;
  378. } else
  379. return -EOPNOTSUPP;
  380. }
  381. /* ---------------------------------------------------------------- */
  382. /*
  383.  * Export the driver private handler definition
  384.  * They will be picked up by tools like iwpriv...
  385.  */
  386. static inline int ioctl_export_private(struct net_device * dev,
  387.        struct ifreq * ifr)
  388. {
  389. struct iwreq * iwr = (struct iwreq *) ifr;
  390. /* Check if the driver has something to export */
  391. if((dev->wireless_handlers->num_private_args == 0) ||
  392.    (dev->wireless_handlers->private_args == NULL))
  393. return -EOPNOTSUPP;
  394. /* Check NULL pointer */
  395. if(iwr->u.data.pointer == NULL)
  396. return -EFAULT;
  397. #ifdef WE_STRICT_WRITE
  398. /* Check if there is enough buffer up there */
  399. if(iwr->u.data.length < (SIOCIWLASTPRIV - SIOCIWFIRSTPRIV + 1))
  400. return -E2BIG;
  401. #endif /* WE_STRICT_WRITE */
  402. /* Set the number of available ioctls. */
  403. iwr->u.data.length = dev->wireless_handlers->num_private_args;
  404. /* Copy structure to the user buffer. */
  405. if (copy_to_user(iwr->u.data.pointer,
  406.  dev->wireless_handlers->private_args,
  407.  sizeof(struct iw_priv_args) * iwr->u.data.length))
  408. return -EFAULT;
  409. return 0;
  410. }
  411. /* ---------------------------------------------------------------- */
  412. /*
  413.  * Wrapper to call a standard Wireless Extension handler.
  414.  * We do various checks and also take care of moving data between
  415.  * user space and kernel space.
  416.  */
  417. static inline int ioctl_standard_call(struct net_device * dev,
  418.       struct ifreq * ifr,
  419.       unsigned int cmd,
  420.       iw_handler handler)
  421. {
  422. struct iwreq * iwr = (struct iwreq *) ifr;
  423. const struct iw_ioctl_description * descr;
  424. struct iw_request_info info;
  425. int ret = -EINVAL;
  426. /* Get the description of the IOCTL */
  427. if((cmd - SIOCIWFIRST) >= standard_ioctl_num)
  428. return -EOPNOTSUPP;
  429. descr = &(standard_ioctl[cmd - SIOCIWFIRST]);
  430. #ifdef WE_IOCTL_DEBUG
  431. printk(KERN_DEBUG "%s (WE) : Found standard handler for 0x%04Xn",
  432.        ifr->ifr_name, cmd);
  433. printk(KERN_DEBUG "%s (WE) : Header type : %d, Token type : %d, size : %d, token : %dn", dev->name, descr->header_type, descr->token_type, descr->token_size, descr->max_tokens);
  434. #endif /* WE_IOCTL_DEBUG */
  435. /* Prepare the call */
  436. info.cmd = cmd;
  437. info.flags = 0;
  438. /* Check if we have a pointer to user space data or not */
  439. if(descr->header_type != IW_HEADER_TYPE_POINT) {
  440. /* No extra arguments. Trivial to handle */
  441. ret = handler(dev, &info, &(iwr->u), NULL);
  442. #ifdef WE_SET_EVENT
  443. /* Generate an event to notify listeners of the change */
  444. if((descr->flags & IW_DESCR_FLAG_EVENT) &&
  445.    ((ret == 0) || (ret == -EIWCOMMIT)))
  446. wireless_send_event(dev, cmd, &(iwr->u), NULL);
  447. #endif /* WE_SET_EVENT */
  448. } else {
  449. char * extra;
  450. int err;
  451. /* Check what user space is giving us */
  452. if(IW_IS_SET(cmd)) {
  453. /* Check NULL pointer */
  454. if((iwr->u.data.pointer == NULL) &&
  455.    (iwr->u.data.length != 0))
  456. return -EFAULT;
  457. /* Check if number of token fits within bounds */
  458. if(iwr->u.data.length > descr->max_tokens)
  459. return -E2BIG;
  460. if(iwr->u.data.length < descr->min_tokens)
  461. return -EINVAL;
  462. } else {
  463. /* Check NULL pointer */
  464. if(iwr->u.data.pointer == NULL)
  465. return -EFAULT;
  466. #ifdef WE_STRICT_WRITE
  467. /* Check if there is enough buffer up there */
  468. if(iwr->u.data.length < descr->max_tokens)
  469. return -E2BIG;
  470. #endif /* WE_STRICT_WRITE */
  471. }
  472. #ifdef WE_IOCTL_DEBUG
  473. printk(KERN_DEBUG "%s (WE) : Malloc %d bytesn",
  474.        dev->name, descr->max_tokens * descr->token_size);
  475. #endif /* WE_IOCTL_DEBUG */
  476. /* Always allocate for max space. Easier, and won't last
  477.  * long... */
  478. extra = kmalloc(descr->max_tokens * descr->token_size,
  479. GFP_KERNEL);
  480. if (extra == NULL) {
  481. return -ENOMEM;
  482. }
  483. /* If it is a SET, get all the extra data in here */
  484. if(IW_IS_SET(cmd) && (iwr->u.data.length != 0)) {
  485. err = copy_from_user(extra, iwr->u.data.pointer,
  486.      iwr->u.data.length *
  487.      descr->token_size);
  488. if (err) {
  489. kfree(extra);
  490. return -EFAULT;
  491. }
  492. #ifdef WE_IOCTL_DEBUG
  493. printk(KERN_DEBUG "%s (WE) : Got %d bytesn",
  494.        dev->name,
  495.        iwr->u.data.length * descr->token_size);
  496. #endif /* WE_IOCTL_DEBUG */
  497. }
  498. /* Call the handler */
  499. ret = handler(dev, &info, &(iwr->u), extra);
  500. /* If we have something to return to the user */
  501. if (!ret && IW_IS_GET(cmd)) {
  502. err = copy_to_user(iwr->u.data.pointer, extra,
  503.    iwr->u.data.length *
  504.    descr->token_size);
  505. if (err)
  506. ret =  -EFAULT;    
  507. #ifdef WE_IOCTL_DEBUG
  508. printk(KERN_DEBUG "%s (WE) : Wrote %d bytesn",
  509.        dev->name,
  510.        iwr->u.data.length * descr->token_size);
  511. #endif /* WE_IOCTL_DEBUG */
  512. }
  513. #ifdef WE_SET_EVENT
  514. /* Generate an event to notify listeners of the change */
  515. if((descr->flags & IW_DESCR_FLAG_EVENT) &&
  516.    ((ret == 0) || (ret == -EIWCOMMIT))) {
  517. if(descr->flags & IW_DESCR_FLAG_RESTRICT)
  518. /* If the event is restricted, don't
  519.  * export the payload */
  520. wireless_send_event(dev, cmd, &(iwr->u), NULL);
  521. else
  522. wireless_send_event(dev, cmd, &(iwr->u),
  523.     extra);
  524. }
  525. #endif /* WE_SET_EVENT */
  526. /* Cleanup - I told you it wasn't that long ;-) */
  527. kfree(extra);
  528. }
  529. /* Call commit handler if needed and defined */
  530. if(ret == -EIWCOMMIT)
  531. ret = call_commit_handler(dev);
  532. /* Here, we will generate the appropriate event if needed */
  533. return ret;
  534. }
  535. /* ---------------------------------------------------------------- */
  536. /*
  537.  * Wrapper to call a private Wireless Extension handler.
  538.  * We do various checks and also take care of moving data between
  539.  * user space and kernel space.
  540.  * It's not as nice and slimline as the standard wrapper. The cause
  541.  * is struct iw_priv_args, which was not really designed for the
  542.  * job we are going here.
  543.  *
  544.  * IMPORTANT : This function prevent to set and get data on the same
  545.  * IOCTL and enforce the SET/GET convention. Not doing it would be
  546.  * far too hairy...
  547.  * If you need to set and get data at the same time, please don't use
  548.  * a iw_handler but process it in your ioctl handler (i.e. use the
  549.  * old driver API).
  550.  */
  551. static inline int ioctl_private_call(struct net_device * dev,
  552.      struct ifreq * ifr,
  553.      unsigned int cmd,
  554.      iw_handler handler)
  555. {
  556. struct iwreq * iwr = (struct iwreq *) ifr;
  557. struct iw_priv_args * descr = NULL;
  558. struct iw_request_info info;
  559. int extra_size = 0;
  560. int i;
  561. int ret = -EINVAL;
  562. /* Get the description of the IOCTL */
  563. for(i = 0; i < dev->wireless_handlers->num_private_args; i++)
  564. if(cmd == dev->wireless_handlers->private_args[i].cmd) {
  565. descr = &(dev->wireless_handlers->private_args[i]);
  566. break;
  567. }
  568. #ifdef WE_IOCTL_DEBUG
  569. printk(KERN_DEBUG "%s (WE) : Found private handler for 0x%04Xn",
  570.        ifr->ifr_name, cmd);
  571. if(descr) {
  572. printk(KERN_DEBUG "%s (WE) : Name %s, set %X, get %Xn",
  573.        dev->name, descr->name,
  574.        descr->set_args, descr->get_args);
  575. }
  576. #endif /* WE_IOCTL_DEBUG */
  577. /* Compute the size of the set/get arguments */
  578. if(descr != NULL) {
  579. if(IW_IS_SET(cmd)) {
  580. /* Size of set arguments */
  581. extra_size = get_priv_size(descr->set_args);
  582. /* Does it fits in iwr ? */
  583. if((descr->set_args & IW_PRIV_SIZE_FIXED) &&
  584.    (extra_size < IFNAMSIZ))
  585. extra_size = 0;
  586. } else {
  587. /* Size of set arguments */
  588. extra_size = get_priv_size(descr->get_args);
  589. /* Does it fits in iwr ? */
  590. if((descr->get_args & IW_PRIV_SIZE_FIXED) &&
  591.    (extra_size < IFNAMSIZ))
  592. extra_size = 0;
  593. }
  594. }
  595. /* Prepare the call */
  596. info.cmd = cmd;
  597. info.flags = 0;
  598. /* Check if we have a pointer to user space data or not. */
  599. if(extra_size == 0) {
  600. /* No extra arguments. Trivial to handle */
  601. ret = handler(dev, &info, &(iwr->u), (char *) &(iwr->u));
  602. } else {
  603. char * extra;
  604. int err;
  605. /* Check what user space is giving us */
  606. if(IW_IS_SET(cmd)) {
  607. /* Check NULL pointer */
  608. if((iwr->u.data.pointer == NULL) &&
  609.    (iwr->u.data.length != 0))
  610. return -EFAULT;
  611. /* Does it fits within bounds ? */
  612. if(iwr->u.data.length > (descr->set_args &
  613.  IW_PRIV_SIZE_MASK))
  614. return -E2BIG;
  615. } else {
  616. /* Check NULL pointer */
  617. if(iwr->u.data.pointer == NULL)
  618. return -EFAULT;
  619. }
  620. #ifdef WE_IOCTL_DEBUG
  621. printk(KERN_DEBUG "%s (WE) : Malloc %d bytesn",
  622.        dev->name, extra_size);
  623. #endif /* WE_IOCTL_DEBUG */
  624. /* Always allocate for max space. Easier, and won't last
  625.  * long... */
  626. extra = kmalloc(extra_size, GFP_KERNEL);
  627. if (extra == NULL) {
  628. return -ENOMEM;
  629. }
  630. /* If it is a SET, get all the extra data in here */
  631. if(IW_IS_SET(cmd) && (iwr->u.data.length != 0)) {
  632. err = copy_from_user(extra, iwr->u.data.pointer,
  633.      extra_size);
  634. if (err) {
  635. kfree(extra);
  636. return -EFAULT;
  637. }
  638. #ifdef WE_IOCTL_DEBUG
  639. printk(KERN_DEBUG "%s (WE) : Got %d elemn",
  640.        dev->name, iwr->u.data.length);
  641. #endif /* WE_IOCTL_DEBUG */
  642. }
  643. /* Call the handler */
  644. ret = handler(dev, &info, &(iwr->u), extra);
  645. /* If we have something to return to the user */
  646. if (!ret && IW_IS_GET(cmd)) {
  647. err = copy_to_user(iwr->u.data.pointer, extra,
  648.    extra_size);
  649. if (err)
  650. ret =  -EFAULT;    
  651. #ifdef WE_IOCTL_DEBUG
  652. printk(KERN_DEBUG "%s (WE) : Wrote %d elemn",
  653.        dev->name, iwr->u.data.length);
  654. #endif /* WE_IOCTL_DEBUG */
  655. }
  656. /* Cleanup - I told you it wasn't that long ;-) */
  657. kfree(extra);
  658. }
  659. /* Call commit handler if needed and defined */
  660. if(ret == -EIWCOMMIT)
  661. ret = call_commit_handler(dev);
  662. return ret;
  663. }
  664. /* ---------------------------------------------------------------- */
  665. /*
  666.  * Main IOCTl dispatcher. Called from the main networking code
  667.  * (dev_ioctl() in net/core/dev.c).
  668.  * Check the type of IOCTL and call the appropriate wrapper...
  669.  */
  670. int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd)
  671. {
  672. struct net_device *dev;
  673. iw_handler handler;
  674. /* Permissions are already checked in dev_ioctl() before calling us.
  675.  * The copy_to/from_user() of ifr is also dealt with in there */
  676. /* Make sure the device exist */
  677. if ((dev = __dev_get_by_name(ifr->ifr_name)) == NULL)
  678. return -ENODEV;
  679. /* A bunch of special cases, then the generic case...
  680.  * Note that 'cmd' is already filtered in dev_ioctl() with
  681.  * (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) */
  682. switch(cmd) 
  683. {
  684. case SIOCGIWSTATS:
  685. /* Get Wireless Stats */
  686. return dev_iwstats(dev, ifr);
  687. case SIOCGIWPRIV:
  688. /* Check if we have some wireless handlers defined */
  689. if(dev->wireless_handlers != NULL) {
  690. /* We export to user space the definition of
  691.  * the private handler ourselves */
  692. return ioctl_export_private(dev, ifr);
  693. }
  694. // ## Fall-through for old API ##
  695. default:
  696. /* Generic IOCTL */
  697. /* Basic check */
  698. if (!netif_device_present(dev))
  699. return -ENODEV;
  700. /* New driver API : try to find the handler */
  701. handler = get_handler(dev, cmd);
  702. if(handler != NULL) {
  703. /* Standard and private are not the same */
  704. if(cmd < SIOCIWFIRSTPRIV)
  705. return ioctl_standard_call(dev,
  706.    ifr,
  707.    cmd,
  708.    handler);
  709. else
  710. return ioctl_private_call(dev,
  711.   ifr,
  712.   cmd,
  713.   handler);
  714. }
  715. /* Old driver API : call driver ioctl handler */
  716. if (dev->do_ioctl) {
  717. return dev->do_ioctl(dev, ifr, cmd);
  718. }
  719. return -EOPNOTSUPP;
  720. }
  721. /* Not reached */
  722. return -EINVAL;
  723. }
  724. /************************* EVENT PROCESSING *************************/
  725. /*
  726.  * Process events generated by the wireless layer or the driver.
  727.  * Most often, the event will be propagated through rtnetlink
  728.  */
  729. #ifdef WE_EVENT_NETLINK
  730. /* "rtnl" is defined in net/core/rtnetlink.c, but we need it here.
  731.  * It is declared in <linux/rtnetlink.h> */
  732. /* ---------------------------------------------------------------- */
  733. /*
  734.  * Fill a rtnetlink message with our event data.
  735.  * Note that we propage only the specified event and don't dump the
  736.  * current wireless config. Dumping the wireless config is far too
  737.  * expensive (for each parameter, the driver need to query the hardware).
  738.  */
  739. static inline int rtnetlink_fill_iwinfo(struct sk_buff * skb,
  740. struct net_device * dev,
  741. int type,
  742. char * event,
  743. int event_len)
  744. {
  745. struct ifinfomsg *r;
  746. struct nlmsghdr  *nlh;
  747. unsigned char  *b = skb->tail;
  748. nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(*r));
  749. r = NLMSG_DATA(nlh);
  750. r->ifi_family = AF_UNSPEC;
  751. r->ifi_type = dev->type;
  752. r->ifi_index = dev->ifindex;
  753. r->ifi_flags = dev->flags;
  754. r->ifi_change = 0; /* Wireless changes don't affect those flags */
  755. /* Add the wireless events in the netlink packet */
  756. RTA_PUT(skb, IFLA_WIRELESS,
  757. event_len, event);
  758. nlh->nlmsg_len = skb->tail - b;
  759. return skb->len;
  760. nlmsg_failure:
  761. rtattr_failure:
  762. skb_trim(skb, b - skb->data);
  763. return -1;
  764. }
  765. /* ---------------------------------------------------------------- */
  766. /*
  767.  * Create and broadcast and send it on the standard rtnetlink socket
  768.  * This is a pure clone rtmsg_ifinfo() in net/core/rtnetlink.c
  769.  * Andrzej Krzysztofowicz mandated that I used a IFLA_XXX field
  770.  * within a RTM_NEWLINK event.
  771.  */
  772. static inline void rtmsg_iwinfo(struct net_device * dev,
  773. char * event,
  774. int event_len)
  775. {
  776. struct sk_buff *skb;
  777. int size = NLMSG_GOODSIZE;
  778. skb = alloc_skb(size, GFP_ATOMIC);
  779. if (!skb)
  780. return;
  781. if (rtnetlink_fill_iwinfo(skb, dev, RTM_NEWLINK,
  782.   event, event_len) < 0) {
  783. kfree_skb(skb);
  784. return;
  785. }
  786. NETLINK_CB(skb).dst_groups = RTMGRP_LINK;
  787. netlink_broadcast(rtnl, skb, 0, RTMGRP_LINK, GFP_ATOMIC);
  788. }
  789. #endif /* WE_EVENT_NETLINK */
  790. /* ---------------------------------------------------------------- */
  791. /*
  792.  * Main event dispatcher. Called from other parts and drivers.
  793.  * Send the event on the apropriate channels.
  794.  * May be called from interrupt context.
  795.  */
  796. void wireless_send_event(struct net_device * dev,
  797.  unsigned int cmd,
  798.  union iwreq_data * wrqu,
  799.  char * extra)
  800. {
  801. const struct iw_ioctl_description * descr = NULL;
  802. int extra_len = 0;
  803. struct iw_event  *event; /* Mallocated whole event */
  804. int event_len; /* Its size */
  805. int hdr_len; /* Size of the event header */
  806. /* Don't "optimise" the following variable, it will crash */
  807. unsigned cmd_index; /* *MUST* be unsigned */
  808. /* Get the description of the IOCTL */
  809. if(cmd <= SIOCIWLAST) {
  810. cmd_index = cmd - SIOCIWFIRST;
  811. if(cmd_index < standard_ioctl_num)
  812. descr = &(standard_ioctl[cmd_index]);
  813. } else {
  814. cmd_index = cmd - IWEVFIRST;
  815. if(cmd_index < standard_event_num)
  816. descr = &(standard_event[cmd_index]);
  817. }
  818. /* Don't accept unknown events */
  819. if(descr == NULL) {
  820. /* Note : we don't return an error to the driver, because
  821.  * the driver would not know what to do about it. It can't
  822.  * return an error to the user, because the event is not
  823.  * initiated by a user request.
  824.  * The best the driver could do is to log an error message.
  825.  * We will do it ourselves instead...
  826.  */
  827.    printk(KERN_ERR "%s (WE) : Invalid Wireless Event (0x%04X)n",
  828.        dev->name, cmd);
  829. return;
  830. }
  831. #ifdef WE_EVENT_DEBUG
  832. printk(KERN_DEBUG "%s (WE) : Got event 0x%04Xn",
  833.        dev->name, cmd);
  834. printk(KERN_DEBUG "%s (WE) : Header type : %d, Token type : %d, size : %d, token : %dn", dev->name, descr->header_type, descr->token_type, descr->token_size, descr->max_tokens);
  835. #endif /* WE_EVENT_DEBUG */
  836. /* Check extra parameters and set extra_len */
  837. if(descr->header_type == IW_HEADER_TYPE_POINT) {
  838. /* Check if number of token fits within bounds */
  839. if(wrqu->data.length > descr->max_tokens) {
  840.    printk(KERN_ERR "%s (WE) : Wireless Event too big (%d)n", dev->name, wrqu->data.length);
  841. return;
  842. }
  843. if(wrqu->data.length < descr->min_tokens) {
  844.    printk(KERN_ERR "%s (WE) : Wireless Event too small (%d)n", dev->name, wrqu->data.length);
  845. return;
  846. }
  847. /* Calculate extra_len - extra is NULL for restricted events */
  848. if(extra != NULL)
  849. extra_len = wrqu->data.length * descr->token_size;
  850. #ifdef WE_EVENT_DEBUG
  851. printk(KERN_DEBUG "%s (WE) : Event 0x%04X, tokens %d, extra_len %dn", dev->name, cmd, wrqu->data.length, extra_len);
  852. #endif /* WE_EVENT_DEBUG */
  853. }
  854. /* Total length of the event */
  855. hdr_len = event_type_size[descr->header_type];
  856. event_len = hdr_len + extra_len;
  857. #ifdef WE_EVENT_DEBUG
  858. printk(KERN_DEBUG "%s (WE) : Event 0x%04X, hdr_len %d, event_len %dn", dev->name, cmd, hdr_len, event_len);
  859. #endif /* WE_EVENT_DEBUG */
  860. /* Create temporary buffer to hold the event */
  861. event = kmalloc(event_len, GFP_ATOMIC);
  862. if(event == NULL)
  863. return;
  864. /* Fill event */
  865. event->len = event_len;
  866. event->cmd = cmd;
  867. memcpy(&event->u, wrqu, hdr_len - IW_EV_LCP_LEN);
  868. if(extra != NULL)
  869. memcpy(((char *) event) + hdr_len, extra, extra_len);
  870. #ifdef WE_EVENT_NETLINK
  871. /* rtnetlink event channel */
  872. rtmsg_iwinfo(dev, (char *) event, event_len);
  873. #endif /* WE_EVENT_NETLINK */
  874. /* Cleanup */
  875. kfree(event);
  876. return; /* Always success, I guess ;-) */
  877. }