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