at v2.6.19-rc1 2322 lines 70 kB view raw
1/* 2 * This file implement the Wireless Extensions APIs. 3 * 4 * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> 5 * Copyright (c) 1997-2006 Jean Tourrilhes, All Rights Reserved. 6 * 7 * (As all part of the Linux kernel, this file is GPL) 8 */ 9 10/************************** DOCUMENTATION **************************/ 11/* 12 * API definition : 13 * -------------- 14 * See <linux/wireless.h> for details of the APIs and the rest. 15 * 16 * History : 17 * ------- 18 * 19 * v1 - 5.12.01 - Jean II 20 * o Created this file. 21 * 22 * v2 - 13.12.01 - Jean II 23 * o Move /proc/net/wireless stuff from net/core/dev.c to here 24 * o Make Wireless Extension IOCTLs go through here 25 * o Added iw_handler handling ;-) 26 * o Added standard ioctl description 27 * o Initial dumb commit strategy based on orinoco.c 28 * 29 * v3 - 19.12.01 - Jean II 30 * o Make sure we don't go out of standard_ioctl[] in ioctl_standard_call 31 * o Add event dispatcher function 32 * o Add event description 33 * o Propagate events as rtnetlink IFLA_WIRELESS option 34 * o Generate event on selected SET requests 35 * 36 * v4 - 18.04.02 - Jean II 37 * o Fix stupid off by one in iw_ioctl_description : IW_ESSID_MAX_SIZE + 1 38 * 39 * v5 - 21.06.02 - Jean II 40 * o Add IW_PRIV_TYPE_ADDR in priv_type_size (+cleanup) 41 * o Reshuffle IW_HEADER_TYPE_XXX to map IW_PRIV_TYPE_XXX changes 42 * o Add IWEVCUSTOM for driver specific event/scanning token 43 * o Turn on WE_STRICT_WRITE by default + kernel warning 44 * o Fix WE_STRICT_WRITE in ioctl_export_private() (32 => iw_num) 45 * o Fix off-by-one in test (extra_size <= IFNAMSIZ) 46 * 47 * v6 - 9.01.03 - Jean II 48 * o Add common spy support : iw_handler_set_spy(), wireless_spy_update() 49 * o Add enhanced spy support : iw_handler_set_thrspy() and event. 50 * o Add WIRELESS_EXT version display in /proc/net/wireless 51 * 52 * v6 - 18.06.04 - Jean II 53 * o Change get_spydata() method for added safety 54 * o Remove spy #ifdef, they are always on -> cleaner code 55 * o Allow any size GET request if user specifies length > max 56 * and if request has IW_DESCR_FLAG_NOMAX flag or is SIOCGIWPRIV 57 * o Start migrating get_wireless_stats to struct iw_handler_def 58 * o Add wmb() in iw_handler_set_spy() for non-coherent archs/cpus 59 * Based on patch from Pavel Roskin <proski@gnu.org> : 60 * o Fix kernel data leak to user space in private handler handling 61 * 62 * v7 - 18.3.05 - Jean II 63 * o Remove (struct iw_point *)->pointer from events and streams 64 * o Remove spy_offset from struct iw_handler_def 65 * o Start deprecating dev->get_wireless_stats, output a warning 66 * o If IW_QUAL_DBM is set, show dBm values in /proc/net/wireless 67 * o Don't loose INVALID/DBM flags when clearing UPDATED flags (iwstats) 68 * 69 * v8 - 17.02.06 - Jean II 70 * o RtNetlink requests support (SET/GET) 71 * 72 * v8b - 03.08.06 - Herbert Xu 73 * o Fix Wireless Event locking issues. 74 * 75 * v9 - 14.3.06 - Jean II 76 * o Change length in ESSID and NICK to strlen() instead of strlen()+1 77 * o Make standard_ioctl_num and standard_event_num unsigned 78 * o Remove (struct net_device *)->get_wireless_stats() 79 */ 80 81/***************************** INCLUDES *****************************/ 82 83#include <linux/module.h> 84#include <linux/types.h> /* off_t */ 85#include <linux/netdevice.h> /* struct ifreq, dev_get_by_name() */ 86#include <linux/proc_fs.h> 87#include <linux/rtnetlink.h> /* rtnetlink stuff */ 88#include <linux/seq_file.h> 89#include <linux/init.h> /* for __init */ 90#include <linux/if_arp.h> /* ARPHRD_ETHER */ 91#include <linux/etherdevice.h> /* compare_ether_addr */ 92#include <linux/interrupt.h> 93 94#include <linux/wireless.h> /* Pretty obvious */ 95#include <net/iw_handler.h> /* New driver API */ 96#include <net/netlink.h> 97 98#include <asm/uaccess.h> /* copy_to_user() */ 99 100/**************************** CONSTANTS ****************************/ 101 102/* Debugging stuff */ 103#undef WE_IOCTL_DEBUG /* Debug IOCTL API */ 104#undef WE_RTNETLINK_DEBUG /* Debug RtNetlink API */ 105#undef WE_EVENT_DEBUG /* Debug Event dispatcher */ 106#undef WE_SPY_DEBUG /* Debug enhanced spy support */ 107 108/* Options */ 109//CONFIG_NET_WIRELESS_RTNETLINK /* Wireless requests over RtNetlink */ 110#define WE_EVENT_RTNETLINK /* Propagate events using RtNetlink */ 111#define WE_SET_EVENT /* Generate an event on some set commands */ 112 113/************************* GLOBAL VARIABLES *************************/ 114/* 115 * You should not use global variables, because of re-entrancy. 116 * On our case, it's only const, so it's OK... 117 */ 118/* 119 * Meta-data about all the standard Wireless Extension request we 120 * know about. 121 */ 122static const struct iw_ioctl_description standard_ioctl[] = { 123 [SIOCSIWCOMMIT - SIOCIWFIRST] = { 124 .header_type = IW_HEADER_TYPE_NULL, 125 }, 126 [SIOCGIWNAME - SIOCIWFIRST] = { 127 .header_type = IW_HEADER_TYPE_CHAR, 128 .flags = IW_DESCR_FLAG_DUMP, 129 }, 130 [SIOCSIWNWID - SIOCIWFIRST] = { 131 .header_type = IW_HEADER_TYPE_PARAM, 132 .flags = IW_DESCR_FLAG_EVENT, 133 }, 134 [SIOCGIWNWID - SIOCIWFIRST] = { 135 .header_type = IW_HEADER_TYPE_PARAM, 136 .flags = IW_DESCR_FLAG_DUMP, 137 }, 138 [SIOCSIWFREQ - SIOCIWFIRST] = { 139 .header_type = IW_HEADER_TYPE_FREQ, 140 .flags = IW_DESCR_FLAG_EVENT, 141 }, 142 [SIOCGIWFREQ - SIOCIWFIRST] = { 143 .header_type = IW_HEADER_TYPE_FREQ, 144 .flags = IW_DESCR_FLAG_DUMP, 145 }, 146 [SIOCSIWMODE - SIOCIWFIRST] = { 147 .header_type = IW_HEADER_TYPE_UINT, 148 .flags = IW_DESCR_FLAG_EVENT, 149 }, 150 [SIOCGIWMODE - SIOCIWFIRST] = { 151 .header_type = IW_HEADER_TYPE_UINT, 152 .flags = IW_DESCR_FLAG_DUMP, 153 }, 154 [SIOCSIWSENS - SIOCIWFIRST] = { 155 .header_type = IW_HEADER_TYPE_PARAM, 156 }, 157 [SIOCGIWSENS - SIOCIWFIRST] = { 158 .header_type = IW_HEADER_TYPE_PARAM, 159 }, 160 [SIOCSIWRANGE - SIOCIWFIRST] = { 161 .header_type = IW_HEADER_TYPE_NULL, 162 }, 163 [SIOCGIWRANGE - SIOCIWFIRST] = { 164 .header_type = IW_HEADER_TYPE_POINT, 165 .token_size = 1, 166 .max_tokens = sizeof(struct iw_range), 167 .flags = IW_DESCR_FLAG_DUMP, 168 }, 169 [SIOCSIWPRIV - SIOCIWFIRST] = { 170 .header_type = IW_HEADER_TYPE_NULL, 171 }, 172 [SIOCGIWPRIV - SIOCIWFIRST] = { /* (handled directly by us) */ 173 .header_type = IW_HEADER_TYPE_POINT, 174 .token_size = sizeof(struct iw_priv_args), 175 .max_tokens = 16, 176 .flags = IW_DESCR_FLAG_NOMAX, 177 }, 178 [SIOCSIWSTATS - SIOCIWFIRST] = { 179 .header_type = IW_HEADER_TYPE_NULL, 180 }, 181 [SIOCGIWSTATS - SIOCIWFIRST] = { /* (handled directly by us) */ 182 .header_type = IW_HEADER_TYPE_POINT, 183 .token_size = 1, 184 .max_tokens = sizeof(struct iw_statistics), 185 .flags = IW_DESCR_FLAG_DUMP, 186 }, 187 [SIOCSIWSPY - SIOCIWFIRST] = { 188 .header_type = IW_HEADER_TYPE_POINT, 189 .token_size = sizeof(struct sockaddr), 190 .max_tokens = IW_MAX_SPY, 191 }, 192 [SIOCGIWSPY - SIOCIWFIRST] = { 193 .header_type = IW_HEADER_TYPE_POINT, 194 .token_size = sizeof(struct sockaddr) + 195 sizeof(struct iw_quality), 196 .max_tokens = IW_MAX_SPY, 197 }, 198 [SIOCSIWTHRSPY - SIOCIWFIRST] = { 199 .header_type = IW_HEADER_TYPE_POINT, 200 .token_size = sizeof(struct iw_thrspy), 201 .min_tokens = 1, 202 .max_tokens = 1, 203 }, 204 [SIOCGIWTHRSPY - SIOCIWFIRST] = { 205 .header_type = IW_HEADER_TYPE_POINT, 206 .token_size = sizeof(struct iw_thrspy), 207 .min_tokens = 1, 208 .max_tokens = 1, 209 }, 210 [SIOCSIWAP - SIOCIWFIRST] = { 211 .header_type = IW_HEADER_TYPE_ADDR, 212 }, 213 [SIOCGIWAP - SIOCIWFIRST] = { 214 .header_type = IW_HEADER_TYPE_ADDR, 215 .flags = IW_DESCR_FLAG_DUMP, 216 }, 217 [SIOCSIWMLME - SIOCIWFIRST] = { 218 .header_type = IW_HEADER_TYPE_POINT, 219 .token_size = 1, 220 .min_tokens = sizeof(struct iw_mlme), 221 .max_tokens = sizeof(struct iw_mlme), 222 }, 223 [SIOCGIWAPLIST - SIOCIWFIRST] = { 224 .header_type = IW_HEADER_TYPE_POINT, 225 .token_size = sizeof(struct sockaddr) + 226 sizeof(struct iw_quality), 227 .max_tokens = IW_MAX_AP, 228 .flags = IW_DESCR_FLAG_NOMAX, 229 }, 230 [SIOCSIWSCAN - SIOCIWFIRST] = { 231 .header_type = IW_HEADER_TYPE_POINT, 232 .token_size = 1, 233 .min_tokens = 0, 234 .max_tokens = sizeof(struct iw_scan_req), 235 }, 236 [SIOCGIWSCAN - SIOCIWFIRST] = { 237 .header_type = IW_HEADER_TYPE_POINT, 238 .token_size = 1, 239 .max_tokens = IW_SCAN_MAX_DATA, 240 .flags = IW_DESCR_FLAG_NOMAX, 241 }, 242 [SIOCSIWESSID - SIOCIWFIRST] = { 243 .header_type = IW_HEADER_TYPE_POINT, 244 .token_size = 1, 245 .max_tokens = IW_ESSID_MAX_SIZE, 246 .flags = IW_DESCR_FLAG_EVENT, 247 }, 248 [SIOCGIWESSID - SIOCIWFIRST] = { 249 .header_type = IW_HEADER_TYPE_POINT, 250 .token_size = 1, 251 .max_tokens = IW_ESSID_MAX_SIZE, 252 .flags = IW_DESCR_FLAG_DUMP, 253 }, 254 [SIOCSIWNICKN - SIOCIWFIRST] = { 255 .header_type = IW_HEADER_TYPE_POINT, 256 .token_size = 1, 257 .max_tokens = IW_ESSID_MAX_SIZE, 258 }, 259 [SIOCGIWNICKN - SIOCIWFIRST] = { 260 .header_type = IW_HEADER_TYPE_POINT, 261 .token_size = 1, 262 .max_tokens = IW_ESSID_MAX_SIZE, 263 }, 264 [SIOCSIWRATE - SIOCIWFIRST] = { 265 .header_type = IW_HEADER_TYPE_PARAM, 266 }, 267 [SIOCGIWRATE - SIOCIWFIRST] = { 268 .header_type = IW_HEADER_TYPE_PARAM, 269 }, 270 [SIOCSIWRTS - SIOCIWFIRST] = { 271 .header_type = IW_HEADER_TYPE_PARAM, 272 }, 273 [SIOCGIWRTS - SIOCIWFIRST] = { 274 .header_type = IW_HEADER_TYPE_PARAM, 275 }, 276 [SIOCSIWFRAG - SIOCIWFIRST] = { 277 .header_type = IW_HEADER_TYPE_PARAM, 278 }, 279 [SIOCGIWFRAG - SIOCIWFIRST] = { 280 .header_type = IW_HEADER_TYPE_PARAM, 281 }, 282 [SIOCSIWTXPOW - SIOCIWFIRST] = { 283 .header_type = IW_HEADER_TYPE_PARAM, 284 }, 285 [SIOCGIWTXPOW - SIOCIWFIRST] = { 286 .header_type = IW_HEADER_TYPE_PARAM, 287 }, 288 [SIOCSIWRETRY - SIOCIWFIRST] = { 289 .header_type = IW_HEADER_TYPE_PARAM, 290 }, 291 [SIOCGIWRETRY - SIOCIWFIRST] = { 292 .header_type = IW_HEADER_TYPE_PARAM, 293 }, 294 [SIOCSIWENCODE - SIOCIWFIRST] = { 295 .header_type = IW_HEADER_TYPE_POINT, 296 .token_size = 1, 297 .max_tokens = IW_ENCODING_TOKEN_MAX, 298 .flags = IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT, 299 }, 300 [SIOCGIWENCODE - SIOCIWFIRST] = { 301 .header_type = IW_HEADER_TYPE_POINT, 302 .token_size = 1, 303 .max_tokens = IW_ENCODING_TOKEN_MAX, 304 .flags = IW_DESCR_FLAG_DUMP | IW_DESCR_FLAG_RESTRICT, 305 }, 306 [SIOCSIWPOWER - SIOCIWFIRST] = { 307 .header_type = IW_HEADER_TYPE_PARAM, 308 }, 309 [SIOCGIWPOWER - SIOCIWFIRST] = { 310 .header_type = IW_HEADER_TYPE_PARAM, 311 }, 312 [SIOCSIWGENIE - SIOCIWFIRST] = { 313 .header_type = IW_HEADER_TYPE_POINT, 314 .token_size = 1, 315 .max_tokens = IW_GENERIC_IE_MAX, 316 }, 317 [SIOCGIWGENIE - SIOCIWFIRST] = { 318 .header_type = IW_HEADER_TYPE_POINT, 319 .token_size = 1, 320 .max_tokens = IW_GENERIC_IE_MAX, 321 }, 322 [SIOCSIWAUTH - SIOCIWFIRST] = { 323 .header_type = IW_HEADER_TYPE_PARAM, 324 }, 325 [SIOCGIWAUTH - SIOCIWFIRST] = { 326 .header_type = IW_HEADER_TYPE_PARAM, 327 }, 328 [SIOCSIWENCODEEXT - SIOCIWFIRST] = { 329 .header_type = IW_HEADER_TYPE_POINT, 330 .token_size = 1, 331 .min_tokens = sizeof(struct iw_encode_ext), 332 .max_tokens = sizeof(struct iw_encode_ext) + 333 IW_ENCODING_TOKEN_MAX, 334 }, 335 [SIOCGIWENCODEEXT - SIOCIWFIRST] = { 336 .header_type = IW_HEADER_TYPE_POINT, 337 .token_size = 1, 338 .min_tokens = sizeof(struct iw_encode_ext), 339 .max_tokens = sizeof(struct iw_encode_ext) + 340 IW_ENCODING_TOKEN_MAX, 341 }, 342 [SIOCSIWPMKSA - SIOCIWFIRST] = { 343 .header_type = IW_HEADER_TYPE_POINT, 344 .token_size = 1, 345 .min_tokens = sizeof(struct iw_pmksa), 346 .max_tokens = sizeof(struct iw_pmksa), 347 }, 348}; 349static const unsigned standard_ioctl_num = (sizeof(standard_ioctl) / 350 sizeof(struct iw_ioctl_description)); 351 352/* 353 * Meta-data about all the additional standard Wireless Extension events 354 * we know about. 355 */ 356static const struct iw_ioctl_description standard_event[] = { 357 [IWEVTXDROP - IWEVFIRST] = { 358 .header_type = IW_HEADER_TYPE_ADDR, 359 }, 360 [IWEVQUAL - IWEVFIRST] = { 361 .header_type = IW_HEADER_TYPE_QUAL, 362 }, 363 [IWEVCUSTOM - IWEVFIRST] = { 364 .header_type = IW_HEADER_TYPE_POINT, 365 .token_size = 1, 366 .max_tokens = IW_CUSTOM_MAX, 367 }, 368 [IWEVREGISTERED - IWEVFIRST] = { 369 .header_type = IW_HEADER_TYPE_ADDR, 370 }, 371 [IWEVEXPIRED - IWEVFIRST] = { 372 .header_type = IW_HEADER_TYPE_ADDR, 373 }, 374 [IWEVGENIE - IWEVFIRST] = { 375 .header_type = IW_HEADER_TYPE_POINT, 376 .token_size = 1, 377 .max_tokens = IW_GENERIC_IE_MAX, 378 }, 379 [IWEVMICHAELMICFAILURE - IWEVFIRST] = { 380 .header_type = IW_HEADER_TYPE_POINT, 381 .token_size = 1, 382 .max_tokens = sizeof(struct iw_michaelmicfailure), 383 }, 384 [IWEVASSOCREQIE - IWEVFIRST] = { 385 .header_type = IW_HEADER_TYPE_POINT, 386 .token_size = 1, 387 .max_tokens = IW_GENERIC_IE_MAX, 388 }, 389 [IWEVASSOCRESPIE - IWEVFIRST] = { 390 .header_type = IW_HEADER_TYPE_POINT, 391 .token_size = 1, 392 .max_tokens = IW_GENERIC_IE_MAX, 393 }, 394 [IWEVPMKIDCAND - IWEVFIRST] = { 395 .header_type = IW_HEADER_TYPE_POINT, 396 .token_size = 1, 397 .max_tokens = sizeof(struct iw_pmkid_cand), 398 }, 399}; 400static const unsigned standard_event_num = (sizeof(standard_event) / 401 sizeof(struct iw_ioctl_description)); 402 403/* Size (in bytes) of the various private data types */ 404static const char iw_priv_type_size[] = { 405 0, /* IW_PRIV_TYPE_NONE */ 406 1, /* IW_PRIV_TYPE_BYTE */ 407 1, /* IW_PRIV_TYPE_CHAR */ 408 0, /* Not defined */ 409 sizeof(__u32), /* IW_PRIV_TYPE_INT */ 410 sizeof(struct iw_freq), /* IW_PRIV_TYPE_FLOAT */ 411 sizeof(struct sockaddr), /* IW_PRIV_TYPE_ADDR */ 412 0, /* Not defined */ 413}; 414 415/* Size (in bytes) of various events */ 416static const int event_type_size[] = { 417 IW_EV_LCP_LEN, /* IW_HEADER_TYPE_NULL */ 418 0, 419 IW_EV_CHAR_LEN, /* IW_HEADER_TYPE_CHAR */ 420 0, 421 IW_EV_UINT_LEN, /* IW_HEADER_TYPE_UINT */ 422 IW_EV_FREQ_LEN, /* IW_HEADER_TYPE_FREQ */ 423 IW_EV_ADDR_LEN, /* IW_HEADER_TYPE_ADDR */ 424 0, 425 IW_EV_POINT_LEN, /* Without variable payload */ 426 IW_EV_PARAM_LEN, /* IW_HEADER_TYPE_PARAM */ 427 IW_EV_QUAL_LEN, /* IW_HEADER_TYPE_QUAL */ 428}; 429 430/************************ COMMON SUBROUTINES ************************/ 431/* 432 * Stuff that may be used in various place or doesn't fit in one 433 * of the section below. 434 */ 435 436/* ---------------------------------------------------------------- */ 437/* 438 * Return the driver handler associated with a specific Wireless Extension. 439 * Called from various place, so make sure it remains efficient. 440 */ 441static inline iw_handler get_handler(struct net_device *dev, 442 unsigned int cmd) 443{ 444 /* Don't "optimise" the following variable, it will crash */ 445 unsigned int index; /* *MUST* be unsigned */ 446 447 /* Check if we have some wireless handlers defined */ 448 if(dev->wireless_handlers == NULL) 449 return NULL; 450 451 /* Try as a standard command */ 452 index = cmd - SIOCIWFIRST; 453 if(index < dev->wireless_handlers->num_standard) 454 return dev->wireless_handlers->standard[index]; 455 456 /* Try as a private command */ 457 index = cmd - SIOCIWFIRSTPRIV; 458 if(index < dev->wireless_handlers->num_private) 459 return dev->wireless_handlers->private[index]; 460 461 /* Not found */ 462 return NULL; 463} 464 465/* ---------------------------------------------------------------- */ 466/* 467 * Get statistics out of the driver 468 */ 469static inline struct iw_statistics *get_wireless_stats(struct net_device *dev) 470{ 471 /* New location */ 472 if((dev->wireless_handlers != NULL) && 473 (dev->wireless_handlers->get_wireless_stats != NULL)) 474 return dev->wireless_handlers->get_wireless_stats(dev); 475 476 /* Not found */ 477 return (struct iw_statistics *) NULL; 478} 479 480/* ---------------------------------------------------------------- */ 481/* 482 * Call the commit handler in the driver 483 * (if exist and if conditions are right) 484 * 485 * Note : our current commit strategy is currently pretty dumb, 486 * but we will be able to improve on that... 487 * The goal is to try to agreagate as many changes as possible 488 * before doing the commit. Drivers that will define a commit handler 489 * are usually those that need a reset after changing parameters, so 490 * we want to minimise the number of reset. 491 * A cool idea is to use a timer : at each "set" command, we re-set the 492 * timer, when the timer eventually fires, we call the driver. 493 * Hopefully, more on that later. 494 * 495 * Also, I'm waiting to see how many people will complain about the 496 * netif_running(dev) test. I'm open on that one... 497 * Hopefully, the driver will remember to do a commit in "open()" ;-) 498 */ 499static inline int call_commit_handler(struct net_device * dev) 500{ 501 if((netif_running(dev)) && 502 (dev->wireless_handlers->standard[0] != NULL)) { 503 /* Call the commit handler on the driver */ 504 return dev->wireless_handlers->standard[0](dev, NULL, 505 NULL, NULL); 506 } else 507 return 0; /* Command completed successfully */ 508} 509 510/* ---------------------------------------------------------------- */ 511/* 512 * Calculate size of private arguments 513 */ 514static inline int get_priv_size(__u16 args) 515{ 516 int num = args & IW_PRIV_SIZE_MASK; 517 int type = (args & IW_PRIV_TYPE_MASK) >> 12; 518 519 return num * iw_priv_type_size[type]; 520} 521 522/* ---------------------------------------------------------------- */ 523/* 524 * Re-calculate the size of private arguments 525 */ 526static inline int adjust_priv_size(__u16 args, 527 union iwreq_data * wrqu) 528{ 529 int num = wrqu->data.length; 530 int max = args & IW_PRIV_SIZE_MASK; 531 int type = (args & IW_PRIV_TYPE_MASK) >> 12; 532 533 /* Make sure the driver doesn't goof up */ 534 if (max < num) 535 num = max; 536 537 return num * iw_priv_type_size[type]; 538} 539 540/* ---------------------------------------------------------------- */ 541/* 542 * Standard Wireless Handler : get wireless stats 543 * Allow programatic access to /proc/net/wireless even if /proc 544 * doesn't exist... Also more efficient... 545 */ 546static int iw_handler_get_iwstats(struct net_device * dev, 547 struct iw_request_info * info, 548 union iwreq_data * wrqu, 549 char * extra) 550{ 551 /* Get stats from the driver */ 552 struct iw_statistics *stats; 553 554 stats = get_wireless_stats(dev); 555 if (stats != (struct iw_statistics *) NULL) { 556 557 /* Copy statistics to extra */ 558 memcpy(extra, stats, sizeof(struct iw_statistics)); 559 wrqu->data.length = sizeof(struct iw_statistics); 560 561 /* Check if we need to clear the updated flag */ 562 if(wrqu->data.flags != 0) 563 stats->qual.updated &= ~IW_QUAL_ALL_UPDATED; 564 return 0; 565 } else 566 return -EOPNOTSUPP; 567} 568 569/* ---------------------------------------------------------------- */ 570/* 571 * Standard Wireless Handler : get iwpriv definitions 572 * Export the driver private handler definition 573 * They will be picked up by tools like iwpriv... 574 */ 575static int iw_handler_get_private(struct net_device * dev, 576 struct iw_request_info * info, 577 union iwreq_data * wrqu, 578 char * extra) 579{ 580 /* Check if the driver has something to export */ 581 if((dev->wireless_handlers->num_private_args == 0) || 582 (dev->wireless_handlers->private_args == NULL)) 583 return -EOPNOTSUPP; 584 585 /* Check if there is enough buffer up there */ 586 if(wrqu->data.length < dev->wireless_handlers->num_private_args) { 587 /* User space can't know in advance how large the buffer 588 * needs to be. Give it a hint, so that we can support 589 * any size buffer we want somewhat efficiently... */ 590 wrqu->data.length = dev->wireless_handlers->num_private_args; 591 return -E2BIG; 592 } 593 594 /* Set the number of available ioctls. */ 595 wrqu->data.length = dev->wireless_handlers->num_private_args; 596 597 /* Copy structure to the user buffer. */ 598 memcpy(extra, dev->wireless_handlers->private_args, 599 sizeof(struct iw_priv_args) * wrqu->data.length); 600 601 return 0; 602} 603 604 605/******************** /proc/net/wireless SUPPORT ********************/ 606/* 607 * The /proc/net/wireless file is a human readable user-space interface 608 * exporting various wireless specific statistics from the wireless devices. 609 * This is the most popular part of the Wireless Extensions ;-) 610 * 611 * This interface is a pure clone of /proc/net/dev (in net/core/dev.c). 612 * The content of the file is basically the content of "struct iw_statistics". 613 */ 614 615#ifdef CONFIG_PROC_FS 616 617/* ---------------------------------------------------------------- */ 618/* 619 * Print one entry (line) of /proc/net/wireless 620 */ 621static __inline__ void wireless_seq_printf_stats(struct seq_file *seq, 622 struct net_device *dev) 623{ 624 /* Get stats from the driver */ 625 struct iw_statistics *stats = get_wireless_stats(dev); 626 627 if (stats) { 628 seq_printf(seq, "%6s: %04x %3d%c %3d%c %3d%c %6d %6d %6d " 629 "%6d %6d %6d\n", 630 dev->name, stats->status, stats->qual.qual, 631 stats->qual.updated & IW_QUAL_QUAL_UPDATED 632 ? '.' : ' ', 633 ((__s32) stats->qual.level) - 634 ((stats->qual.updated & IW_QUAL_DBM) ? 0x100 : 0), 635 stats->qual.updated & IW_QUAL_LEVEL_UPDATED 636 ? '.' : ' ', 637 ((__s32) stats->qual.noise) - 638 ((stats->qual.updated & IW_QUAL_DBM) ? 0x100 : 0), 639 stats->qual.updated & IW_QUAL_NOISE_UPDATED 640 ? '.' : ' ', 641 stats->discard.nwid, stats->discard.code, 642 stats->discard.fragment, stats->discard.retries, 643 stats->discard.misc, stats->miss.beacon); 644 stats->qual.updated &= ~IW_QUAL_ALL_UPDATED; 645 } 646} 647 648/* ---------------------------------------------------------------- */ 649/* 650 * Print info for /proc/net/wireless (print all entries) 651 */ 652static int wireless_seq_show(struct seq_file *seq, void *v) 653{ 654 if (v == SEQ_START_TOKEN) 655 seq_printf(seq, "Inter-| sta-| Quality | Discarded " 656 "packets | Missed | WE\n" 657 " face | tus | link level noise | nwid " 658 "crypt frag retry misc | beacon | %d\n", 659 WIRELESS_EXT); 660 else 661 wireless_seq_printf_stats(seq, v); 662 return 0; 663} 664 665static struct seq_operations wireless_seq_ops = { 666 .start = dev_seq_start, 667 .next = dev_seq_next, 668 .stop = dev_seq_stop, 669 .show = wireless_seq_show, 670}; 671 672static int wireless_seq_open(struct inode *inode, struct file *file) 673{ 674 return seq_open(file, &wireless_seq_ops); 675} 676 677static struct file_operations wireless_seq_fops = { 678 .owner = THIS_MODULE, 679 .open = wireless_seq_open, 680 .read = seq_read, 681 .llseek = seq_lseek, 682 .release = seq_release, 683}; 684 685int __init wireless_proc_init(void) 686{ 687 /* Create /proc/net/wireless entry */ 688 if (!proc_net_fops_create("wireless", S_IRUGO, &wireless_seq_fops)) 689 return -ENOMEM; 690 691 return 0; 692} 693#endif /* CONFIG_PROC_FS */ 694 695/************************** IOCTL SUPPORT **************************/ 696/* 697 * The original user space API to configure all those Wireless Extensions 698 * is through IOCTLs. 699 * In there, we check if we need to call the new driver API (iw_handler) 700 * or just call the driver ioctl handler. 701 */ 702 703/* ---------------------------------------------------------------- */ 704/* 705 * Wrapper to call a standard Wireless Extension handler. 706 * We do various checks and also take care of moving data between 707 * user space and kernel space. 708 */ 709static int ioctl_standard_call(struct net_device * dev, 710 struct ifreq * ifr, 711 unsigned int cmd, 712 iw_handler handler) 713{ 714 struct iwreq * iwr = (struct iwreq *) ifr; 715 const struct iw_ioctl_description * descr; 716 struct iw_request_info info; 717 int ret = -EINVAL; 718 719 /* Get the description of the IOCTL */ 720 if((cmd - SIOCIWFIRST) >= standard_ioctl_num) 721 return -EOPNOTSUPP; 722 descr = &(standard_ioctl[cmd - SIOCIWFIRST]); 723 724#ifdef WE_IOCTL_DEBUG 725 printk(KERN_DEBUG "%s (WE) : Found standard handler for 0x%04X\n", 726 ifr->ifr_name, cmd); 727 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); 728#endif /* WE_IOCTL_DEBUG */ 729 730 /* Prepare the call */ 731 info.cmd = cmd; 732 info.flags = 0; 733 734 /* Check if we have a pointer to user space data or not */ 735 if(descr->header_type != IW_HEADER_TYPE_POINT) { 736 737 /* No extra arguments. Trivial to handle */ 738 ret = handler(dev, &info, &(iwr->u), NULL); 739 740#ifdef WE_SET_EVENT 741 /* Generate an event to notify listeners of the change */ 742 if((descr->flags & IW_DESCR_FLAG_EVENT) && 743 ((ret == 0) || (ret == -EIWCOMMIT))) 744 wireless_send_event(dev, cmd, &(iwr->u), NULL); 745#endif /* WE_SET_EVENT */ 746 } else { 747 char * extra; 748 int extra_size; 749 int user_length = 0; 750 int err; 751 752 /* Calculate space needed by arguments. Always allocate 753 * for max space. Easier, and won't last long... */ 754 extra_size = descr->max_tokens * descr->token_size; 755 756 /* Check what user space is giving us */ 757 if(IW_IS_SET(cmd)) { 758 /* Check NULL pointer */ 759 if((iwr->u.data.pointer == NULL) && 760 (iwr->u.data.length != 0)) 761 return -EFAULT; 762 /* Check if number of token fits within bounds */ 763 if(iwr->u.data.length > descr->max_tokens) 764 return -E2BIG; 765 if(iwr->u.data.length < descr->min_tokens) 766 return -EINVAL; 767 } else { 768 /* Check NULL pointer */ 769 if(iwr->u.data.pointer == NULL) 770 return -EFAULT; 771 /* Save user space buffer size for checking */ 772 user_length = iwr->u.data.length; 773 774 /* Don't check if user_length > max to allow forward 775 * compatibility. The test user_length < min is 776 * implied by the test at the end. */ 777 778 /* Support for very large requests */ 779 if((descr->flags & IW_DESCR_FLAG_NOMAX) && 780 (user_length > descr->max_tokens)) { 781 /* Allow userspace to GET more than max so 782 * we can support any size GET requests. 783 * There is still a limit : -ENOMEM. */ 784 extra_size = user_length * descr->token_size; 785 /* Note : user_length is originally a __u16, 786 * and token_size is controlled by us, 787 * so extra_size won't get negative and 788 * won't overflow... */ 789 } 790 } 791 792#ifdef WE_IOCTL_DEBUG 793 printk(KERN_DEBUG "%s (WE) : Malloc %d bytes\n", 794 dev->name, extra_size); 795#endif /* WE_IOCTL_DEBUG */ 796 797 /* Create the kernel buffer */ 798 extra = kmalloc(extra_size, GFP_KERNEL); 799 if (extra == NULL) { 800 return -ENOMEM; 801 } 802 803 /* If it is a SET, get all the extra data in here */ 804 if(IW_IS_SET(cmd) && (iwr->u.data.length != 0)) { 805 err = copy_from_user(extra, iwr->u.data.pointer, 806 iwr->u.data.length * 807 descr->token_size); 808 if (err) { 809 kfree(extra); 810 return -EFAULT; 811 } 812#ifdef WE_IOCTL_DEBUG 813 printk(KERN_DEBUG "%s (WE) : Got %d bytes\n", 814 dev->name, 815 iwr->u.data.length * descr->token_size); 816#endif /* WE_IOCTL_DEBUG */ 817 } 818 819 /* Call the handler */ 820 ret = handler(dev, &info, &(iwr->u), extra); 821 822 /* If we have something to return to the user */ 823 if (!ret && IW_IS_GET(cmd)) { 824 /* Check if there is enough buffer up there */ 825 if(user_length < iwr->u.data.length) { 826 kfree(extra); 827 return -E2BIG; 828 } 829 830 err = copy_to_user(iwr->u.data.pointer, extra, 831 iwr->u.data.length * 832 descr->token_size); 833 if (err) 834 ret = -EFAULT; 835#ifdef WE_IOCTL_DEBUG 836 printk(KERN_DEBUG "%s (WE) : Wrote %d bytes\n", 837 dev->name, 838 iwr->u.data.length * descr->token_size); 839#endif /* WE_IOCTL_DEBUG */ 840 } 841 842#ifdef WE_SET_EVENT 843 /* Generate an event to notify listeners of the change */ 844 if((descr->flags & IW_DESCR_FLAG_EVENT) && 845 ((ret == 0) || (ret == -EIWCOMMIT))) { 846 if(descr->flags & IW_DESCR_FLAG_RESTRICT) 847 /* If the event is restricted, don't 848 * export the payload */ 849 wireless_send_event(dev, cmd, &(iwr->u), NULL); 850 else 851 wireless_send_event(dev, cmd, &(iwr->u), 852 extra); 853 } 854#endif /* WE_SET_EVENT */ 855 856 /* Cleanup - I told you it wasn't that long ;-) */ 857 kfree(extra); 858 } 859 860 /* Call commit handler if needed and defined */ 861 if(ret == -EIWCOMMIT) 862 ret = call_commit_handler(dev); 863 864 /* Here, we will generate the appropriate event if needed */ 865 866 return ret; 867} 868 869/* ---------------------------------------------------------------- */ 870/* 871 * Wrapper to call a private Wireless Extension handler. 872 * We do various checks and also take care of moving data between 873 * user space and kernel space. 874 * It's not as nice and slimline as the standard wrapper. The cause 875 * is struct iw_priv_args, which was not really designed for the 876 * job we are going here. 877 * 878 * IMPORTANT : This function prevent to set and get data on the same 879 * IOCTL and enforce the SET/GET convention. Not doing it would be 880 * far too hairy... 881 * If you need to set and get data at the same time, please don't use 882 * a iw_handler but process it in your ioctl handler (i.e. use the 883 * old driver API). 884 */ 885static inline int ioctl_private_call(struct net_device * dev, 886 struct ifreq * ifr, 887 unsigned int cmd, 888 iw_handler handler) 889{ 890 struct iwreq * iwr = (struct iwreq *) ifr; 891 const struct iw_priv_args * descr = NULL; 892 struct iw_request_info info; 893 int extra_size = 0; 894 int i; 895 int ret = -EINVAL; 896 897 /* Get the description of the IOCTL */ 898 for(i = 0; i < dev->wireless_handlers->num_private_args; i++) 899 if(cmd == dev->wireless_handlers->private_args[i].cmd) { 900 descr = &(dev->wireless_handlers->private_args[i]); 901 break; 902 } 903 904#ifdef WE_IOCTL_DEBUG 905 printk(KERN_DEBUG "%s (WE) : Found private handler for 0x%04X\n", 906 ifr->ifr_name, cmd); 907 if(descr) { 908 printk(KERN_DEBUG "%s (WE) : Name %s, set %X, get %X\n", 909 dev->name, descr->name, 910 descr->set_args, descr->get_args); 911 } 912#endif /* WE_IOCTL_DEBUG */ 913 914 /* Compute the size of the set/get arguments */ 915 if(descr != NULL) { 916 if(IW_IS_SET(cmd)) { 917 int offset = 0; /* For sub-ioctls */ 918 /* Check for sub-ioctl handler */ 919 if(descr->name[0] == '\0') 920 /* Reserve one int for sub-ioctl index */ 921 offset = sizeof(__u32); 922 923 /* Size of set arguments */ 924 extra_size = get_priv_size(descr->set_args); 925 926 /* Does it fits in iwr ? */ 927 if((descr->set_args & IW_PRIV_SIZE_FIXED) && 928 ((extra_size + offset) <= IFNAMSIZ)) 929 extra_size = 0; 930 } else { 931 /* Size of get arguments */ 932 extra_size = get_priv_size(descr->get_args); 933 934 /* Does it fits in iwr ? */ 935 if((descr->get_args & IW_PRIV_SIZE_FIXED) && 936 (extra_size <= IFNAMSIZ)) 937 extra_size = 0; 938 } 939 } 940 941 /* Prepare the call */ 942 info.cmd = cmd; 943 info.flags = 0; 944 945 /* Check if we have a pointer to user space data or not. */ 946 if(extra_size == 0) { 947 /* No extra arguments. Trivial to handle */ 948 ret = handler(dev, &info, &(iwr->u), (char *) &(iwr->u)); 949 } else { 950 char * extra; 951 int err; 952 953 /* Check what user space is giving us */ 954 if(IW_IS_SET(cmd)) { 955 /* Check NULL pointer */ 956 if((iwr->u.data.pointer == NULL) && 957 (iwr->u.data.length != 0)) 958 return -EFAULT; 959 960 /* Does it fits within bounds ? */ 961 if(iwr->u.data.length > (descr->set_args & 962 IW_PRIV_SIZE_MASK)) 963 return -E2BIG; 964 } else { 965 /* Check NULL pointer */ 966 if(iwr->u.data.pointer == NULL) 967 return -EFAULT; 968 } 969 970#ifdef WE_IOCTL_DEBUG 971 printk(KERN_DEBUG "%s (WE) : Malloc %d bytes\n", 972 dev->name, extra_size); 973#endif /* WE_IOCTL_DEBUG */ 974 975 /* Always allocate for max space. Easier, and won't last 976 * long... */ 977 extra = kmalloc(extra_size, GFP_KERNEL); 978 if (extra == NULL) { 979 return -ENOMEM; 980 } 981 982 /* If it is a SET, get all the extra data in here */ 983 if(IW_IS_SET(cmd) && (iwr->u.data.length != 0)) { 984 err = copy_from_user(extra, iwr->u.data.pointer, 985 extra_size); 986 if (err) { 987 kfree(extra); 988 return -EFAULT; 989 } 990#ifdef WE_IOCTL_DEBUG 991 printk(KERN_DEBUG "%s (WE) : Got %d elem\n", 992 dev->name, iwr->u.data.length); 993#endif /* WE_IOCTL_DEBUG */ 994 } 995 996 /* Call the handler */ 997 ret = handler(dev, &info, &(iwr->u), extra); 998 999 /* If we have something to return to the user */ 1000 if (!ret && IW_IS_GET(cmd)) { 1001 1002 /* Adjust for the actual length if it's variable, 1003 * avoid leaking kernel bits outside. */ 1004 if (!(descr->get_args & IW_PRIV_SIZE_FIXED)) { 1005 extra_size = adjust_priv_size(descr->get_args, 1006 &(iwr->u)); 1007 } 1008 1009 err = copy_to_user(iwr->u.data.pointer, extra, 1010 extra_size); 1011 if (err) 1012 ret = -EFAULT; 1013#ifdef WE_IOCTL_DEBUG 1014 printk(KERN_DEBUG "%s (WE) : Wrote %d elem\n", 1015 dev->name, iwr->u.data.length); 1016#endif /* WE_IOCTL_DEBUG */ 1017 } 1018 1019 /* Cleanup - I told you it wasn't that long ;-) */ 1020 kfree(extra); 1021 } 1022 1023 1024 /* Call commit handler if needed and defined */ 1025 if(ret == -EIWCOMMIT) 1026 ret = call_commit_handler(dev); 1027 1028 return ret; 1029} 1030 1031/* ---------------------------------------------------------------- */ 1032/* 1033 * Main IOCTl dispatcher. Called from the main networking code 1034 * (dev_ioctl() in net/core/dev.c). 1035 * Check the type of IOCTL and call the appropriate wrapper... 1036 */ 1037int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd) 1038{ 1039 struct net_device *dev; 1040 iw_handler handler; 1041 1042 /* Permissions are already checked in dev_ioctl() before calling us. 1043 * The copy_to/from_user() of ifr is also dealt with in there */ 1044 1045 /* Make sure the device exist */ 1046 if ((dev = __dev_get_by_name(ifr->ifr_name)) == NULL) 1047 return -ENODEV; 1048 1049 /* A bunch of special cases, then the generic case... 1050 * Note that 'cmd' is already filtered in dev_ioctl() with 1051 * (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) */ 1052 switch(cmd) 1053 { 1054 case SIOCGIWSTATS: 1055 /* Get Wireless Stats */ 1056 return ioctl_standard_call(dev, 1057 ifr, 1058 cmd, 1059 &iw_handler_get_iwstats); 1060 1061 case SIOCGIWPRIV: 1062 /* Check if we have some wireless handlers defined */ 1063 if(dev->wireless_handlers != NULL) { 1064 /* We export to user space the definition of 1065 * the private handler ourselves */ 1066 return ioctl_standard_call(dev, 1067 ifr, 1068 cmd, 1069 &iw_handler_get_private); 1070 } 1071 // ## Fall-through for old API ## 1072 default: 1073 /* Generic IOCTL */ 1074 /* Basic check */ 1075 if (!netif_device_present(dev)) 1076 return -ENODEV; 1077 /* New driver API : try to find the handler */ 1078 handler = get_handler(dev, cmd); 1079 if(handler != NULL) { 1080 /* Standard and private are not the same */ 1081 if(cmd < SIOCIWFIRSTPRIV) 1082 return ioctl_standard_call(dev, 1083 ifr, 1084 cmd, 1085 handler); 1086 else 1087 return ioctl_private_call(dev, 1088 ifr, 1089 cmd, 1090 handler); 1091 } 1092 /* Old driver API : call driver ioctl handler */ 1093 if (dev->do_ioctl) { 1094 return dev->do_ioctl(dev, ifr, cmd); 1095 } 1096 return -EOPNOTSUPP; 1097 } 1098 /* Not reached */ 1099 return -EINVAL; 1100} 1101 1102/********************** RTNETLINK REQUEST API **********************/ 1103/* 1104 * The alternate user space API to configure all those Wireless Extensions 1105 * is through RtNetlink. 1106 * This API support only the new driver API (iw_handler). 1107 * 1108 * This RtNetlink API use the same query/reply model as the ioctl API. 1109 * Maximum effort has been done to fit in the RtNetlink model, and 1110 * we support both RtNetlink Set and RtNelink Get operations. 1111 * On the other hand, we don't offer Dump operations because of the 1112 * following reasons : 1113 * o Large number of parameters, most optional 1114 * o Large size of some parameters (> 100 bytes) 1115 * o Each parameters need to be extracted from hardware 1116 * o Scan requests can take seconds and disable network activity. 1117 * Because of this high cost/overhead, we want to return only the 1118 * parameters the user application is really interested in. 1119 * We could offer partial Dump using the IW_DESCR_FLAG_DUMP flag. 1120 * 1121 * The API uses the standard RtNetlink socket. When the RtNetlink code 1122 * find a IFLA_WIRELESS field in a RtNetlink SET_LINK request, 1123 * it calls here. 1124 */ 1125 1126#ifdef CONFIG_NET_WIRELESS_RTNETLINK 1127/* ---------------------------------------------------------------- */ 1128/* 1129 * Wrapper to call a standard Wireless Extension GET handler. 1130 * We do various checks and call the handler with the proper args. 1131 */ 1132static int rtnetlink_standard_get(struct net_device * dev, 1133 struct iw_event * request, 1134 int request_len, 1135 iw_handler handler, 1136 char ** p_buf, 1137 int * p_len) 1138{ 1139 const struct iw_ioctl_description * descr = NULL; 1140 unsigned int cmd; 1141 union iwreq_data * wrqu; 1142 int hdr_len; 1143 struct iw_request_info info; 1144 char * buffer = NULL; 1145 int buffer_size = 0; 1146 int ret = -EINVAL; 1147 1148 /* Get the description of the Request */ 1149 cmd = request->cmd; 1150 if((cmd - SIOCIWFIRST) >= standard_ioctl_num) 1151 return -EOPNOTSUPP; 1152 descr = &(standard_ioctl[cmd - SIOCIWFIRST]); 1153 1154#ifdef WE_RTNETLINK_DEBUG 1155 printk(KERN_DEBUG "%s (WE.r) : Found standard handler for 0x%04X\n", 1156 dev->name, cmd); 1157 printk(KERN_DEBUG "%s (WE.r) : 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); 1158#endif /* WE_RTNETLINK_DEBUG */ 1159 1160 /* Check if wrqu is complete */ 1161 hdr_len = event_type_size[descr->header_type]; 1162 if(request_len < hdr_len) { 1163#ifdef WE_RTNETLINK_DEBUG 1164 printk(KERN_DEBUG 1165 "%s (WE.r) : Wireless request too short (%d)\n", 1166 dev->name, request_len); 1167#endif /* WE_RTNETLINK_DEBUG */ 1168 return -EINVAL; 1169 } 1170 1171 /* Prepare the call */ 1172 info.cmd = cmd; 1173 info.flags = 0; 1174 1175 /* Check if we have extra data in the reply or not */ 1176 if(descr->header_type != IW_HEADER_TYPE_POINT) { 1177 1178 /* Create the kernel buffer that we will return. 1179 * It's at an offset to match the TYPE_POINT case... */ 1180 buffer_size = request_len + IW_EV_POINT_OFF; 1181 buffer = kmalloc(buffer_size, GFP_KERNEL); 1182 if (buffer == NULL) { 1183 return -ENOMEM; 1184 } 1185 /* Copy event data */ 1186 memcpy(buffer + IW_EV_POINT_OFF, request, request_len); 1187 /* Use our own copy of wrqu */ 1188 wrqu = (union iwreq_data *) (buffer + IW_EV_POINT_OFF 1189 + IW_EV_LCP_LEN); 1190 1191 /* No extra arguments. Trivial to handle */ 1192 ret = handler(dev, &info, wrqu, NULL); 1193 1194 } else { 1195 union iwreq_data wrqu_point; 1196 char * extra = NULL; 1197 int extra_size = 0; 1198 1199 /* Get a temp copy of wrqu (skip pointer) */ 1200 memcpy(((char *) &wrqu_point) + IW_EV_POINT_OFF, 1201 ((char *) request) + IW_EV_LCP_LEN, 1202 IW_EV_POINT_LEN - IW_EV_LCP_LEN); 1203 1204 /* Calculate space needed by arguments. Always allocate 1205 * for max space. Easier, and won't last long... */ 1206 extra_size = descr->max_tokens * descr->token_size; 1207 /* Support for very large requests */ 1208 if((descr->flags & IW_DESCR_FLAG_NOMAX) && 1209 (wrqu_point.data.length > descr->max_tokens)) 1210 extra_size = (wrqu_point.data.length 1211 * descr->token_size); 1212 buffer_size = extra_size + IW_EV_POINT_LEN + IW_EV_POINT_OFF; 1213#ifdef WE_RTNETLINK_DEBUG 1214 printk(KERN_DEBUG "%s (WE.r) : Malloc %d bytes (%d bytes)\n", 1215 dev->name, extra_size, buffer_size); 1216#endif /* WE_RTNETLINK_DEBUG */ 1217 1218 /* Create the kernel buffer that we will return */ 1219 buffer = kmalloc(buffer_size, GFP_KERNEL); 1220 if (buffer == NULL) { 1221 return -ENOMEM; 1222 } 1223 1224 /* Put wrqu in the right place (just before extra). 1225 * Leave space for IWE header and dummy pointer... 1226 * Note that IW_EV_LCP_LEN==4 bytes, so it's still aligned... 1227 */ 1228 memcpy(buffer + IW_EV_LCP_LEN + IW_EV_POINT_OFF, 1229 ((char *) &wrqu_point) + IW_EV_POINT_OFF, 1230 IW_EV_POINT_LEN - IW_EV_LCP_LEN); 1231 wrqu = (union iwreq_data *) (buffer + IW_EV_LCP_LEN); 1232 1233 /* Extra comes logically after that. Offset +12 bytes. */ 1234 extra = buffer + IW_EV_POINT_OFF + IW_EV_POINT_LEN; 1235 1236 /* Call the handler */ 1237 ret = handler(dev, &info, wrqu, extra); 1238 1239 /* Calculate real returned length */ 1240 extra_size = (wrqu->data.length * descr->token_size); 1241 /* Re-adjust reply size */ 1242 request->len = extra_size + IW_EV_POINT_LEN; 1243 1244 /* Put the iwe header where it should, i.e. scrap the 1245 * dummy pointer. */ 1246 memcpy(buffer + IW_EV_POINT_OFF, request, IW_EV_LCP_LEN); 1247 1248#ifdef WE_RTNETLINK_DEBUG 1249 printk(KERN_DEBUG "%s (WE.r) : Reply 0x%04X, hdr_len %d, tokens %d, extra_size %d, buffer_size %d\n", dev->name, cmd, hdr_len, wrqu->data.length, extra_size, buffer_size); 1250#endif /* WE_RTNETLINK_DEBUG */ 1251 1252 /* Check if there is enough buffer up there */ 1253 if(wrqu_point.data.length < wrqu->data.length) 1254 ret = -E2BIG; 1255 } 1256 1257 /* Return the buffer to the caller */ 1258 if (!ret) { 1259 *p_buf = buffer; 1260 *p_len = request->len; 1261 } else { 1262 /* Cleanup */ 1263 if(buffer) 1264 kfree(buffer); 1265 } 1266 1267 return ret; 1268} 1269 1270/* ---------------------------------------------------------------- */ 1271/* 1272 * Wrapper to call a standard Wireless Extension SET handler. 1273 * We do various checks and call the handler with the proper args. 1274 */ 1275static inline int rtnetlink_standard_set(struct net_device * dev, 1276 struct iw_event * request, 1277 int request_len, 1278 iw_handler handler) 1279{ 1280 const struct iw_ioctl_description * descr = NULL; 1281 unsigned int cmd; 1282 union iwreq_data * wrqu; 1283 union iwreq_data wrqu_point; 1284 int hdr_len; 1285 char * extra = NULL; 1286 int extra_size = 0; 1287 struct iw_request_info info; 1288 int ret = -EINVAL; 1289 1290 /* Get the description of the Request */ 1291 cmd = request->cmd; 1292 if((cmd - SIOCIWFIRST) >= standard_ioctl_num) 1293 return -EOPNOTSUPP; 1294 descr = &(standard_ioctl[cmd - SIOCIWFIRST]); 1295 1296#ifdef WE_RTNETLINK_DEBUG 1297 printk(KERN_DEBUG "%s (WE.r) : Found standard SET handler for 0x%04X\n", 1298 dev->name, cmd); 1299 printk(KERN_DEBUG "%s (WE.r) : 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); 1300#endif /* WE_RTNETLINK_DEBUG */ 1301 1302 /* Extract fixed header from request. This is properly aligned. */ 1303 wrqu = &request->u; 1304 1305 /* Check if wrqu is complete */ 1306 hdr_len = event_type_size[descr->header_type]; 1307 if(request_len < hdr_len) { 1308#ifdef WE_RTNETLINK_DEBUG 1309 printk(KERN_DEBUG 1310 "%s (WE.r) : Wireless request too short (%d)\n", 1311 dev->name, request_len); 1312#endif /* WE_RTNETLINK_DEBUG */ 1313 return -EINVAL; 1314 } 1315 1316 /* Prepare the call */ 1317 info.cmd = cmd; 1318 info.flags = 0; 1319 1320 /* Check if we have extra data in the request or not */ 1321 if(descr->header_type != IW_HEADER_TYPE_POINT) { 1322 1323 /* No extra arguments. Trivial to handle */ 1324 ret = handler(dev, &info, wrqu, NULL); 1325 1326 } else { 1327 int extra_len; 1328 1329 /* Put wrqu in the right place (skip pointer) */ 1330 memcpy(((char *) &wrqu_point) + IW_EV_POINT_OFF, 1331 wrqu, IW_EV_POINT_LEN - IW_EV_LCP_LEN); 1332 /* Don't forget about the event code... */ 1333 wrqu = &wrqu_point; 1334 1335 /* Check if number of token fits within bounds */ 1336 if(wrqu_point.data.length > descr->max_tokens) 1337 return -E2BIG; 1338 if(wrqu_point.data.length < descr->min_tokens) 1339 return -EINVAL; 1340 1341 /* Real length of payload */ 1342 extra_len = wrqu_point.data.length * descr->token_size; 1343 1344 /* Check if request is self consistent */ 1345 if((request_len - hdr_len) < extra_len) { 1346#ifdef WE_RTNETLINK_DEBUG 1347 printk(KERN_DEBUG "%s (WE.r) : Wireless request data too short (%d)\n", 1348 dev->name, extra_size); 1349#endif /* WE_RTNETLINK_DEBUG */ 1350 return -EINVAL; 1351 } 1352 1353#ifdef WE_RTNETLINK_DEBUG 1354 printk(KERN_DEBUG "%s (WE.r) : Malloc %d bytes\n", 1355 dev->name, extra_size); 1356#endif /* WE_RTNETLINK_DEBUG */ 1357 1358 /* Always allocate for max space. Easier, and won't last 1359 * long... */ 1360 extra_size = descr->max_tokens * descr->token_size; 1361 extra = kmalloc(extra_size, GFP_KERNEL); 1362 if (extra == NULL) 1363 return -ENOMEM; 1364 1365 /* Copy extra in aligned buffer */ 1366 memcpy(extra, ((char *) request) + hdr_len, extra_len); 1367 1368 /* Call the handler */ 1369 ret = handler(dev, &info, &wrqu_point, extra); 1370 } 1371 1372#ifdef WE_SET_EVENT 1373 /* Generate an event to notify listeners of the change */ 1374 if((descr->flags & IW_DESCR_FLAG_EVENT) && 1375 ((ret == 0) || (ret == -EIWCOMMIT))) { 1376 if(descr->flags & IW_DESCR_FLAG_RESTRICT) 1377 /* If the event is restricted, don't 1378 * export the payload */ 1379 wireless_send_event(dev, cmd, wrqu, NULL); 1380 else 1381 wireless_send_event(dev, cmd, wrqu, extra); 1382 } 1383#endif /* WE_SET_EVENT */ 1384 1385 /* Cleanup - I told you it wasn't that long ;-) */ 1386 if(extra) 1387 kfree(extra); 1388 1389 /* Call commit handler if needed and defined */ 1390 if(ret == -EIWCOMMIT) 1391 ret = call_commit_handler(dev); 1392 1393 return ret; 1394} 1395 1396/* ---------------------------------------------------------------- */ 1397/* 1398 * Wrapper to call a private Wireless Extension GET handler. 1399 * Same as above... 1400 * It's not as nice and slimline as the standard wrapper. The cause 1401 * is struct iw_priv_args, which was not really designed for the 1402 * job we are going here. 1403 * 1404 * IMPORTANT : This function prevent to set and get data on the same 1405 * IOCTL and enforce the SET/GET convention. Not doing it would be 1406 * far too hairy... 1407 * If you need to set and get data at the same time, please don't use 1408 * a iw_handler but process it in your ioctl handler (i.e. use the 1409 * old driver API). 1410 */ 1411static inline int rtnetlink_private_get(struct net_device * dev, 1412 struct iw_event * request, 1413 int request_len, 1414 iw_handler handler, 1415 char ** p_buf, 1416 int * p_len) 1417{ 1418 const struct iw_priv_args * descr = NULL; 1419 unsigned int cmd; 1420 union iwreq_data * wrqu; 1421 int hdr_len; 1422 struct iw_request_info info; 1423 int extra_size = 0; 1424 int i; 1425 char * buffer = NULL; 1426 int buffer_size = 0; 1427 int ret = -EINVAL; 1428 1429 /* Get the description of the Request */ 1430 cmd = request->cmd; 1431 for(i = 0; i < dev->wireless_handlers->num_private_args; i++) 1432 if(cmd == dev->wireless_handlers->private_args[i].cmd) { 1433 descr = &(dev->wireless_handlers->private_args[i]); 1434 break; 1435 } 1436 if(descr == NULL) 1437 return -EOPNOTSUPP; 1438 1439#ifdef WE_RTNETLINK_DEBUG 1440 printk(KERN_DEBUG "%s (WE.r) : Found private handler for 0x%04X\n", 1441 dev->name, cmd); 1442 printk(KERN_DEBUG "%s (WE.r) : Name %s, set %X, get %X\n", 1443 dev->name, descr->name, descr->set_args, descr->get_args); 1444#endif /* WE_RTNETLINK_DEBUG */ 1445 1446 /* Compute the max size of the get arguments */ 1447 extra_size = get_priv_size(descr->get_args); 1448 1449 /* Does it fits in wrqu ? */ 1450 if((descr->get_args & IW_PRIV_SIZE_FIXED) && 1451 (extra_size <= IFNAMSIZ)) { 1452 hdr_len = extra_size; 1453 extra_size = 0; 1454 } else { 1455 hdr_len = IW_EV_POINT_LEN; 1456 } 1457 1458 /* Check if wrqu is complete */ 1459 if(request_len < hdr_len) { 1460#ifdef WE_RTNETLINK_DEBUG 1461 printk(KERN_DEBUG 1462 "%s (WE.r) : Wireless request too short (%d)\n", 1463 dev->name, request_len); 1464#endif /* WE_RTNETLINK_DEBUG */ 1465 return -EINVAL; 1466 } 1467 1468 /* Prepare the call */ 1469 info.cmd = cmd; 1470 info.flags = 0; 1471 1472 /* Check if we have a pointer to user space data or not. */ 1473 if(extra_size == 0) { 1474 1475 /* Create the kernel buffer that we will return. 1476 * It's at an offset to match the TYPE_POINT case... */ 1477 buffer_size = request_len + IW_EV_POINT_OFF; 1478 buffer = kmalloc(buffer_size, GFP_KERNEL); 1479 if (buffer == NULL) { 1480 return -ENOMEM; 1481 } 1482 /* Copy event data */ 1483 memcpy(buffer + IW_EV_POINT_OFF, request, request_len); 1484 /* Use our own copy of wrqu */ 1485 wrqu = (union iwreq_data *) (buffer + IW_EV_POINT_OFF 1486 + IW_EV_LCP_LEN); 1487 1488 /* No extra arguments. Trivial to handle */ 1489 ret = handler(dev, &info, wrqu, (char *) wrqu); 1490 1491 } else { 1492 char * extra; 1493 1494 /* Buffer for full reply */ 1495 buffer_size = extra_size + IW_EV_POINT_LEN + IW_EV_POINT_OFF; 1496 1497#ifdef WE_RTNETLINK_DEBUG 1498 printk(KERN_DEBUG "%s (WE.r) : Malloc %d bytes (%d bytes)\n", 1499 dev->name, extra_size, buffer_size); 1500#endif /* WE_RTNETLINK_DEBUG */ 1501 1502 /* Create the kernel buffer that we will return */ 1503 buffer = kmalloc(buffer_size, GFP_KERNEL); 1504 if (buffer == NULL) { 1505 return -ENOMEM; 1506 } 1507 1508 /* Put wrqu in the right place (just before extra). 1509 * Leave space for IWE header and dummy pointer... 1510 * Note that IW_EV_LCP_LEN==4 bytes, so it's still aligned... 1511 */ 1512 memcpy(buffer + IW_EV_LCP_LEN + IW_EV_POINT_OFF, 1513 ((char *) request) + IW_EV_LCP_LEN, 1514 IW_EV_POINT_LEN - IW_EV_LCP_LEN); 1515 wrqu = (union iwreq_data *) (buffer + IW_EV_LCP_LEN); 1516 1517 /* Extra comes logically after that. Offset +12 bytes. */ 1518 extra = buffer + IW_EV_POINT_OFF + IW_EV_POINT_LEN; 1519 1520 /* Call the handler */ 1521 ret = handler(dev, &info, wrqu, extra); 1522 1523 /* Adjust for the actual length if it's variable, 1524 * avoid leaking kernel bits outside. */ 1525 if (!(descr->get_args & IW_PRIV_SIZE_FIXED)) 1526 extra_size = adjust_priv_size(descr->get_args, wrqu); 1527 /* Re-adjust reply size */ 1528 request->len = extra_size + IW_EV_POINT_LEN; 1529 1530 /* Put the iwe header where it should, i.e. scrap the 1531 * dummy pointer. */ 1532 memcpy(buffer + IW_EV_POINT_OFF, request, IW_EV_LCP_LEN); 1533 1534#ifdef WE_RTNETLINK_DEBUG 1535 printk(KERN_DEBUG "%s (WE.r) : Reply 0x%04X, hdr_len %d, tokens %d, extra_size %d, buffer_size %d\n", dev->name, cmd, hdr_len, wrqu->data.length, extra_size, buffer_size); 1536#endif /* WE_RTNETLINK_DEBUG */ 1537 } 1538 1539 /* Return the buffer to the caller */ 1540 if (!ret) { 1541 *p_buf = buffer; 1542 *p_len = request->len; 1543 } else { 1544 /* Cleanup */ 1545 if(buffer) 1546 kfree(buffer); 1547 } 1548 1549 return ret; 1550} 1551 1552/* ---------------------------------------------------------------- */ 1553/* 1554 * Wrapper to call a private Wireless Extension SET handler. 1555 * Same as above... 1556 * It's not as nice and slimline as the standard wrapper. The cause 1557 * is struct iw_priv_args, which was not really designed for the 1558 * job we are going here. 1559 * 1560 * IMPORTANT : This function prevent to set and get data on the same 1561 * IOCTL and enforce the SET/GET convention. Not doing it would be 1562 * far too hairy... 1563 * If you need to set and get data at the same time, please don't use 1564 * a iw_handler but process it in your ioctl handler (i.e. use the 1565 * old driver API). 1566 */ 1567static inline int rtnetlink_private_set(struct net_device * dev, 1568 struct iw_event * request, 1569 int request_len, 1570 iw_handler handler) 1571{ 1572 const struct iw_priv_args * descr = NULL; 1573 unsigned int cmd; 1574 union iwreq_data * wrqu; 1575 union iwreq_data wrqu_point; 1576 int hdr_len; 1577 char * extra = NULL; 1578 int extra_size = 0; 1579 int offset = 0; /* For sub-ioctls */ 1580 struct iw_request_info info; 1581 int i; 1582 int ret = -EINVAL; 1583 1584 /* Get the description of the Request */ 1585 cmd = request->cmd; 1586 for(i = 0; i < dev->wireless_handlers->num_private_args; i++) 1587 if(cmd == dev->wireless_handlers->private_args[i].cmd) { 1588 descr = &(dev->wireless_handlers->private_args[i]); 1589 break; 1590 } 1591 if(descr == NULL) 1592 return -EOPNOTSUPP; 1593 1594#ifdef WE_RTNETLINK_DEBUG 1595 printk(KERN_DEBUG "%s (WE.r) : Found private handler for 0x%04X\n", 1596 ifr->ifr_name, cmd); 1597 printk(KERN_DEBUG "%s (WE.r) : Name %s, set %X, get %X\n", 1598 dev->name, descr->name, descr->set_args, descr->get_args); 1599#endif /* WE_RTNETLINK_DEBUG */ 1600 1601 /* Compute the size of the set arguments */ 1602 /* Check for sub-ioctl handler */ 1603 if(descr->name[0] == '\0') 1604 /* Reserve one int for sub-ioctl index */ 1605 offset = sizeof(__u32); 1606 1607 /* Size of set arguments */ 1608 extra_size = get_priv_size(descr->set_args); 1609 1610 /* Does it fits in wrqu ? */ 1611 if((descr->set_args & IW_PRIV_SIZE_FIXED) && 1612 (extra_size <= IFNAMSIZ)) { 1613 hdr_len = IW_EV_LCP_LEN + extra_size; 1614 extra_size = 0; 1615 } else { 1616 hdr_len = IW_EV_POINT_LEN; 1617 } 1618 1619 /* Extract fixed header from request. This is properly aligned. */ 1620 wrqu = &request->u; 1621 1622 /* Check if wrqu is complete */ 1623 if(request_len < hdr_len) { 1624#ifdef WE_RTNETLINK_DEBUG 1625 printk(KERN_DEBUG 1626 "%s (WE.r) : Wireless request too short (%d)\n", 1627 dev->name, request_len); 1628#endif /* WE_RTNETLINK_DEBUG */ 1629 return -EINVAL; 1630 } 1631 1632 /* Prepare the call */ 1633 info.cmd = cmd; 1634 info.flags = 0; 1635 1636 /* Check if we have a pointer to user space data or not. */ 1637 if(extra_size == 0) { 1638 1639 /* No extra arguments. Trivial to handle */ 1640 ret = handler(dev, &info, wrqu, (char *) wrqu); 1641 1642 } else { 1643 int extra_len; 1644 1645 /* Put wrqu in the right place (skip pointer) */ 1646 memcpy(((char *) &wrqu_point) + IW_EV_POINT_OFF, 1647 wrqu, IW_EV_POINT_LEN - IW_EV_LCP_LEN); 1648 1649 /* Does it fits within bounds ? */ 1650 if(wrqu_point.data.length > (descr->set_args & 1651 IW_PRIV_SIZE_MASK)) 1652 return -E2BIG; 1653 1654 /* Real length of payload */ 1655 extra_len = adjust_priv_size(descr->set_args, &wrqu_point); 1656 1657 /* Check if request is self consistent */ 1658 if((request_len - hdr_len) < extra_len) { 1659#ifdef WE_RTNETLINK_DEBUG 1660 printk(KERN_DEBUG "%s (WE.r) : Wireless request data too short (%d)\n", 1661 dev->name, extra_size); 1662#endif /* WE_RTNETLINK_DEBUG */ 1663 return -EINVAL; 1664 } 1665 1666#ifdef WE_RTNETLINK_DEBUG 1667 printk(KERN_DEBUG "%s (WE.r) : Malloc %d bytes\n", 1668 dev->name, extra_size); 1669#endif /* WE_RTNETLINK_DEBUG */ 1670 1671 /* Always allocate for max space. Easier, and won't last 1672 * long... */ 1673 extra = kmalloc(extra_size, GFP_KERNEL); 1674 if (extra == NULL) 1675 return -ENOMEM; 1676 1677 /* Copy extra in aligned buffer */ 1678 memcpy(extra, ((char *) request) + hdr_len, extra_len); 1679 1680 /* Call the handler */ 1681 ret = handler(dev, &info, &wrqu_point, extra); 1682 1683 /* Cleanup - I told you it wasn't that long ;-) */ 1684 kfree(extra); 1685 } 1686 1687 /* Call commit handler if needed and defined */ 1688 if(ret == -EIWCOMMIT) 1689 ret = call_commit_handler(dev); 1690 1691 return ret; 1692} 1693 1694/* ---------------------------------------------------------------- */ 1695/* 1696 * Main RtNetlink dispatcher. Called from the main networking code 1697 * (do_getlink() in net/core/rtnetlink.c). 1698 * Check the type of Request and call the appropriate wrapper... 1699 */ 1700int wireless_rtnetlink_get(struct net_device * dev, 1701 char * data, 1702 int len, 1703 char ** p_buf, 1704 int * p_len) 1705{ 1706 struct iw_event * request = (struct iw_event *) data; 1707 iw_handler handler; 1708 1709 /* Check length */ 1710 if(len < IW_EV_LCP_LEN) { 1711 printk(KERN_DEBUG "%s (WE.r) : RtNetlink request too short (%d)\n", 1712 dev->name, len); 1713 return -EINVAL; 1714 } 1715 1716 /* ReCheck length (len may have padding) */ 1717 if(request->len > len) { 1718 printk(KERN_DEBUG "%s (WE.r) : RtNetlink request len invalid (%d-%d)\n", 1719 dev->name, request->len, len); 1720 return -EINVAL; 1721 } 1722 1723 /* Only accept GET requests in here */ 1724 if(!IW_IS_GET(request->cmd)) 1725 return -EOPNOTSUPP; 1726 1727 /* If command is `get the encoding parameters', check if 1728 * the user has the right to do it */ 1729 if (request->cmd == SIOCGIWENCODE || 1730 request->cmd == SIOCGIWENCODEEXT) { 1731 if (!capable(CAP_NET_ADMIN)) 1732 return -EPERM; 1733 } 1734 1735 /* Special cases */ 1736 if(request->cmd == SIOCGIWSTATS) 1737 /* Get Wireless Stats */ 1738 return rtnetlink_standard_get(dev, 1739 request, 1740 request->len, 1741 &iw_handler_get_iwstats, 1742 p_buf, p_len); 1743 if(request->cmd == SIOCGIWPRIV) { 1744 /* Check if we have some wireless handlers defined */ 1745 if(dev->wireless_handlers == NULL) 1746 return -EOPNOTSUPP; 1747 /* Get Wireless Stats */ 1748 return rtnetlink_standard_get(dev, 1749 request, 1750 request->len, 1751 &iw_handler_get_private, 1752 p_buf, p_len); 1753 } 1754 1755 /* Basic check */ 1756 if (!netif_device_present(dev)) 1757 return -ENODEV; 1758 1759 /* Try to find the handler */ 1760 handler = get_handler(dev, request->cmd); 1761 if(handler != NULL) { 1762 /* Standard and private are not the same */ 1763 if(request->cmd < SIOCIWFIRSTPRIV) 1764 return rtnetlink_standard_get(dev, 1765 request, 1766 request->len, 1767 handler, 1768 p_buf, p_len); 1769 else 1770 return rtnetlink_private_get(dev, 1771 request, 1772 request->len, 1773 handler, 1774 p_buf, p_len); 1775 } 1776 1777 return -EOPNOTSUPP; 1778} 1779 1780/* ---------------------------------------------------------------- */ 1781/* 1782 * Main RtNetlink dispatcher. Called from the main networking code 1783 * (do_setlink() in net/core/rtnetlink.c). 1784 * Check the type of Request and call the appropriate wrapper... 1785 */ 1786int wireless_rtnetlink_set(struct net_device * dev, 1787 char * data, 1788 int len) 1789{ 1790 struct iw_event * request = (struct iw_event *) data; 1791 iw_handler handler; 1792 1793 /* Check length */ 1794 if(len < IW_EV_LCP_LEN) { 1795 printk(KERN_DEBUG "%s (WE.r) : RtNetlink request too short (%d)\n", 1796 dev->name, len); 1797 return -EINVAL; 1798 } 1799 1800 /* ReCheck length (len may have padding) */ 1801 if(request->len > len) { 1802 printk(KERN_DEBUG "%s (WE.r) : RtNetlink request len invalid (%d-%d)\n", 1803 dev->name, request->len, len); 1804 return -EINVAL; 1805 } 1806 1807 /* Only accept SET requests in here */ 1808 if(!IW_IS_SET(request->cmd)) 1809 return -EOPNOTSUPP; 1810 1811 /* Basic check */ 1812 if (!netif_device_present(dev)) 1813 return -ENODEV; 1814 1815 /* New driver API : try to find the handler */ 1816 handler = get_handler(dev, request->cmd); 1817 if(handler != NULL) { 1818 /* Standard and private are not the same */ 1819 if(request->cmd < SIOCIWFIRSTPRIV) 1820 return rtnetlink_standard_set(dev, 1821 request, 1822 request->len, 1823 handler); 1824 else 1825 return rtnetlink_private_set(dev, 1826 request, 1827 request->len, 1828 handler); 1829 } 1830 1831 return -EOPNOTSUPP; 1832} 1833#endif /* CONFIG_NET_WIRELESS_RTNETLINK */ 1834 1835 1836/************************* EVENT PROCESSING *************************/ 1837/* 1838 * Process events generated by the wireless layer or the driver. 1839 * Most often, the event will be propagated through rtnetlink 1840 */ 1841 1842#ifdef WE_EVENT_RTNETLINK 1843/* ---------------------------------------------------------------- */ 1844/* 1845 * Locking... 1846 * ---------- 1847 * 1848 * Thanks to Herbert Xu <herbert@gondor.apana.org.au> for fixing 1849 * the locking issue in here and implementing this code ! 1850 * 1851 * The issue : wireless_send_event() is often called in interrupt context, 1852 * while the Netlink layer can never be called in interrupt context. 1853 * The fully formed RtNetlink events are queued, and then a tasklet is run 1854 * to feed those to Netlink. 1855 * The skb_queue is interrupt safe, and its lock is not held while calling 1856 * Netlink, so there is no possibility of dealock. 1857 * Jean II 1858 */ 1859 1860static struct sk_buff_head wireless_nlevent_queue; 1861 1862static int __init wireless_nlevent_init(void) 1863{ 1864 skb_queue_head_init(&wireless_nlevent_queue); 1865 return 0; 1866} 1867 1868subsys_initcall(wireless_nlevent_init); 1869 1870static void wireless_nlevent_process(unsigned long data) 1871{ 1872 struct sk_buff *skb; 1873 1874 while ((skb = skb_dequeue(&wireless_nlevent_queue))) 1875 rtnl_notify(skb, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC); 1876} 1877 1878static DECLARE_TASKLET(wireless_nlevent_tasklet, wireless_nlevent_process, 0); 1879 1880/* ---------------------------------------------------------------- */ 1881/* 1882 * Fill a rtnetlink message with our event data. 1883 * Note that we propage only the specified event and don't dump the 1884 * current wireless config. Dumping the wireless config is far too 1885 * expensive (for each parameter, the driver need to query the hardware). 1886 */ 1887static inline int rtnetlink_fill_iwinfo(struct sk_buff * skb, 1888 struct net_device * dev, 1889 int type, 1890 char * event, 1891 int event_len) 1892{ 1893 struct ifinfomsg *r; 1894 struct nlmsghdr *nlh; 1895 unsigned char *b = skb->tail; 1896 1897 nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(*r)); 1898 r = NLMSG_DATA(nlh); 1899 r->ifi_family = AF_UNSPEC; 1900 r->__ifi_pad = 0; 1901 r->ifi_type = dev->type; 1902 r->ifi_index = dev->ifindex; 1903 r->ifi_flags = dev_get_flags(dev); 1904 r->ifi_change = 0; /* Wireless changes don't affect those flags */ 1905 1906 /* Add the wireless events in the netlink packet */ 1907 RTA_PUT(skb, IFLA_WIRELESS, event_len, event); 1908 1909 nlh->nlmsg_len = skb->tail - b; 1910 return skb->len; 1911 1912nlmsg_failure: 1913rtattr_failure: 1914 skb_trim(skb, b - skb->data); 1915 return -1; 1916} 1917 1918/* ---------------------------------------------------------------- */ 1919/* 1920 * Create and broadcast and send it on the standard rtnetlink socket 1921 * This is a pure clone rtmsg_ifinfo() in net/core/rtnetlink.c 1922 * Andrzej Krzysztofowicz mandated that I used a IFLA_XXX field 1923 * within a RTM_NEWLINK event. 1924 */ 1925static inline void rtmsg_iwinfo(struct net_device * dev, 1926 char * event, 1927 int event_len) 1928{ 1929 struct sk_buff *skb; 1930 int size = NLMSG_GOODSIZE; 1931 1932 skb = alloc_skb(size, GFP_ATOMIC); 1933 if (!skb) 1934 return; 1935 1936 if (rtnetlink_fill_iwinfo(skb, dev, RTM_NEWLINK, 1937 event, event_len) < 0) { 1938 kfree_skb(skb); 1939 return; 1940 } 1941 NETLINK_CB(skb).dst_group = RTNLGRP_LINK; 1942 skb_queue_tail(&wireless_nlevent_queue, skb); 1943 tasklet_schedule(&wireless_nlevent_tasklet); 1944} 1945 1946#endif /* WE_EVENT_RTNETLINK */ 1947 1948/* ---------------------------------------------------------------- */ 1949/* 1950 * Main event dispatcher. Called from other parts and drivers. 1951 * Send the event on the appropriate channels. 1952 * May be called from interrupt context. 1953 */ 1954void wireless_send_event(struct net_device * dev, 1955 unsigned int cmd, 1956 union iwreq_data * wrqu, 1957 char * extra) 1958{ 1959 const struct iw_ioctl_description * descr = NULL; 1960 int extra_len = 0; 1961 struct iw_event *event; /* Mallocated whole event */ 1962 int event_len; /* Its size */ 1963 int hdr_len; /* Size of the event header */ 1964 int wrqu_off = 0; /* Offset in wrqu */ 1965 /* Don't "optimise" the following variable, it will crash */ 1966 unsigned cmd_index; /* *MUST* be unsigned */ 1967 1968 /* Get the description of the Event */ 1969 if(cmd <= SIOCIWLAST) { 1970 cmd_index = cmd - SIOCIWFIRST; 1971 if(cmd_index < standard_ioctl_num) 1972 descr = &(standard_ioctl[cmd_index]); 1973 } else { 1974 cmd_index = cmd - IWEVFIRST; 1975 if(cmd_index < standard_event_num) 1976 descr = &(standard_event[cmd_index]); 1977 } 1978 /* Don't accept unknown events */ 1979 if(descr == NULL) { 1980 /* Note : we don't return an error to the driver, because 1981 * the driver would not know what to do about it. It can't 1982 * return an error to the user, because the event is not 1983 * initiated by a user request. 1984 * The best the driver could do is to log an error message. 1985 * We will do it ourselves instead... 1986 */ 1987 printk(KERN_ERR "%s (WE) : Invalid/Unknown Wireless Event (0x%04X)\n", 1988 dev->name, cmd); 1989 return; 1990 } 1991#ifdef WE_EVENT_DEBUG 1992 printk(KERN_DEBUG "%s (WE) : Got event 0x%04X\n", 1993 dev->name, cmd); 1994 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); 1995#endif /* WE_EVENT_DEBUG */ 1996 1997 /* Check extra parameters and set extra_len */ 1998 if(descr->header_type == IW_HEADER_TYPE_POINT) { 1999 /* Check if number of token fits within bounds */ 2000 if(wrqu->data.length > descr->max_tokens) { 2001 printk(KERN_ERR "%s (WE) : Wireless Event too big (%d)\n", dev->name, wrqu->data.length); 2002 return; 2003 } 2004 if(wrqu->data.length < descr->min_tokens) { 2005 printk(KERN_ERR "%s (WE) : Wireless Event too small (%d)\n", dev->name, wrqu->data.length); 2006 return; 2007 } 2008 /* Calculate extra_len - extra is NULL for restricted events */ 2009 if(extra != NULL) 2010 extra_len = wrqu->data.length * descr->token_size; 2011 /* Always at an offset in wrqu */ 2012 wrqu_off = IW_EV_POINT_OFF; 2013#ifdef WE_EVENT_DEBUG 2014 printk(KERN_DEBUG "%s (WE) : Event 0x%04X, tokens %d, extra_len %d\n", dev->name, cmd, wrqu->data.length, extra_len); 2015#endif /* WE_EVENT_DEBUG */ 2016 } 2017 2018 /* Total length of the event */ 2019 hdr_len = event_type_size[descr->header_type]; 2020 event_len = hdr_len + extra_len; 2021 2022#ifdef WE_EVENT_DEBUG 2023 printk(KERN_DEBUG "%s (WE) : Event 0x%04X, hdr_len %d, wrqu_off %d, event_len %d\n", dev->name, cmd, hdr_len, wrqu_off, event_len); 2024#endif /* WE_EVENT_DEBUG */ 2025 2026 /* Create temporary buffer to hold the event */ 2027 event = kmalloc(event_len, GFP_ATOMIC); 2028 if(event == NULL) 2029 return; 2030 2031 /* Fill event */ 2032 event->len = event_len; 2033 event->cmd = cmd; 2034 memcpy(&event->u, ((char *) wrqu) + wrqu_off, hdr_len - IW_EV_LCP_LEN); 2035 if(extra != NULL) 2036 memcpy(((char *) event) + hdr_len, extra, extra_len); 2037 2038#ifdef WE_EVENT_RTNETLINK 2039 /* Send via the RtNetlink event channel */ 2040 rtmsg_iwinfo(dev, (char *) event, event_len); 2041#endif /* WE_EVENT_RTNETLINK */ 2042 2043 /* Cleanup */ 2044 kfree(event); 2045 2046 return; /* Always success, I guess ;-) */ 2047} 2048 2049/********************** ENHANCED IWSPY SUPPORT **********************/ 2050/* 2051 * In the old days, the driver was handling spy support all by itself. 2052 * Now, the driver can delegate this task to Wireless Extensions. 2053 * It needs to use those standard spy iw_handler in struct iw_handler_def, 2054 * push data to us via wireless_spy_update() and include struct iw_spy_data 2055 * in its private part (and export it in net_device->wireless_data->spy_data). 2056 * One of the main advantage of centralising spy support here is that 2057 * it becomes much easier to improve and extend it without having to touch 2058 * the drivers. One example is the addition of the Spy-Threshold events. 2059 */ 2060 2061/* ---------------------------------------------------------------- */ 2062/* 2063 * Return the pointer to the spy data in the driver. 2064 * Because this is called on the Rx path via wireless_spy_update(), 2065 * we want it to be efficient... 2066 */ 2067static inline struct iw_spy_data * get_spydata(struct net_device *dev) 2068{ 2069 /* This is the new way */ 2070 if(dev->wireless_data) 2071 return(dev->wireless_data->spy_data); 2072 return NULL; 2073} 2074 2075/*------------------------------------------------------------------*/ 2076/* 2077 * Standard Wireless Handler : set Spy List 2078 */ 2079int iw_handler_set_spy(struct net_device * dev, 2080 struct iw_request_info * info, 2081 union iwreq_data * wrqu, 2082 char * extra) 2083{ 2084 struct iw_spy_data * spydata = get_spydata(dev); 2085 struct sockaddr * address = (struct sockaddr *) extra; 2086 2087 /* Make sure driver is not buggy or using the old API */ 2088 if(!spydata) 2089 return -EOPNOTSUPP; 2090 2091 /* Disable spy collection while we copy the addresses. 2092 * While we copy addresses, any call to wireless_spy_update() 2093 * will NOP. This is OK, as anyway the addresses are changing. */ 2094 spydata->spy_number = 0; 2095 2096 /* We want to operate without locking, because wireless_spy_update() 2097 * most likely will happen in the interrupt handler, and therefore 2098 * have its own locking constraints and needs performance. 2099 * The rtnl_lock() make sure we don't race with the other iw_handlers. 2100 * This make sure wireless_spy_update() "see" that the spy list 2101 * is temporarily disabled. */ 2102 wmb(); 2103 2104 /* Are there are addresses to copy? */ 2105 if(wrqu->data.length > 0) { 2106 int i; 2107 2108 /* Copy addresses */ 2109 for(i = 0; i < wrqu->data.length; i++) 2110 memcpy(spydata->spy_address[i], address[i].sa_data, 2111 ETH_ALEN); 2112 /* Reset stats */ 2113 memset(spydata->spy_stat, 0, 2114 sizeof(struct iw_quality) * IW_MAX_SPY); 2115 2116#ifdef WE_SPY_DEBUG 2117 printk(KERN_DEBUG "iw_handler_set_spy() : wireless_data %p, spydata %p, num %d\n", dev->wireless_data, spydata, wrqu->data.length); 2118 for (i = 0; i < wrqu->data.length; i++) 2119 printk(KERN_DEBUG 2120 "%02X:%02X:%02X:%02X:%02X:%02X \n", 2121 spydata->spy_address[i][0], 2122 spydata->spy_address[i][1], 2123 spydata->spy_address[i][2], 2124 spydata->spy_address[i][3], 2125 spydata->spy_address[i][4], 2126 spydata->spy_address[i][5]); 2127#endif /* WE_SPY_DEBUG */ 2128 } 2129 2130 /* Make sure above is updated before re-enabling */ 2131 wmb(); 2132 2133 /* Enable addresses */ 2134 spydata->spy_number = wrqu->data.length; 2135 2136 return 0; 2137} 2138 2139/*------------------------------------------------------------------*/ 2140/* 2141 * Standard Wireless Handler : get Spy List 2142 */ 2143int iw_handler_get_spy(struct net_device * dev, 2144 struct iw_request_info * info, 2145 union iwreq_data * wrqu, 2146 char * extra) 2147{ 2148 struct iw_spy_data * spydata = get_spydata(dev); 2149 struct sockaddr * address = (struct sockaddr *) extra; 2150 int i; 2151 2152 /* Make sure driver is not buggy or using the old API */ 2153 if(!spydata) 2154 return -EOPNOTSUPP; 2155 2156 wrqu->data.length = spydata->spy_number; 2157 2158 /* Copy addresses. */ 2159 for(i = 0; i < spydata->spy_number; i++) { 2160 memcpy(address[i].sa_data, spydata->spy_address[i], ETH_ALEN); 2161 address[i].sa_family = AF_UNIX; 2162 } 2163 /* Copy stats to the user buffer (just after). */ 2164 if(spydata->spy_number > 0) 2165 memcpy(extra + (sizeof(struct sockaddr) *spydata->spy_number), 2166 spydata->spy_stat, 2167 sizeof(struct iw_quality) * spydata->spy_number); 2168 /* Reset updated flags. */ 2169 for(i = 0; i < spydata->spy_number; i++) 2170 spydata->spy_stat[i].updated &= ~IW_QUAL_ALL_UPDATED; 2171 return 0; 2172} 2173 2174/*------------------------------------------------------------------*/ 2175/* 2176 * Standard Wireless Handler : set spy threshold 2177 */ 2178int iw_handler_set_thrspy(struct net_device * dev, 2179 struct iw_request_info *info, 2180 union iwreq_data * wrqu, 2181 char * extra) 2182{ 2183 struct iw_spy_data * spydata = get_spydata(dev); 2184 struct iw_thrspy * threshold = (struct iw_thrspy *) extra; 2185 2186 /* Make sure driver is not buggy or using the old API */ 2187 if(!spydata) 2188 return -EOPNOTSUPP; 2189 2190 /* Just do it */ 2191 memcpy(&(spydata->spy_thr_low), &(threshold->low), 2192 2 * sizeof(struct iw_quality)); 2193 2194 /* Clear flag */ 2195 memset(spydata->spy_thr_under, '\0', sizeof(spydata->spy_thr_under)); 2196 2197#ifdef WE_SPY_DEBUG 2198 printk(KERN_DEBUG "iw_handler_set_thrspy() : low %d ; high %d\n", spydata->spy_thr_low.level, spydata->spy_thr_high.level); 2199#endif /* WE_SPY_DEBUG */ 2200 2201 return 0; 2202} 2203 2204/*------------------------------------------------------------------*/ 2205/* 2206 * Standard Wireless Handler : get spy threshold 2207 */ 2208int iw_handler_get_thrspy(struct net_device * dev, 2209 struct iw_request_info *info, 2210 union iwreq_data * wrqu, 2211 char * extra) 2212{ 2213 struct iw_spy_data * spydata = get_spydata(dev); 2214 struct iw_thrspy * threshold = (struct iw_thrspy *) extra; 2215 2216 /* Make sure driver is not buggy or using the old API */ 2217 if(!spydata) 2218 return -EOPNOTSUPP; 2219 2220 /* Just do it */ 2221 memcpy(&(threshold->low), &(spydata->spy_thr_low), 2222 2 * sizeof(struct iw_quality)); 2223 2224 return 0; 2225} 2226 2227/*------------------------------------------------------------------*/ 2228/* 2229 * Prepare and send a Spy Threshold event 2230 */ 2231static void iw_send_thrspy_event(struct net_device * dev, 2232 struct iw_spy_data * spydata, 2233 unsigned char * address, 2234 struct iw_quality * wstats) 2235{ 2236 union iwreq_data wrqu; 2237 struct iw_thrspy threshold; 2238 2239 /* Init */ 2240 wrqu.data.length = 1; 2241 wrqu.data.flags = 0; 2242 /* Copy address */ 2243 memcpy(threshold.addr.sa_data, address, ETH_ALEN); 2244 threshold.addr.sa_family = ARPHRD_ETHER; 2245 /* Copy stats */ 2246 memcpy(&(threshold.qual), wstats, sizeof(struct iw_quality)); 2247 /* Copy also thresholds */ 2248 memcpy(&(threshold.low), &(spydata->spy_thr_low), 2249 2 * sizeof(struct iw_quality)); 2250 2251#ifdef WE_SPY_DEBUG 2252 printk(KERN_DEBUG "iw_send_thrspy_event() : address %02X:%02X:%02X:%02X:%02X:%02X, level %d, up = %d\n", 2253 threshold.addr.sa_data[0], 2254 threshold.addr.sa_data[1], 2255 threshold.addr.sa_data[2], 2256 threshold.addr.sa_data[3], 2257 threshold.addr.sa_data[4], 2258 threshold.addr.sa_data[5], threshold.qual.level); 2259#endif /* WE_SPY_DEBUG */ 2260 2261 /* Send event to user space */ 2262 wireless_send_event(dev, SIOCGIWTHRSPY, &wrqu, (char *) &threshold); 2263} 2264 2265/* ---------------------------------------------------------------- */ 2266/* 2267 * Call for the driver to update the spy data. 2268 * For now, the spy data is a simple array. As the size of the array is 2269 * small, this is good enough. If we wanted to support larger number of 2270 * spy addresses, we should use something more efficient... 2271 */ 2272void wireless_spy_update(struct net_device * dev, 2273 unsigned char * address, 2274 struct iw_quality * wstats) 2275{ 2276 struct iw_spy_data * spydata = get_spydata(dev); 2277 int i; 2278 int match = -1; 2279 2280 /* Make sure driver is not buggy or using the old API */ 2281 if(!spydata) 2282 return; 2283 2284#ifdef WE_SPY_DEBUG 2285 printk(KERN_DEBUG "wireless_spy_update() : wireless_data %p, spydata %p, address %02X:%02X:%02X:%02X:%02X:%02X\n", dev->wireless_data, spydata, address[0], address[1], address[2], address[3], address[4], address[5]); 2286#endif /* WE_SPY_DEBUG */ 2287 2288 /* Update all records that match */ 2289 for(i = 0; i < spydata->spy_number; i++) 2290 if(!compare_ether_addr(address, spydata->spy_address[i])) { 2291 memcpy(&(spydata->spy_stat[i]), wstats, 2292 sizeof(struct iw_quality)); 2293 match = i; 2294 } 2295 2296 /* Generate an event if we cross the spy threshold. 2297 * To avoid event storms, we have a simple hysteresis : we generate 2298 * event only when we go under the low threshold or above the 2299 * high threshold. */ 2300 if(match >= 0) { 2301 if(spydata->spy_thr_under[match]) { 2302 if(wstats->level > spydata->spy_thr_high.level) { 2303 spydata->spy_thr_under[match] = 0; 2304 iw_send_thrspy_event(dev, spydata, 2305 address, wstats); 2306 } 2307 } else { 2308 if(wstats->level < spydata->spy_thr_low.level) { 2309 spydata->spy_thr_under[match] = 1; 2310 iw_send_thrspy_event(dev, spydata, 2311 address, wstats); 2312 } 2313 } 2314 } 2315} 2316 2317EXPORT_SYMBOL(iw_handler_get_spy); 2318EXPORT_SYMBOL(iw_handler_get_thrspy); 2319EXPORT_SYMBOL(iw_handler_set_spy); 2320EXPORT_SYMBOL(iw_handler_set_thrspy); 2321EXPORT_SYMBOL(wireless_send_event); 2322EXPORT_SYMBOL(wireless_spy_update);