diff options
Diffstat (limited to 'linux/montavista-sa-2.4.17-mvl21')
10 files changed, 3458 insertions, 0 deletions
diff --git a/linux/montavista-sa-2.4.17-mvl21/apm-hh-merge.patch b/linux/montavista-sa-2.4.17-mvl21/apm-hh-merge.patch index e69de29bb2..f8343f89e1 100644 --- a/linux/montavista-sa-2.4.17-mvl21/apm-hh-merge.patch +++ b/linux/montavista-sa-2.4.17-mvl21/apm-hh-merge.patch @@ -0,0 +1,561 @@ + +# +# Patch managed by http://www.holgerschurig.de/patcher.html +# + +--- linux-2.4.17_mvl21/arch/arm/mach-sa1100/apm.c~apm-hh-merge ++++ linux-2.4.17_mvl21/arch/arm/mach-sa1100/apm.c +@@ -86,6 +86,8 @@ + int magic; + struct apm_user * next; + int suser: 1; ++ int writer : 1; ++ int reader : 1; + int suspend_wait: 1; + int suspend_result; + int suspends_pending; +@@ -105,7 +107,7 @@ + /* + * Local variables + */ +-//static int suspends_pending; ++static int suspends_pending; + //static int standbys_pending; + //static int ignore_normal_resume; + +@@ -123,8 +125,6 @@ + #else + static int power_off = 1; + #endif +-static int exit_kapmd; +-static int kapmd_running; + + static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue); + static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue); +@@ -192,6 +192,41 @@ + return as->events[as->event_tail]; + } + ++static void queue_event(apm_event_t event, struct apm_user *sender) ++{ ++ struct apm_user * as; ++ if (user_list == NULL) ++ return; ++ for (as = user_list; as != NULL; as = as->next) { ++ if ((as == sender) || (!as->reader)) ++ continue; ++ as->event_head = (as->event_head + 1) % APM_MAX_EVENTS; ++ if (as->event_head == as->event_tail) { ++ static int notified; ++ ++ if (notified++ == 0) ++ printk(KERN_ERR "apm: an event queue overflowed\n"); ++ as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS; ++ } ++ as->events[as->event_head] = event; ++ if ((!as->suser) || (!as->writer)) ++ continue; ++ switch (event) { ++ case APM_SYS_SUSPEND: ++ case APM_USER_SUSPEND: ++ as->suspends_pending++; ++ suspends_pending++; ++ break; ++ ++ case APM_SYS_STANDBY: ++ case APM_USER_STANDBY: ++ as->standbys_pending++; ++ break; ++ } ++ } ++ wake_up_interruptible(&apm_waitqueue); ++} ++ + static int check_apm_user(struct apm_user *as, const char *func) + { + if ((as == NULL) || (as->magic != APM_BIOS_MAGIC)) { +@@ -270,7 +305,6 @@ + return 0; + } + +-extern int pm_do_suspend(void); + + static int do_ioctl(struct inode * inode, struct file *filp, + u_int cmd, u_long arg) +@@ -284,7 +318,17 @@ + return -EPERM; + switch (cmd) { + case APM_IOC_SUSPEND: +- pm_do_suspend(); ++ if (as->suspends_read > 0) { ++ as->suspends_read--; ++ as->suspends_pending--; ++ suspends_pending--; ++ } else { ++ queue_event(APM_USER_SUSPEND, as); ++ } ++ ++ if (suspends_pending <= 0) ++ wake_up(&apm_suspend_waitqueue); ++ + break; + default: + return -EINVAL; +@@ -301,6 +345,20 @@ + return 0; + filp->private_data = NULL; + lock_kernel(); ++ if (user_list == as) ++ user_list = as->next; ++ else { ++ struct apm_user * as1; ++ ++ for (as1 = user_list; ++ (as1 != NULL) && (as1->next != as); ++ as1 = as1->next) ++ ; ++ if (as1 == NULL) ++ printk(KERN_ERR "apm: filp not in user list\n"); ++ else ++ as1->next = as->next; ++ } + unlock_kernel(); + kfree(as); + return 0; +@@ -328,6 +386,8 @@ + * privileged operation -- cevans + */ + as->suser = capable(CAP_SYS_ADMIN); ++ as->writer = (filp->f_mode & FMODE_WRITE) == FMODE_WRITE; ++ as->reader = (filp->f_mode & FMODE_READ) == FMODE_READ; + as->next = user_list; + user_list = as; + filp->private_data = as; +@@ -411,33 +471,7 @@ + return p - buf; + } + +-#ifndef MODULE +-static int __init apm_setup(char *str) +-{ +- int invert; +- +- while ((str != NULL) && (*str != '\0')) { +- if (strncmp(str, "off", 3) == 0) +- apm_disabled = 1; +- if (strncmp(str, "on", 2) == 0) +- apm_disabled = 0; +- invert = (strncmp(str, "no-", 3) == 0); +- if (invert) +- str += 3; +- if (strncmp(str, "debug", 5) == 0) +- debug = !invert; +- if ((strncmp(str, "power-off", 9) == 0) || +- (strncmp(str, "power_off", 9) == 0)) +- power_off = !invert; +- str = strchr(str, ','); +- if (str != NULL) +- str += strspn(str, ", \t"); +- } +- return 1; +-} + +-__setup("apm=", apm_setup); +-#endif + + static struct file_operations apm_bios_fops = { + owner: THIS_MODULE, +@@ -449,13 +483,55 @@ + }; + + static struct miscdevice apm_device = { +- APM_MINOR_DEV, +- "apm_bios", +- &apm_bios_fops ++ minor : APM_MINOR_DEV, ++ name : "apm_bios", ++ fops : &apm_bios_fops + }; + + #define APM_INIT_ERROR_RETURN return -1 + ++static pid_t apmd_pid; ++static DECLARE_COMPLETION(apmd_exited); ++ ++static int apm(void *unused) ++{ ++ unsigned short bx; ++ unsigned short cx; ++ unsigned short dx; ++ int error; ++ char * power_stat; ++ char * bat_stat; ++ DECLARE_WAITQUEUE(wait, current); ++ struct apm_user au, *as; ++ ++ lock_kernel(); ++ ++ daemonize(); ++ ++ strcpy(current->comm, "kapmd"); ++ ++ as = &au; ++ as->magic = APM_BIOS_MAGIC; ++ as->event_tail = as->event_head = 0; ++ as->suspends_pending = as->standbys_pending = 0; ++ as->suspends_read = as->standbys_read = 0; ++ as->suser = 1; ++ as->writer = 1; ++ as->reader = 0; ++ ++ while (!signal_pending (current)) { ++ interruptible_sleep_on(&apm_suspend_waitqueue); ++ ++ pm_suggest_suspend(); ++ ++ queue_event(APM_NORMAL_RESUME, as); ++ } ++ ++ unlock_kernel(); ++ ++ complete_and_exit(&apmd_exited, 0); ++} ++ + /* + * Just start the APM thread. We do NOT want to do APM BIOS + * calls from anything but the APM thread, if for no other reason +@@ -494,18 +570,19 @@ + + misc_register(&apm_device); + ++ apmd_pid = kernel_thread(apm, NULL, 0); ++ + return 0; + } + + static void __exit apm_exit(void) + { + misc_deregister(&apm_device); +- remove_proc_entry("apm", NULL); ++ remove_proc_entry("apm", NULL); ++ kill_proc (apmd_pid, SIGTERM, 1); ++ wait_for_completion(&apmd_exited); + if (power_off) + pm_power_off = NULL; +- exit_kapmd = 1; +- while (kapmd_running) +- schedule(); + pm_active = 0; + } + +@@ -514,6 +591,7 @@ + + MODULE_AUTHOR("Jamey Hicks, pulling bits from original by Stephen Rothwell"); + MODULE_DESCRIPTION("A minimal emulation of APM"); ++MODULE_LICENSE("GPL"); + MODULE_PARM(debug, "i"); + MODULE_PARM_DESC(debug, "Enable debug mode"); + MODULE_PARM(power_off, "i"); +--- linux-2.4.17_mvl21/arch/arm/mach-sa1100/pm.c~apm-hh-merge ++++ linux-2.4.17_mvl21/arch/arm/mach-sa1100/pm.c +@@ -53,6 +53,10 @@ + #include <asm/arch/assabet.h> + #endif + ++#define __KERNEL_SYSCALLS__ ++#include <linux/unistd.h> ++ ++ + /* + * ARGH! Stupid ACPI people. They should define this in linux/sysctl.h, + * NOT linux/acpi.h. +@@ -64,123 +68,6 @@ + #define CTL_ACPI 9999 + #define ACPI_S1_SLP_TYP 19 + +-#ifndef CONFIG_SA1100_BEAGLE +- +-extern void sa1100_cpu_suspend(void); +-extern void sa1100_cpu_resume(void); +- +-extern unsigned long *sleep_save; /* virtual address */ +-extern unsigned long sleep_save_p; /* physical address */ +- +-#define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x +-#define RESTORE(x) x = sleep_save[SLEEP_SAVE_##x] +- +-int sa1110_suspend(void) +-{ +- int retval; +- +- /* set up pointer to sleep parameters */ +- sleep_save = kmalloc (SLEEP_SAVE_SIZE*sizeof(long), GFP_ATOMIC); +- if (!sleep_save) +- return -ENOMEM; +- sleep_save_p = virt_to_phys(sleep_save); +- +- retval = pm_send_all(PM_SUSPEND, (void *)2); +- if (retval) { +- kfree(sleep_save); +- return retval; +- } +- +- cli(); +- +- /* preserve current time */ +- RCNR = xtime.tv_sec; +- +- /* save vital registers */ +- SAVE(OSCR); +- SAVE(OSMR0); +- SAVE(OSMR1); +- SAVE(OSMR2); +- SAVE(OSMR3); +- SAVE(OIER); +- +- SAVE(GPDR); +- SAVE(GRER); +- SAVE(GFER); +- SAVE(GAFR); +- +- SAVE(PPDR); +- SAVE(PPSR); +- SAVE(PPAR); +- SAVE(PSDR); +- +- SAVE(Ser1SDCR0); +- +- SAVE(ICMR); +- +- /* ... maybe a global variable initialized by arch code to set this? */ +- GRER = PWER; +- GFER = 0; +- GEDR = GEDR; +- +- /* Clear previous reset status */ +- RCSR = RCSR_HWR | RCSR_SWR | RCSR_WDR | RCSR_SMR; +- +- /* set resume return address */ +- PSPR = virt_to_phys(sa1100_cpu_resume); +- +- /* go zzz */ +- sa1100_cpu_suspend(); +- +- /* ensure not to come back here if it wasn't intended */ +- PSPR = 0; +- +- DPRINTK("*** made it back from resume\n"); +- +- /* restore registers */ +- RESTORE(GPDR); +- RESTORE(GRER); +- RESTORE(GFER); +- RESTORE(GAFR); +- +- /* clear any edge detect bit */ +- GEDR = GEDR; +- +- RESTORE(PPDR); +- RESTORE(PPSR); +- RESTORE(PPAR); +- RESTORE(PSDR); +- +- RESTORE(Ser1SDCR0); +- +- PSSR = PSSR_PH; +- +- RESTORE(OSMR0); +- RESTORE(OSMR1); +- RESTORE(OSMR2); +- RESTORE(OSMR3); +- RESTORE(OSCR); +- RESTORE(OIER); +- +- ICLR = 0; +- ICCR = 1; +- RESTORE(ICMR); +- +- /* restore current time */ +- xtime.tv_sec = RCNR; +- +- sti(); +- +- kfree (sleep_save); +- +-#ifdef CONFIG_CPU_FREQ +- cpufreq_restore(); +-#endif +- +- return pm_send_all(PM_RESUME, (void *)0); +-} +- +-#else //CONFIG_SA1100_BEAGLE + + typedef struct _tag_SLEEP_SAVED_DATA { + uint wakeup_addr; +@@ -363,9 +250,6 @@ + " ); + } + +-extern void h3600_control_egpio( enum ipaq_egpio_type x, int setp ); +-extern unsigned long h3600_read_egpio( void ); +- + static int GPDR_saved; + static int GPLR_saved; + static int GRER_saved; +@@ -742,21 +626,37 @@ + Ser3UTSR1 = 0xff; + } + +-#endif //CONFIG_SA1100_BEAGLE +- ++/* ++ * If pm_suggest_suspend_hook is non-NULL, it is called by pm_suggest_suspend. ++ * ++ * If sysctl_pm_do_suspend_hook is non-NULL, it is called by sysctl_pm_do_suspend. ++ * If it returns a true value, then pm_suspend is not called. ++ * Use this to hook in apmd, for now. ++ * ++ * -not exported just so that the code compiles ++ */ ++int (*pm_suggest_suspend_hook)(int state); ++int (*pm_sysctl_suspend_hook)(int state); ++int pm_use_sbin_pm_helper = 1; + static char pm_helper_path[128] = "/sbin/pm_helper"; ++extern int exec_usermodehelper(char *path, char **argv, char **envp); ++int debug_pm = 0; ++static int pm_helper_veto = 0; + +-static void ++static int + run_sbin_pm_helper( pm_request_t action ) + { + int i; + char *argv[3], *envp[8]; + + if (!pm_helper_path[0]) +- return; ++ return 2; + + if ( action != PM_SUSPEND && action != PM_RESUME ) +- return; ++ return 1; ++ ++ /* Be root */ ++ current->uid = current->gid = 0; + + i = 0; + argv[i++] = pm_helper_path; +@@ -771,14 +671,15 @@ + envp[i] = 0; + + /* other stuff we want to pass to /sbin/hotplug */ +- call_usermodehelper (argv [0], argv, envp); ++ return exec_usermodehelper (argv [0], argv, envp); + } + ++int pm_force_suspend(void); ++ + int pm_do_suspend(void) + { +- DPRINTK("suggest\n"); +- run_sbin_pm_helper(PM_SUSPEND); +- return 0; ++ DPRINTK("suspend now\n"); ++ return pm_force_suspend(); + } + + #ifdef CONFIG_SA1100_BEAGLE +@@ -863,9 +764,91 @@ + } + #endif + ++int pm_suggest_suspend(void) ++{ ++ int retval; ++ ++ if (pm_suggest_suspend_hook) { ++ if (pm_suggest_suspend_hook(PM_SUSPEND)) ++ return 0; ++ } ++ ++ if (pm_use_sbin_pm_helper) { ++ pid_t pid; ++ int res; ++ int status = 0; ++ unsigned int old_fs; ++ ++ pid = kernel_thread ((int (*) (void *)) run_sbin_pm_helper, (void *) PM_SUSPEND, 0 ); ++ if ( pid < 0 ) ++ return pid; ++ ++ if (debug_pm) ++ printk(KERN_CRIT "%s:%d got pid=%d\n", __FUNCTION__, __LINE__, pid); ++ ++ old_fs = get_fs (); ++ set_fs (get_ds ()); ++ res = waitpid(pid, &status, __WCLONE); ++ set_fs (old_fs); ++ ++ if ( pid != res ) { ++ if (debug_pm) ++ printk(KERN_CRIT ": waitpid returned %d (exit_code=%d); not suspending\n", res, status ); ++ ++ return -1; ++ } ++ ++ /*if ( WIFEXITED(status) && ( WIFEXITSTATUS(status) != 0 )) {*/ ++ if (( status & 0xff7f ) != 0 ) { ++ if (pm_helper_veto) { ++ if (debug_pm) ++ printk(KERN_CRIT "%s: SUSPEND WAS CANCELLED BY pm_helper (exit status %d)\n", __FUNCTION__, status >> 8); ++ return -1; ++ } else { ++ if (debug_pm) ++ printk(KERN_CRIT "%s: pm_helper returned %d, but going ahead anyway\n", __FUNCTION__, status >> 8); ++ } ++ } ++ } ++ ++ if (debug_pm) ++ printk(KERN_CRIT "%s: REALLY SUSPENDING NOW\n", __FUNCTION__ ); ++ ++ if (pm_sysctl_suspend_hook) { ++ if (pm_sysctl_suspend_hook(PM_SUSPEND)) ++ return 0; ++ } ++ ++ retval = pm_do_suspend(); ++ if (retval) { ++ if (debug_pm) ++ printk(KERN_CRIT "pm_suspend returned %d\n", retval); ++ return retval; ++ } ++ ++ if (pm_use_sbin_pm_helper) { ++ pid_t pid; ++ ++ if (debug_pm) ++ printk(KERN_CRIT "%s: running pm_helper for wakeup\n", __FUNCTION__); ++ ++ pid = kernel_thread ((int (*) (void *)) run_sbin_pm_helper, (void *) PM_RESUME, 0 ); ++ if ( pid < 0 ) ++ return pid; ++ ++ if ( pid != waitpid ( pid, NULL, __WCLONE )) ++ return -1; ++ } ++ ++ return 0; ++} ++ ++EXPORT_SYMBOL(pm_suggest_suspend); ++ ++ + static struct ctl_table pm_table[] = + { +- {ACPI_S1_SLP_TYP, "suspend", NULL, 0, 0644, NULL, (proc_handler *)&pm_force_suspend}, ++/* {ACPI_S1_SLP_TYP, "suspend", NULL, 0, 0644, NULL, (proc_handler *)&pm_force_suspend}, */ + {2, "helper", pm_helper_path, sizeof(pm_helper_path), 0644, NULL, (proc_handler *)&proc_dostring}, + #ifdef CONFIG_SA1100_BEAGLE + {3, "wakeup_delayed_time", &wakeup_delayed_time, sizeof(wakeup_delayed_time), 0644, NULL, &proc_dointvec }, diff --git a/linux/montavista-sa-2.4.17-mvl21/beagle-sound.patch b/linux/montavista-sa-2.4.17-mvl21/beagle-sound.patch index e69de29bb2..f4749ca944 100644 --- a/linux/montavista-sa-2.4.17-mvl21/beagle-sound.patch +++ b/linux/montavista-sa-2.4.17-mvl21/beagle-sound.patch @@ -0,0 +1,57 @@ + +# +# Patch managed by http://www.holgerschurig.de/patcher.html +# + +--- linux-2.4.17_mvl21/drivers/sound/assabet-uda1341.c~beagle-sound.patch ++++ linux-2.4.17_mvl21/drivers/sound/assabet-uda1341.c +@@ -49,7 +49,9 @@ + #ifdef CONFIG_SA1100_BEAGLE + #include <linux/timer.h> + #include <linux/sysctl.h> +-#include <asm/io.h> ++ ++#define CCR_ADDR 0xf2000000 ++ + #endif + + #include "sa1100-audio.h" +@@ -142,15 +144,12 @@ + /* MasterIA support full sampling rate in BEAGLE and + provide click from other device */ + +- unsigned int ccr_addr; + unsigned int frg_set; + unsigned int frg_get = -1; + int count; + + audio_samplerate = val; + +- ccr_addr = (unsigned int)__ioremap((unsigned long)0x18000000, 0x00100000, 0); +- + switch(val) { + case 8000: frg_set = 0x01; break; + case 11025: frg_set = 0x02; break; +@@ -165,18 +164,16 @@ + count = 0; + while(frg_set != frg_get) { + /* Ensure CPLD read we gave */ +- *((volatile unsigned int*)(ccr_addr+0x04)) = frg_set; ++ *((volatile unsigned int*)(CCR_ADDR+0x04)) = frg_set; + +- frg_get = *((volatile unsigned int*)(ccr_addr+0x0024)) & 0xFF; ++ frg_get = *((volatile unsigned int*)(CCR_ADDR+0x0024)) & 0xFF; + if ( ++count >= 10 ) { + schedule_timeout( 1 ); + count = 0; + } +-// printk("*** Sound: write %02x[%08x], read %02x[%08x]\n", frg_set, ccr_addr+0x04, +-// frg_get, ccr_addr+0x24); ++// printk("*** Sound: write %02x[%08x], read %02x[%08x]\n", frg_set, CCR_ADDR+0x04, ++// frg_get, CCR_ADDR+0x24); + } +- +- __iounmap((void*)ccr_addr); + #else + struct uda1341_cfg cfg; + u_int clk_ref, clk_div; diff --git a/linux/montavista-sa-2.4.17-mvl21/disable-pcmcia-probe.patch b/linux/montavista-sa-2.4.17-mvl21/disable-pcmcia-probe.patch index e69de29bb2..79ba036323 100644 --- a/linux/montavista-sa-2.4.17-mvl21/disable-pcmcia-probe.patch +++ b/linux/montavista-sa-2.4.17-mvl21/disable-pcmcia-probe.patch @@ -0,0 +1,17 @@ + +# +# Patch managed by http://www.mn-logistik.de/unsupported/pxa250/patcher +# + +--- linux/drivers/pcmcia/Config.in~disable-pcmcia-probe 2003-05-13 11:18:23.000000000 +0200 ++++ linux/drivers/pcmcia/Config.in 2004-05-27 13:59:50.000000000 +0200 +@@ -15,9 +15,6 @@ + tristate 'PCMCIA/CardBus support' CONFIG_PCMCIA + if [ "$CONFIG_PCMCIA" != "n" ]; then + # yes, I really mean the following... +- if [ "$CONFIG_ISA" = "y" -o "$CONFIG_ARCH_SA1100" = "y" ]; then +- define_bool CONFIG_PCMCIA_PROBE y +- fi + if [ "$CONFIG_PCI" != "n" ]; then + bool ' CardBus support' CONFIG_CARDBUS + fi diff --git a/linux/montavista-sa-2.4.17-mvl21/iw240_we15-6.diff b/linux/montavista-sa-2.4.17-mvl21/iw240_we15-6.diff index e69de29bb2..2ebfd8ec12 100644 --- a/linux/montavista-sa-2.4.17-mvl21/iw240_we15-6.diff +++ b/linux/montavista-sa-2.4.17-mvl21/iw240_we15-6.diff @@ -0,0 +1,399 @@ +diff -u -p linux/include/linux/wireless.14.h linux/include/linux/wireless.h +--- linux/include/linux/wireless.14.h Mon Dec 2 18:51:00 2002 ++++ linux/include/linux/wireless.h Mon Dec 2 18:53:35 2002 +@@ -1,7 +1,7 @@ + /* + * This file define a set of standard wireless extensions + * +- * Version : 14 25.1.02 ++ * Version : 15 12.7.02 + * + * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> + * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved. +@@ -80,7 +80,7 @@ + * (there is some stuff that will be added in the future...) + * I just plan to increment with each new version. + */ +-#define WIRELESS_EXT 14 ++#define WIRELESS_EXT 15 + + /* + * Changes : +@@ -153,17 +153,32 @@ + * - Define additional specific event numbers + * - Add "addr" and "param" fields in union iwreq_data + * - AP scanning stuff (SIOCSIWSCAN and friends) ++ * ++ * V14 to V15 ++ * ---------- ++ * - Add IW_PRIV_TYPE_ADDR for struct sockaddr private arg ++ * - Make struct iw_freq signed (both m & e), add explicit padding ++ * - Add IWEVCUSTOM for driver specific event/scanning token ++ * - Add IW_MAX_GET_SPY for driver returning a lot of addresses ++ * - Add IW_TXPOW_RANGE for range of Tx Powers ++ * - Add IWEVREGISTERED & IWEVEXPIRED events for Access Points ++ * - Add IW_MODE_MONITOR for passive monitor + */ + + /**************************** CONSTANTS ****************************/ + + /* -------------------------- IOCTL LIST -------------------------- */ + +-/* Basic operations */ ++/* Wireless Identification */ + #define SIOCSIWCOMMIT 0x8B00 /* Commit pending changes to driver */ + #define SIOCGIWNAME 0x8B01 /* get name == wireless protocol */ +-#define SIOCSIWNWID 0x8B02 /* set network id (the cell) */ +-#define SIOCGIWNWID 0x8B03 /* get network id */ ++/* SIOCGIWNAME is used to verify the presence of Wireless Extensions. ++ * Common values : "IEEE 802.11-DS", "IEEE 802.11-FH", "IEEE 802.11b"... ++ * Don't put the name of your driver there, it's useless. */ ++ ++/* Basic operations */ ++#define SIOCSIWNWID 0x8B02 /* set network id (pre-802.11) */ ++#define SIOCGIWNWID 0x8B03 /* get network id (the cell) */ + #define SIOCSIWFREQ 0x8B04 /* set channel/frequency (Hz) */ + #define SIOCGIWFREQ 0x8B05 /* get channel/frequency (Hz) */ + #define SIOCSIWMODE 0x8B06 /* set operation mode */ +@@ -178,16 +193,18 @@ + #define SIOCGIWPRIV 0x8B0D /* get private ioctl interface info */ + #define SIOCSIWSTATS 0x8B0E /* Unused */ + #define SIOCGIWSTATS 0x8B0F /* Get /proc/net/wireless stats */ ++/* SIOCGIWSTATS is strictly used between user space and the kernel, and ++ * is never passed to the driver (i.e. the driver will never see it). */ + +-/* Mobile IP support */ ++/* Mobile IP support (statistics per MAC address) */ + #define SIOCSIWSPY 0x8B10 /* set spy addresses */ + #define SIOCGIWSPY 0x8B11 /* get spy info (quality of link) */ + + /* Access Point manipulation */ + #define SIOCSIWAP 0x8B14 /* set access point MAC addresses */ + #define SIOCGIWAP 0x8B15 /* get access point MAC addresses */ +-#define SIOCGIWAPLIST 0x8B17 /* get list of access point in range */ +-#define SIOCSIWSCAN 0x8B18 /* trigger scanning */ ++#define SIOCGIWAPLIST 0x8B17 /* Deprecated in favor of scanning */ ++#define SIOCSIWSCAN 0x8B18 /* trigger scanning (list cells) */ + #define SIOCGIWSCAN 0x8B19 /* get scanning results */ + + /* 802.11 specific support */ +@@ -197,9 +214,7 @@ + #define SIOCGIWNICKN 0x8B1D /* get node name/nickname */ + /* As the ESSID and NICKN are strings up to 32 bytes long, it doesn't fit + * within the 'iwreq' structure, so we need to use the 'data' member to +- * point to a string in user space, like it is done for RANGE... +- * The "flags" member indicate if the ESSID is active or not (promiscuous). +- */ ++ * point to a string in user space, like it is done for RANGE... */ + + /* Other parameters useful in 802.11 and some other devices */ + #define SIOCSIWRATE 0x8B20 /* set default bit rate (bps) */ +@@ -257,7 +272,10 @@ + /* Most events use the same identifier as ioctl requests */ + + #define IWEVTXDROP 0x8C00 /* Packet dropped to excessive retry */ +-#define IWEVQUAL 0x8C01 /* Quality part of statistics */ ++#define IWEVQUAL 0x8C01 /* Quality part of statistics (scan) */ ++#define IWEVCUSTOM 0x8C02 /* Driver specific ascii string */ ++#define IWEVREGISTERED 0x8C03 /* Discovered a new node (AP mode) */ ++#define IWEVEXPIRED 0x8C04 /* Expired a node (AP mode) */ + + #define IWEVFIRST 0x8C00 + +@@ -273,7 +291,8 @@ + #define IW_PRIV_TYPE_BYTE 0x1000 /* Char as number */ + #define IW_PRIV_TYPE_CHAR 0x2000 /* Char as character */ + #define IW_PRIV_TYPE_INT 0x4000 /* 32 bits int */ +-#define IW_PRIV_TYPE_FLOAT 0x5000 ++#define IW_PRIV_TYPE_FLOAT 0x5000 /* struct iw_freq */ ++#define IW_PRIV_TYPE_ADDR 0x6000 /* struct sockaddr */ + + #define IW_PRIV_SIZE_FIXED 0x0800 /* Variable or fixed nuber of args */ + +@@ -297,13 +316,16 @@ + + /* Maximum tx powers in the range struct */ + #define IW_MAX_TXPOWER 8 ++/* Note : if you more than 8 TXPowers, just set the max and min or ++ * a few of them in the struct iw_range. */ + + /* Maximum of address that you may set with SPY */ +-#define IW_MAX_SPY 8 ++#define IW_MAX_SPY 8 /* set */ ++#define IW_MAX_GET_SPY 64 /* get */ + + /* Maximum of address that you may get in the + list of access points in range */ +-#define IW_MAX_AP 8 ++#define IW_MAX_AP 64 + + /* Maximum size of the ESSID and NICKN strings */ + #define IW_ESSID_MAX_SIZE 32 +@@ -315,6 +337,7 @@ + #define IW_MODE_MASTER 3 /* Synchronisation master or Access Point */ + #define IW_MODE_REPEAT 4 /* Wireless Repeater (forwarder) */ + #define IW_MODE_SECOND 5 /* Secondary master/repeater (backup) */ ++#define IW_MODE_MONITOR 6 /* Passive monitor (listen only) */ + + /* Maximum number of size of encoding token available + * they are listed in the range structure */ +@@ -350,8 +373,10 @@ + #define IW_POWER_RELATIVE 0x0004 /* Value is not in seconds/ms/us */ + + /* Transmit Power flags available */ ++#define IW_TXPOW_TYPE 0x00FF /* Type of value */ + #define IW_TXPOW_DBM 0x0000 /* Value is in dBm */ + #define IW_TXPOW_MWATT 0x0001 /* Value is in mW */ ++#define IW_TXPOW_RANGE 0x1000 /* Range of value between min/max */ + + /* Retry limits and lifetime flags available */ + #define IW_RETRY_ON 0x0000 /* No details... */ +@@ -376,6 +401,9 @@ + /* Maximum size of returned data */ + #define IW_SCAN_MAX_DATA 4096 /* In bytes */ + ++/* Max number of char in custom event - use multiple of them if needed */ ++#define IW_CUSTOM_MAX 256 /* In bytes */ ++ + /****************************** TYPES ******************************/ + + /* --------------------------- SUBTYPES --------------------------- */ +@@ -411,9 +439,10 @@ struct iw_point + */ + struct iw_freq + { +- __u32 m; /* Mantissa */ +- __u16 e; /* Exponent */ ++ __s32 m; /* Mantissa */ ++ __s16 e; /* Exponent */ + __u8 i; /* List index (when in range struct) */ ++ __u8 pad; /* Unused - just for alignement */ + }; + + /* +diff -u -p linux/include/net/iw_handler.14.h linux/include/net/iw_handler.h +--- linux/include/net/iw_handler.14.h Mon Dec 2 18:51:17 2002 ++++ linux/include/net/iw_handler.h Mon Dec 2 18:54:51 2002 +@@ -1,7 +1,7 @@ + /* + * This file define the new driver API for Wireless Extensions + * +- * Version : 3 17.1.02 ++ * Version : 4 21.6.02 + * + * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> + * Copyright (c) 2001-2002 Jean Tourrilhes, All Rights Reserved. +@@ -206,7 +206,7 @@ + * will be needed... + * I just plan to increment with each new version. + */ +-#define IW_HANDLER_VERSION 3 ++#define IW_HANDLER_VERSION 4 + + /* + * Changes : +@@ -217,6 +217,9 @@ + * - Add Wireless Event support : + * o wireless_send_event() prototype + * o iwe_stream_add_event/point() inline functions ++ * V3 to V4 ++ * -------- ++ * - Reshuffle IW_HEADER_TYPE_XXX to map IW_PRIV_TYPE_XXX changes + */ + + /**************************** CONSTANTS ****************************/ +@@ -233,10 +236,10 @@ + #define IW_HEADER_TYPE_CHAR 2 /* char [IFNAMSIZ] */ + #define IW_HEADER_TYPE_UINT 4 /* __u32 */ + #define IW_HEADER_TYPE_FREQ 5 /* struct iw_freq */ +-#define IW_HEADER_TYPE_POINT 6 /* struct iw_point */ +-#define IW_HEADER_TYPE_PARAM 7 /* struct iw_param */ +-#define IW_HEADER_TYPE_ADDR 8 /* struct sockaddr */ +-#define IW_HEADER_TYPE_QUAL 9 /* struct iw_quality */ ++#define IW_HEADER_TYPE_ADDR 6 /* struct sockaddr */ ++#define IW_HEADER_TYPE_POINT 8 /* struct iw_point */ ++#define IW_HEADER_TYPE_PARAM 9 /* struct iw_param */ ++#define IW_HEADER_TYPE_QUAL 10 /* struct iw_quality */ + + /* Handling flags */ + /* Most are not implemented. I just use them as a reminder of some +diff -u -p linux/net/core/wireless.14.c linux/net/core/wireless.c +--- linux/net/core/wireless.14.c Mon Dec 2 18:51:35 2002 ++++ linux/net/core/wireless.c Mon Dec 2 18:53:10 2002 +@@ -33,8 +33,16 @@ + * o Propagate events as rtnetlink IFLA_WIRELESS option + * o Generate event on selected SET requests + * +- * v4 - 18.04.01 - Jean II ++ * v4 - 18.04.02 - Jean II + * o Fix stupid off by one in iw_ioctl_description : IW_ESSID_MAX_SIZE + 1 ++ * ++ * v5 - 21.06.02 - Jean II ++ * o Add IW_PRIV_TYPE_ADDR in priv_type_size (+cleanup) ++ * o Reshuffle IW_HEADER_TYPE_XXX to map IW_PRIV_TYPE_XXX changes ++ * o Add IWEVCUSTOM for driver specific event/scanning token ++ * o Turn on WE_STRICT_WRITE by default + kernel warning ++ * o Fix WE_STRICT_WRITE in ioctl_export_private() (32 => iw_num) ++ * o Fix off-by-one in test (extra_size <= IFNAMSIZ) + */ + + /***************************** INCLUDES *****************************/ +@@ -50,8 +58,9 @@ + + /**************************** CONSTANTS ****************************/ + +-/* This will be turned on later on... */ +-#undef WE_STRICT_WRITE /* Check write buffer size */ ++/* Enough lenience, let's make sure things are proper... */ ++#define WE_STRICT_WRITE /* Check write buffer size */ ++/* I'll probably drop both the define and kernel message in the next version */ + + /* Debuging stuff */ + #undef WE_IOCTL_DEBUG /* Debug IOCTL API */ +@@ -106,7 +115,7 @@ static const struct iw_ioctl_description + /* SIOCSIWSPY */ + { IW_HEADER_TYPE_POINT, 0, sizeof(struct sockaddr), 0, IW_MAX_SPY, 0}, + /* SIOCGIWSPY */ +- { IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_SPY, 0}, ++ { IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_GET_SPY, 0}, + /* -- hole -- */ + { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, + /* -- hole -- */ +@@ -176,25 +185,41 @@ static const struct iw_ioctl_description + { IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0}, + /* IWEVQUAL */ + { IW_HEADER_TYPE_QUAL, 0, 0, 0, 0, 0}, ++ /* IWEVCUSTOM */ ++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_CUSTOM_MAX, 0}, ++ /* IWEVREGISTERED */ ++ { IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0}, ++ /* IWEVEXPIRED */ ++ { IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0}, + }; + static const int standard_event_num = (sizeof(standard_event) / + sizeof(struct iw_ioctl_description)); + + /* Size (in bytes) of the various private data types */ +-static const char priv_type_size[] = { 0, 1, 1, 0, 4, 4, 0, 0 }; ++static const char priv_type_size[] = { ++ 0, /* IW_PRIV_TYPE_NONE */ ++ 1, /* IW_PRIV_TYPE_BYTE */ ++ 1, /* IW_PRIV_TYPE_CHAR */ ++ 0, /* Not defined */ ++ sizeof(__u32), /* IW_PRIV_TYPE_INT */ ++ sizeof(struct iw_freq), /* IW_PRIV_TYPE_FLOAT */ ++ sizeof(struct sockaddr), /* IW_PRIV_TYPE_ADDR */ ++ 0, /* Not defined */ ++}; + + /* Size (in bytes) of various events */ + static const int event_type_size[] = { +- IW_EV_LCP_LEN, ++ IW_EV_LCP_LEN, /* IW_HEADER_TYPE_NULL */ ++ 0, ++ IW_EV_CHAR_LEN, /* IW_HEADER_TYPE_CHAR */ + 0, +- IW_EV_CHAR_LEN, ++ IW_EV_UINT_LEN, /* IW_HEADER_TYPE_UINT */ ++ IW_EV_FREQ_LEN, /* IW_HEADER_TYPE_FREQ */ ++ IW_EV_ADDR_LEN, /* IW_HEADER_TYPE_ADDR */ + 0, +- IW_EV_UINT_LEN, +- IW_EV_FREQ_LEN, + IW_EV_POINT_LEN, /* Without variable payload */ +- IW_EV_PARAM_LEN, +- IW_EV_ADDR_LEN, +- IW_EV_QUAL_LEN, ++ IW_EV_PARAM_LEN, /* IW_HEADER_TYPE_PARAM */ ++ IW_EV_QUAL_LEN, /* IW_HEADER_TYPE_QUAL */ + }; + + /************************ COMMON SUBROUTINES ************************/ +@@ -440,8 +465,10 @@ static inline int ioctl_export_private(s + return -EFAULT; + #ifdef WE_STRICT_WRITE + /* Check if there is enough buffer up there */ +- if(iwr->u.data.length < (SIOCIWLASTPRIV - SIOCIWFIRSTPRIV + 1)) ++ if(iwr->u.data.length < dev->wireless_handlers->num_private_args) { ++ printk(KERN_ERR "%s (WE) : Buffer for request SIOCGIWPRIV too small (%d<%d)\n", dev->name, iwr->u.data.length, dev->wireless_handlers->num_private_args); + return -E2BIG; ++ } + #endif /* WE_STRICT_WRITE */ + + /* Set the number of available ioctls. */ +@@ -471,6 +498,7 @@ static inline int ioctl_standard_call(st + const struct iw_ioctl_description * descr; + struct iw_request_info info; + int ret = -EINVAL; ++ int user_size = 0; + + /* Get the description of the IOCTL */ + if((cmd - SIOCIWFIRST) >= standard_ioctl_num) +@@ -518,11 +546,8 @@ static inline int ioctl_standard_call(st + /* Check NULL pointer */ + if(iwr->u.data.pointer == NULL) + return -EFAULT; +-#ifdef WE_STRICT_WRITE +- /* Check if there is enough buffer up there */ +- if(iwr->u.data.length < descr->max_tokens) +- return -E2BIG; +-#endif /* WE_STRICT_WRITE */ ++ /* Save user space buffer size for checking */ ++ user_size = iwr->u.data.length; + } + + #ifdef WE_IOCTL_DEBUG +@@ -559,6 +584,15 @@ static inline int ioctl_standard_call(st + + /* If we have something to return to the user */ + if (!ret && IW_IS_GET(cmd)) { ++#ifdef WE_STRICT_WRITE ++ /* Check if there is enough buffer up there */ ++ if(user_size < iwr->u.data.length) { ++ printk(KERN_ERR "%s (WE) : Buffer for request %04X too small (%d<%d)\n", dev->name, cmd, user_size, iwr->u.data.length); ++ kfree(extra); ++ return -E2BIG; ++ } ++#endif /* WE_STRICT_WRITE */ ++ + err = copy_to_user(iwr->u.data.pointer, extra, + iwr->u.data.length * + descr->token_size); +@@ -646,12 +680,18 @@ static inline int ioctl_private_call(str + /* Compute the size of the set/get arguments */ + if(descr != NULL) { + if(IW_IS_SET(cmd)) { ++ int offset = 0; /* For sub-ioctls */ ++ /* Check for sub-ioctl handler */ ++ if(descr->name[0] == '\0') ++ /* Reserve one int for sub-ioctl index */ ++ offset = sizeof(__u32); ++ + /* Size of set arguments */ + extra_size = get_priv_size(descr->set_args); + + /* Does it fits in iwr ? */ + if((descr->set_args & IW_PRIV_SIZE_FIXED) && +- (extra_size < IFNAMSIZ)) ++ ((extra_size + offset) <= IFNAMSIZ)) + extra_size = 0; + } else { + /* Size of set arguments */ +@@ -659,7 +699,7 @@ static inline int ioctl_private_call(str + + /* Does it fits in iwr ? */ + if((descr->get_args & IW_PRIV_SIZE_FIXED) && +- (extra_size < IFNAMSIZ)) ++ (extra_size <= IFNAMSIZ)) + extra_size = 0; + } + } +@@ -925,7 +965,7 @@ void wireless_send_event(struct net_devi + * The best the driver could do is to log an error message. + * We will do it ourselves instead... + */ +- printk(KERN_ERR "%s (WE) : Invalid Wireless Event (0x%04X)\n", ++ printk(KERN_ERR "%s (WE) : Invalid/Unknown Wireless Event (0x%04X)\n", + dev->name, cmd); + return; + } diff --git a/linux/montavista-sa-2.4.17-mvl21/iw_handlers.w13-5.diff b/linux/montavista-sa-2.4.17-mvl21/iw_handlers.w13-5.diff index e69de29bb2..a27a7654a9 100644 --- a/linux/montavista-sa-2.4.17-mvl21/iw_handlers.w13-5.diff +++ b/linux/montavista-sa-2.4.17-mvl21/iw_handlers.w13-5.diff @@ -0,0 +1,1513 @@ +diff -u -p -r --new-file linux/include/linux-w12/netdevice.h linux/include/linux/netdevice.h +--- linux/include/linux-w12/netdevice.h Thu Nov 22 11:47:09 2001 ++++ linux/include/linux/netdevice.h Thu Jan 17 12:00:39 2002 +@@ -278,6 +278,10 @@ struct net_device + struct net_device_stats* (*get_stats)(struct net_device *dev); + struct iw_statistics* (*get_wireless_stats)(struct net_device *dev); + ++ /* List of functions to handle Wireless Extensions (instead of ioctl). ++ * See <net/iw_handler.h> for details. Jean II */ ++ struct iw_handler_def * wireless_handlers; ++ + /* + * This marks the end of the "visible" part of the structure. All + * fields hereafter are internal to the system, and may change at +diff -u -p -r --new-file linux/include/linux-w12/wireless.h linux/include/linux/wireless.h +--- linux/include/linux-w12/wireless.h Thu Nov 22 11:47:12 2001 ++++ linux/include/linux/wireless.h Thu Jan 17 12:04:08 2002 +@@ -1,9 +1,10 @@ + /* + * This file define a set of standard wireless extensions + * +- * Version : 12 5.10.01 ++ * Version : 13 6.12.01 + * + * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> ++ * Copyright (c) 1997-2001 Jean Tourrilhes, All Rights Reserved. + */ + + #ifndef _LINUX_WIRELESS_H +@@ -11,6 +12,8 @@ + + /************************** DOCUMENTATION **************************/ + /* ++ * Initial APIs (1996 -> onward) : ++ * ----------------------------- + * Basically, the wireless extensions are for now a set of standard ioctl + * call + /proc/net/wireless + * +@@ -27,16 +30,27 @@ + * We have the list of command plus a structure descibing the + * data exchanged... + * Note that to add these ioctl, I was obliged to modify : +- * net/core/dev.c (two place + add include) +- * net/ipv4/af_inet.c (one place + add include) ++ * # net/core/dev.c (two place + add include) ++ * # net/ipv4/af_inet.c (one place + add include) + * + * /proc/net/wireless is a copy of /proc/net/dev. + * We have a structure for data passed from the driver to /proc/net/wireless + * Too add this, I've modified : +- * net/core/dev.c (two other places) +- * include/linux/netdevice.h (one place) +- * include/linux/proc_fs.h (one place) ++ * # net/core/dev.c (two other places) ++ * # include/linux/netdevice.h (one place) ++ * # include/linux/proc_fs.h (one place) ++ * ++ * New driver API (2001 -> onward) : ++ * ------------------------------- ++ * This file is only concerned with the user space API and common definitions. ++ * The new driver API is defined and documented in : ++ * # include/net/iw_handler.h + * ++ * Note as well that /proc/net/wireless implementation has now moved in : ++ * # include/linux/wireless.c ++ * ++ * Other comments : ++ * -------------- + * Do not add here things that are redundant with other mechanisms + * (drivers init, ifconfig, /proc/net/dev, ...) and with are not + * wireless specific. +@@ -54,16 +68,14 @@ + #include <linux/socket.h> /* for "struct sockaddr" et al */ + #include <linux/if.h> /* for IFNAMSIZ and co... */ + +-/**************************** CONSTANTS ****************************/ +- +-/* --------------------------- VERSION --------------------------- */ ++/***************************** VERSION *****************************/ + /* + * This constant is used to know the availability of the wireless + * extensions and to know which version of wireless extensions it is + * (there is some stuff that will be added in the future...) + * I just plan to increment with each new version. + */ +-#define WIRELESS_EXT 12 ++#define WIRELESS_EXT 13 + + /* + * Changes : +@@ -123,12 +135,20 @@ + * - Add DEV PRIVATE IOCTL to avoid collisions in SIOCDEVPRIVATE space + * - Add new statistics (frag, retry, beacon) + * - Add average quality (for user space calibration) ++ * ++ * V12 to V13 ++ * ---------- ++ * - Document creation of new driver API. ++ * - Extract union iwreq_data from struct iwreq (for new driver API). ++ * - Rename SIOCSIWNAME as SIOCSIWCOMMIT + */ + ++/**************************** CONSTANTS ****************************/ ++ + /* -------------------------- IOCTL LIST -------------------------- */ + + /* Basic operations */ +-#define SIOCSIWNAME 0x8B00 /* Unused */ ++#define SIOCSIWCOMMIT 0x8B00 /* Commit pending changes to driver */ + #define SIOCGIWNAME 0x8B01 /* get name == wireless protocol */ + #define SIOCSIWNWID 0x8B02 /* set network id (the cell) */ + #define SIOCGIWNWID 0x8B03 /* get network id */ +@@ -414,13 +434,49 @@ struct iw_statistics + + /* ------------------------ IOCTL REQUEST ------------------------ */ + /* ++ * This structure defines the payload of an ioctl, and is used ++ * below. ++ * ++ * Note that this structure should fit on the memory footprint ++ * of iwreq (which is the same as ifreq), which mean a max size of ++ * 16 octets = 128 bits. Warning, pointers might be 64 bits wide... ++ * You should check this when increasing the structures defined ++ * above in this file... ++ */ ++union iwreq_data ++{ ++ /* Config - generic */ ++ char name[IFNAMSIZ]; ++ /* Name : used to verify the presence of wireless extensions. ++ * Name of the protocol/provider... */ ++ ++ struct iw_point essid; /* Extended network name */ ++ struct iw_param nwid; /* network id (or domain - the cell) */ ++ struct iw_freq freq; /* frequency or channel : ++ * 0-1000 = channel ++ * > 1000 = frequency in Hz */ ++ ++ struct iw_param sens; /* signal level threshold */ ++ struct iw_param bitrate; /* default bit rate */ ++ struct iw_param txpower; /* default transmit power */ ++ struct iw_param rts; /* RTS threshold threshold */ ++ struct iw_param frag; /* Fragmentation threshold */ ++ __u32 mode; /* Operation mode */ ++ struct iw_param retry; /* Retry limits & lifetime */ ++ ++ struct iw_point encoding; /* Encoding stuff : tokens */ ++ struct iw_param power; /* PM duration/timeout */ ++ ++ struct sockaddr ap_addr; /* Access point address */ ++ ++ struct iw_point data; /* Other large parameters */ ++}; ++ ++/* + * The structure to exchange data for ioctl. + * This structure is the same as 'struct ifreq', but (re)defined for + * convenience... +- * +- * Note that it should fit on the same memory footprint ! +- * You should check this when increasing the above structures (16 octets) +- * 16 octets = 128 bits. Warning, pointers might be 64 bits wide... ++ * Do I need to remind you about structure size (32 octets) ? + */ + struct iwreq + { +@@ -429,35 +485,8 @@ struct iwreq + char ifrn_name[IFNAMSIZ]; /* if name, e.g. "eth0" */ + } ifr_ifrn; + +- /* Data part */ +- union +- { +- /* Config - generic */ +- char name[IFNAMSIZ]; +- /* Name : used to verify the presence of wireless extensions. +- * Name of the protocol/provider... */ +- +- struct iw_point essid; /* Extended network name */ +- struct iw_param nwid; /* network id (or domain - the cell) */ +- struct iw_freq freq; /* frequency or channel : +- * 0-1000 = channel +- * > 1000 = frequency in Hz */ +- +- struct iw_param sens; /* signal level threshold */ +- struct iw_param bitrate; /* default bit rate */ +- struct iw_param txpower; /* default transmit power */ +- struct iw_param rts; /* RTS threshold threshold */ +- struct iw_param frag; /* Fragmentation threshold */ +- __u32 mode; /* Operation mode */ +- struct iw_param retry; /* Retry limits & lifetime */ +- +- struct iw_point encoding; /* Encoding stuff : tokens */ +- struct iw_param power; /* PM duration/timeout */ +- +- struct sockaddr ap_addr; /* Access point address */ +- +- struct iw_point data; /* Other large parameters */ +- } u; ++ /* Data part (defined just above) */ ++ union iwreq_data u; + }; + + /* -------------------------- IOCTL DATA -------------------------- */ +diff -u -p -r --new-file linux/include/net-w12/iw_handler.h linux/include/net/iw_handler.h +--- linux/include/net-w12/iw_handler.h Wed Dec 31 16:00:00 1969 ++++ linux/include/net/iw_handler.h Thu Jan 17 12:16:46 2002 +@@ -0,0 +1,374 @@ ++/* ++ * This file define the new driver API for Wireless Extensions ++ * ++ * Version : 2 6.12.01 ++ * ++ * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> ++ * Copyright (c) 2001 Jean Tourrilhes, All Rights Reserved. ++ */ ++ ++#ifndef _IW_HANDLER_H ++#define _IW_HANDLER_H ++ ++/************************** DOCUMENTATION **************************/ ++/* ++ * Initial driver API (1996 -> onward) : ++ * ----------------------------------- ++ * The initial API just sends the IOCTL request received from user space ++ * to the driver (via the driver ioctl handler). The driver has to ++ * handle all the rest... ++ * ++ * The initial API also defines a specific handler in struct net_device ++ * to handle wireless statistics. ++ * ++ * The initial APIs served us well and has proven a reasonably good design. ++ * However, there is a few shortcommings : ++ * o No events, everything is a request to the driver. ++ * o Large ioctl function in driver with gigantic switch statement ++ * (i.e. spaghetti code). ++ * o Driver has to mess up with copy_to/from_user, and in many cases ++ * does it unproperly. Common mistakes are : ++ * * buffer overflows (no checks or off by one checks) ++ * * call copy_to/from_user with irq disabled ++ * o The user space interface is tied to ioctl because of the use ++ * copy_to/from_user. ++ * ++ * New driver API (2001 -> onward) : ++ * ------------------------------- ++ * The new driver API is just a bunch of standard functions (handlers), ++ * each handling a specific Wireless Extension. The driver just export ++ * the list of handler it supports, and those will be called apropriately. ++ * ++ * I tried to keep the main advantage of the previous API (simplicity, ++ * efficiency and light weight), and also I provide a good dose of backward ++ * compatibility (most structures are the same, driver can use both API ++ * simultaneously, ...). ++ * Hopefully, I've also addressed the shortcomming of the initial API. ++ * ++ * The advantage of the new API are : ++ * o Handling of Extensions in driver broken in small contained functions ++ * o Tighter checks of ioctl before calling the driver ++ * o Flexible commit strategy (at least, the start of it) ++ * o Backward compatibility (can be mixed with old API) ++ * o Driver doesn't have to worry about memory and user-space issues ++ * The last point is important for the following reasons : ++ * o You are now able to call the new driver API from any API you ++ * want (including from within other parts of the kernel). ++ * o Common mistakes are avoided (buffer overflow, user space copy ++ * with irq disabled and so on). ++ * ++ * The Drawback of the new API are : ++ * o bloat (especially kernel) ++ * o need to migrate existing drivers to new API ++ * My initial testing shows that the new API adds around 3kB to the kernel ++ * and save between 0 and 5kB from a typical driver. ++ * Also, as all structures and data types are unchanged, the migration is ++ * quite straightforward (but tedious). ++ * ++ * --- ++ * ++ * The new driver API is defined below in this file. User space should ++ * not be aware of what's happening down there... ++ * ++ * A new kernel wrapper is in charge of validating the IOCTLs and calling ++ * the appropriate driver handler. This is implemented in : ++ * # net/core/wireless.c ++ * ++ * The driver export the list of handlers in : ++ * # include/linux/netdevice.h (one place) ++ * ++ * The new driver API is available for WIRELESS_EXT >= 13. ++ * Good luck with migration to the new API ;-) ++ */ ++ ++/* ---------------------- THE IMPLEMENTATION ---------------------- */ ++/* ++ * Some of the choice I've made are pretty controversials. Defining an ++ * API is very much weighting compromises. This goes into some of the ++ * details and the thinking behind the implementation. ++ * ++ * Implementation goals : ++ * -------------------- ++ * The implementation goals were as follow : ++ * o Obvious : you should not need a PhD to understand what's happening, ++ * the benefit is easier maintainance. ++ * o Flexible : it should accomodate a wide variety of driver ++ * implementations and be as flexible as the old API. ++ * o Lean : it should be efficient memory wise to minimise the impact ++ * on kernel footprint. ++ * o Transparent to user space : the large number of user space ++ * applications that use Wireless Extensions should not need ++ * any modifications. ++ * ++ * Array of functions versus Struct of functions ++ * --------------------------------------------- ++ * 1) Having an array of functions allow the kernel code to access the ++ * handler in a single lookup, which is much more efficient (think hash ++ * table here). ++ * 2) The only drawback is that driver writer may put their handler in ++ * the wrong slot. This is trivial to test (I set the frequency, the ++ * bitrate changes). Once the handler is in the proper slot, it will be ++ * there forever, because the array is only extended at the end. ++ * 3) Backward/forward compatibility : adding new handler just require ++ * extending the array, so you can put newer driver in older kernel ++ * without having to patch the kernel code (and vice versa). ++ * ++ * All handler are of the same generic type ++ * ---------------------------------------- ++ * That's a feature !!! ++ * 1) Having a generic handler allow to have generic code, which is more ++ * efficient. If each of the handler was individually typed I would need ++ * to add a big switch in the kernel (== more bloat). This solution is ++ * more scalable, adding new Wireless Extensions doesn't add new code. ++ * 2) You can use the same handler in different slots of the array. For ++ * hardware, it may be more efficient or logical to handle multiple ++ * Wireless Extensions with a single function, and the API allow you to ++ * do that. (An example would be a single record on the card to control ++ * both bitrate and frequency, the handler would read the old record, ++ * modify it according to info->cmd and rewrite it). ++ * ++ * Functions prototype uses union iwreq_data ++ * ----------------------------------------- ++ * Some would have prefered functions defined this way : ++ * static int mydriver_ioctl_setrate(struct net_device *dev, ++ * long rate, int auto) ++ * 1) The kernel code doesn't "validate" the content of iwreq_data, and ++ * can't do it (different hardware may have different notion of what a ++ * valid frequency is), so we don't pretend that we do it. ++ * 2) The above form is not extendable. If I want to add a flag (for ++ * example to distinguish setting max rate and basic rate), I would ++ * break the prototype. Using iwreq_data is more flexible. ++ * 3) Also, the above form is not generic (see above). ++ * 4) I don't expect driver developper using the wrong field of the ++ * union (Doh !), so static typechecking doesn't add much value. ++ * 5) Lastly, you can skip the union by doing : ++ * static int mydriver_ioctl_setrate(struct net_device *dev, ++ * struct iw_request_info *info, ++ * struct iw_param *rrq, ++ * char *extra) ++ * And then adding the handler in the array like this : ++ * (iw_handler) mydriver_ioctl_setrate, // SIOCSIWRATE ++ * ++ * Using functions and not a registry ++ * ---------------------------------- ++ * Another implementation option would have been for every instance to ++ * define a registry (a struct containing all the Wireless Extensions) ++ * and only have a function to commit the registry to the hardware. ++ * 1) This approach can be emulated by the current code, but not ++ * vice versa. ++ * 2) Some drivers don't keep any configuration in the driver, for them ++ * adding such a registry would be a significant bloat. ++ * 3) The code to translate from Wireless Extension to native format is ++ * needed anyway, so it would not reduce significantely the amount of code. ++ * 4) The current approach only selectively translate Wireless Extensions ++ * to native format and only selectively set, whereas the registry approach ++ * would require to translate all WE and set all parameters for any single ++ * change. ++ * 5) For many Wireless Extensions, the GET operation return the current ++ * dynamic value, not the value that was set. ++ * ++ * This header is <net/iw_handler.h> ++ * --------------------------------- ++ * 1) This header is kernel space only and should not be exported to ++ * user space. Headers in "include/linux/" are exported, headers in ++ * "include/net/" are not. ++ * ++ * Mixed 32/64 bit issues ++ * ---------------------- ++ * The Wireless Extensions are designed to be 64 bit clean, by using only ++ * datatypes with explicit storage size. ++ * There are some issues related to kernel and user space using different ++ * memory model, and in particular 64bit kernel with 32bit user space. ++ * The problem is related to struct iw_point, that contains a pointer ++ * that *may* need to be translated. ++ * This is quite messy. The new API doesn't solve this problem (it can't), ++ * but is a step in the right direction : ++ * 1) Meta data about each ioctl is easily available, so we know what type ++ * of translation is needed. ++ * 2) The move of data between kernel and user space is only done in a single ++ * place in the kernel, so adding specific hooks in there is possible. ++ * 3) In the long term, it allows to move away from using ioctl as the ++ * user space API. ++ * ++ * So many comments and so few code ++ * -------------------------------- ++ * That's a feature. Comments won't bloat the resulting kernel binary. ++ */ ++ ++/***************************** INCLUDES *****************************/ ++ ++#include <linux/wireless.h> /* IOCTL user space API */ ++ ++/***************************** VERSION *****************************/ ++/* ++ * This constant is used to know which version of the driver API is ++ * available. Hopefully, this will be pretty stable and no changes ++ * will be needed... ++ * I just plan to increment with each new version. ++ */ ++#define IW_HANDLER_VERSION 2 ++ ++/**************************** CONSTANTS ****************************/ ++ ++/* Special error message for the driver to indicate that we ++ * should do a commit after return from the iw_handler */ ++#define EIWCOMMIT EINPROGRESS ++ ++/* Flags available in struct iw_request_info */ ++#define IW_REQUEST_FLAG_NONE 0x0000 /* No flag so far */ ++ ++/* Type of headers we know about (basically union iwreq_data) */ ++#define IW_HEADER_TYPE_NULL 0 /* Not available */ ++#define IW_HEADER_TYPE_CHAR 2 /* char [IFNAMSIZ] */ ++#define IW_HEADER_TYPE_UINT 4 /* __u32 */ ++#define IW_HEADER_TYPE_FREQ 5 /* struct iw_freq */ ++#define IW_HEADER_TYPE_POINT 6 /* struct iw_point */ ++#define IW_HEADER_TYPE_PARAM 7 /* struct iw_param */ ++#define IW_HEADER_TYPE_ADDR 8 /* struct sockaddr */ ++ ++/* Handling flags */ ++/* Most are not implemented. I just use them as a reminder of some ++ * cool features we might need one day ;-) */ ++#define IW_DESCR_FLAG_NONE 0x0000 /* Obvious */ ++/* Wrapper level flags */ ++#define IW_DESCR_FLAG_DUMP 0x0001 /* Not part of the dump command */ ++#define IW_DESCR_FLAG_EVENT 0x0002 /* Generate an event on SET */ ++#define IW_DESCR_FLAG_RESTRICT 0x0004 /* GET request is ROOT only */ ++/* Driver level flags */ ++#define IW_DESCR_FLAG_WAIT 0x0100 /* Wait for driver event */ ++ ++/****************************** TYPES ******************************/ ++ ++/* ----------------------- WIRELESS HANDLER ----------------------- */ ++/* ++ * A wireless handler is just a standard function, that looks like the ++ * ioctl handler. ++ * We also define there how a handler list look like... As the Wireless ++ * Extension space is quite dense, we use a simple array, which is faster ++ * (that's the perfect hash table ;-). ++ */ ++ ++/* ++ * Meta data about the request passed to the iw_handler. ++ * Most handlers can safely ignore what's in there. ++ * The 'cmd' field might come handy if you want to use the same handler ++ * for multiple command... ++ * This struct is also my long term insurance. I can add new fields here ++ * without breaking the prototype of iw_handler... ++ */ ++struct iw_request_info ++{ ++ __u16 cmd; /* Wireless Extension command */ ++ __u16 flags; /* More to come ;-) */ ++}; ++ ++/* ++ * This is how a function handling a Wireless Extension should look ++ * like (both get and set, standard and private). ++ */ ++typedef int (*iw_handler)(struct net_device *dev, struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra); ++ ++/* ++ * This define all the handler that the driver export. ++ * As you need only one per driver type, please use a static const ++ * shared by all driver instances... Same for the members... ++ * This will be linked from net_device in <linux/netdevice.h> ++ */ ++struct iw_handler_def ++{ ++ /* Number of handlers defined (more precisely, index of the ++ * last defined handler + 1) */ ++ __u16 num_standard; ++ __u16 num_private; ++ /* Number of private arg description */ ++ __u16 num_private_args; ++ ++ /* Array of handlers for standard ioctls ++ * We will call dev->wireless_handlers->standard[ioctl - SIOCSIWNAME] ++ */ ++ iw_handler * standard; ++ ++ /* Array of handlers for private ioctls ++ * Will call dev->wireless_handlers->private[ioctl - SIOCIWFIRSTPRIV] ++ */ ++ iw_handler * private; ++ ++ /* Arguments of private handler. This one is just a list, so you ++ * can put it in any order you want and should not leave holes... ++ * We will automatically export that to user space... */ ++ struct iw_priv_args * private_args; ++ ++ /* In the long term, get_wireless_stats will move from ++ * 'struct net_device' to here, to minimise bloat. */ ++}; ++ ++/* ----------------------- WIRELESS EVENTS ----------------------- */ ++/* ++ * Currently we don't support events, so let's just plan for the ++ * future... ++ */ ++ ++/* ++ * A Wireless Event. ++ */ ++// How do we define short header ? We don't want a flag on length. ++// Probably a flag on event ? Highest bit to zero... ++struct iw_event ++{ ++ __u16 length; /* Lenght of this stuff */ ++ __u16 event; /* Wireless IOCTL */ ++ union iwreq_data header; /* IOCTL fixed payload */ ++ char extra[0]; /* Optional IOCTL data */ ++}; ++ ++/* ---------------------- IOCTL DESCRIPTION ---------------------- */ ++/* ++ * One of the main goal of the new interface is to deal entirely with ++ * user space/kernel space memory move. ++ * For that, we need to know : ++ * o if iwreq is a pointer or contain the full data ++ * o what is the size of the data to copy ++ * ++ * For private IOCTLs, we use the same rules as used by iwpriv and ++ * defined in struct iw_priv_args. ++ * ++ * For standard IOCTLs, things are quite different and we need to ++ * use the stuctures below. Actually, this struct is also more ++ * efficient, but that's another story... ++ */ ++ ++/* ++ * Describe how a standard IOCTL looks like. ++ */ ++struct iw_ioctl_description ++{ ++ __u8 header_type; /* NULL, iw_point or other */ ++ __u8 token_type; /* Future */ ++ __u16 token_size; /* Granularity of payload */ ++ __u16 min_tokens; /* Min acceptable token number */ ++ __u16 max_tokens; /* Max acceptable token number */ ++ __u32 flags; /* Special handling of the request */ ++}; ++ ++/* Need to think of short header translation table. Later. */ ++ ++/**************************** PROTOTYPES ****************************/ ++/* ++ * Functions part of the Wireless Extensions (defined in net/core/wireless.c). ++ * Those may be called only within the kernel. ++ */ ++ ++/* First : function strictly used inside the kernel */ ++ ++/* Handle /proc/net/wireless, called in net/code/dev.c */ ++extern int dev_get_wireless_info(char * buffer, char **start, off_t offset, ++ int length); ++ ++/* Handle IOCTLs, called in net/code/dev.c */ ++extern int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd); ++ ++/* Second : functions that may be called by driver modules */ ++/* None yet */ ++ ++#endif /* _LINUX_WIRELESS_H */ +diff -u -p -r --new-file linux/net/core-w12/Makefile linux/net/core/Makefile +--- linux/net/core-w12/Makefile Tue Oct 30 15:08:12 2001 ++++ linux/net/core/Makefile Thu Jan 17 11:06:07 2002 +@@ -26,5 +26,8 @@ obj-$(CONFIG_NET) += dev.o dev_mcast.o d + obj-$(CONFIG_NETFILTER) += netfilter.o + obj-$(CONFIG_NET_DIVERT) += dv.o + obj-$(CONFIG_NET_PROFILE) += profile.o ++obj-$(CONFIG_NET_RADIO) += wireless.o ++# Ugly. I wish all wireless drivers were moved in drivers/net/wireless ++obj-$(CONFIG_NET_PCMCIA_RADIO) += wireless.o + + include $(TOPDIR)/Rules.make +diff -u -p -r --new-file linux/net/core-w12/dev.c linux/net/core/dev.c +--- linux/net/core-w12/dev.c Wed Nov 7 14:39:36 2001 ++++ linux/net/core/dev.c Thu Jan 17 11:06:07 2002 +@@ -102,6 +102,7 @@ + #include <linux/module.h> + #if defined(CONFIG_NET_RADIO) || defined(CONFIG_NET_PCMCIA_RADIO) + #include <linux/wireless.h> /* Note : will define WIRELESS_EXT */ ++#include <net/iw_handler.h> + #endif /* CONFIG_NET_RADIO || CONFIG_NET_PCMCIA_RADIO */ + #ifdef CONFIG_PLIP + extern int plip_init(void); +@@ -1796,122 +1797,6 @@ static int dev_proc_stats(char *buffer, + #endif /* CONFIG_PROC_FS */ + + +-#ifdef WIRELESS_EXT +-#ifdef CONFIG_PROC_FS +- +-/* +- * Print one entry of /proc/net/wireless +- * This is a clone of /proc/net/dev (just above) +- */ +-static int sprintf_wireless_stats(char *buffer, struct net_device *dev) +-{ +- /* Get stats from the driver */ +- struct iw_statistics *stats = (dev->get_wireless_stats ? +- dev->get_wireless_stats(dev) : +- (struct iw_statistics *) NULL); +- int size; +- +- if (stats != (struct iw_statistics *) NULL) { +- size = sprintf(buffer, +- "%6s: %04x %3d%c %3d%c %3d%c %6d %6d %6d %6d %6d %6d\n", +- dev->name, +- stats->status, +- stats->qual.qual, +- stats->qual.updated & 1 ? '.' : ' ', +- stats->qual.level, +- stats->qual.updated & 2 ? '.' : ' ', +- stats->qual.noise, +- stats->qual.updated & 4 ? '.' : ' ', +- stats->discard.nwid, +- stats->discard.code, +- stats->discard.fragment, +- stats->discard.retries, +- stats->discard.misc, +- stats->miss.beacon); +- stats->qual.updated = 0; +- } +- else +- size = 0; +- +- return size; +-} +- +-/* +- * Print info for /proc/net/wireless (print all entries) +- * This is a clone of /proc/net/dev (just above) +- */ +-static int dev_get_wireless_info(char * buffer, char **start, off_t offset, +- int length) +-{ +- int len = 0; +- off_t begin = 0; +- off_t pos = 0; +- int size; +- +- struct net_device * dev; +- +- size = sprintf(buffer, +- "Inter-| sta-| Quality | Discarded packets | Missed\n" +- " face | tus | link level noise | nwid crypt frag retry misc | beacon\n" +- ); +- +- pos += size; +- len += size; +- +- read_lock(&dev_base_lock); +- for (dev = dev_base; dev != NULL; dev = dev->next) { +- size = sprintf_wireless_stats(buffer + len, dev); +- len += size; +- pos = begin + len; +- +- if (pos < offset) { +- len = 0; +- begin = pos; +- } +- if (pos > offset + length) +- break; +- } +- read_unlock(&dev_base_lock); +- +- *start = buffer + (offset - begin); /* Start of wanted data */ +- len -= (offset - begin); /* Start slop */ +- if (len > length) +- len = length; /* Ending slop */ +- if (len < 0) +- len = 0; +- +- return len; +-} +-#endif /* CONFIG_PROC_FS */ +- +-/* +- * Allow programatic access to /proc/net/wireless even if /proc +- * doesn't exist... Also more efficient... +- */ +-static inline int dev_iwstats(struct net_device *dev, struct ifreq *ifr) +-{ +- /* Get stats from the driver */ +- struct iw_statistics *stats = (dev->get_wireless_stats ? +- dev->get_wireless_stats(dev) : +- (struct iw_statistics *) NULL); +- +- if (stats != (struct iw_statistics *) NULL) { +- struct iwreq * wrq = (struct iwreq *)ifr; +- +- /* Copy statistics to the user buffer */ +- if(copy_to_user(wrq->u.data.pointer, stats, +- sizeof(struct iw_statistics))) +- return -EFAULT; +- +- /* Check if we need to clear the update flag */ +- if(wrq->u.data.flags != 0) +- stats->qual.updated = 0; +- return(0); +- } else +- return -EOPNOTSUPP; +-} +-#endif /* WIRELESS_EXT */ +- + /** + * netdev_set_master - set up master/slave pair + * @slave: slave device +@@ -2209,11 +2094,6 @@ static int dev_ifsioc(struct ifreq *ifr, + notifier_call_chain(&netdev_chain, NETDEV_CHANGENAME, dev); + return 0; + +-#ifdef WIRELESS_EXT +- case SIOCGIWSTATS: +- return dev_iwstats(dev, ifr); +-#endif /* WIRELESS_EXT */ +- + /* + * Unknown or private ioctl + */ +@@ -2239,17 +2119,6 @@ static int dev_ifsioc(struct ifreq *ifr, + return -EOPNOTSUPP; + } + +-#ifdef WIRELESS_EXT +- if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) { +- if (dev->do_ioctl) { +- if (!netif_device_present(dev)) +- return -ENODEV; +- return dev->do_ioctl(dev, ifr, cmd); +- } +- return -EOPNOTSUPP; +- } +-#endif /* WIRELESS_EXT */ +- + } + return -EINVAL; + } +@@ -2431,7 +2300,8 @@ int dev_ioctl(unsigned int cmd, void *ar + } + dev_load(ifr.ifr_name); + rtnl_lock(); +- ret = dev_ifsioc(&ifr, cmd); ++ /* Follow me in net/core/wireless.c */ ++ ret = wireless_process_ioctl(&ifr, cmd); + rtnl_unlock(); + if (!ret && IW_IS_GET(cmd) && + copy_to_user(arg, &ifr, sizeof(struct ifreq))) +@@ -2856,6 +2726,7 @@ int __init net_dev_init(void) + proc_net_create("dev", 0, dev_get_info); + create_proc_read_entry("net/softnet_stat", 0, 0, dev_proc_stats, NULL); + #ifdef WIRELESS_EXT ++ /* Available in net/core/wireless.c */ + proc_net_create("wireless", 0, dev_get_wireless_info); + #endif /* WIRELESS_EXT */ + #endif /* CONFIG_PROC_FS */ +diff -u -p -r --new-file linux/net/core-w12/wireless.c linux/net/core/wireless.c +--- linux/net/core-w12/wireless.c Wed Dec 31 16:00:00 1969 ++++ linux/net/core/wireless.c Mon Jan 21 11:13:23 2002 +@@ -0,0 +1,733 @@ ++/* ++ * This file implement the Wireless Extensions APIs. ++ * ++ * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> ++ * Copyright (c) 1997-2001 Jean Tourrilhes, All Rights Reserved. ++ * ++ * (As all part of the Linux kernel, this file is GPL) ++ */ ++ ++/************************** DOCUMENTATION **************************/ ++/* ++ * API definition : ++ * -------------- ++ * See <linux/wireless.h> for details of the APIs and the rest. ++ * ++ * History : ++ * ------- ++ * ++ * v1 - 5.12.01 - Jean II ++ * o Created this file. ++ * ++ * v2 - 13.12.01 - Jean II ++ * o Move /proc/net/wireless stuff from net/core/dev.c to here ++ * o Make Wireless Extension IOCTLs go through here ++ * o Added iw_handler handling ;-) ++ * o Added standard ioctl description ++ * o Initial dumb commit strategy based on orinoco.c ++ */ ++ ++/***************************** INCLUDES *****************************/ ++ ++#include <asm/uaccess.h> /* copy_to_user() */ ++#include <linux/config.h> /* Not needed ??? */ ++#include <linux/types.h> /* off_t */ ++#include <linux/netdevice.h> /* struct ifreq, dev_get_by_name() */ ++ ++#include <linux/wireless.h> /* Pretty obvious */ ++#include <net/iw_handler.h> /* New driver API */ ++ ++/**************************** CONSTANTS ****************************/ ++ ++/* This will be turned on later on... */ ++#undef WE_STRICT_WRITE /* Check write buffer size */ ++ ++/* Debuging stuff */ ++#undef WE_IOCTL_DEBUG /* Debug IOCTL API */ ++ ++/************************* GLOBAL VARIABLES *************************/ ++/* ++ * You should not use global variables, because or re-entrancy. ++ * On our case, it's only const, so it's OK... ++ */ ++static const struct iw_ioctl_description standard_ioctl[] = { ++ /* SIOCSIWCOMMIT (internal) */ ++ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, ++ /* SIOCGIWNAME */ ++ { IW_HEADER_TYPE_CHAR, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP}, ++ /* SIOCSIWNWID */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, IW_DESCR_FLAG_EVENT}, ++ /* SIOCGIWNWID */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP}, ++ /* SIOCSIWFREQ */ ++ { IW_HEADER_TYPE_FREQ, 0, 0, 0, 0, IW_DESCR_FLAG_EVENT}, ++ /* SIOCGIWFREQ */ ++ { IW_HEADER_TYPE_FREQ, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP}, ++ /* SIOCSIWMODE */ ++ { IW_HEADER_TYPE_UINT, 0, 0, 0, 0, IW_DESCR_FLAG_EVENT}, ++ /* SIOCGIWMODE */ ++ { IW_HEADER_TYPE_UINT, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP}, ++ /* SIOCSIWSENS */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++ /* SIOCGIWSENS */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++ /* SIOCSIWRANGE */ ++ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, ++ /* SIOCGIWRANGE */ ++ { IW_HEADER_TYPE_POINT, 0, 1, 0, sizeof(struct iw_range), IW_DESCR_FLAG_DUMP}, ++ /* SIOCSIWPRIV */ ++ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, ++ /* SIOCGIWPRIV (handled directly by us) */ ++ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, ++ /* SIOCSIWSTATS */ ++ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, ++ /* SIOCGIWSTATS (handled directly by us) */ ++ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP}, ++ /* SIOCSIWSPY */ ++ { IW_HEADER_TYPE_POINT, 0, sizeof(struct sockaddr), 0, IW_MAX_SPY, 0}, ++ /* SIOCGIWSPY */ ++ { IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_SPY, 0}, ++ /* -- hole -- */ ++ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, ++ /* -- hole -- */ ++ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, ++ /* SIOCSIWAP */ ++ { IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0}, ++ /* SIOCGIWAP */ ++ { IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP}, ++ /* -- hole -- */ ++ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, ++ /* SIOCGIWAPLIST */ ++ { IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_AP, 0}, ++ /* -- hole -- */ ++ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, ++ /* -- hole -- */ ++ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, ++ /* SIOCSIWESSID */ ++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, IW_DESCR_FLAG_EVENT}, ++ /* SIOCGIWESSID */ ++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, IW_DESCR_FLAG_DUMP}, ++ /* SIOCSIWNICKN */ ++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, 0}, ++ /* SIOCGIWNICKN */ ++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, 0}, ++ /* -- hole -- */ ++ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, ++ /* -- hole -- */ ++ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, ++ /* SIOCSIWRATE */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++ /* SIOCGIWRATE */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++ /* SIOCSIWRTS */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++ /* SIOCGIWRTS */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++ /* SIOCSIWFRAG */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++ /* SIOCGIWFRAG */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++ /* SIOCSIWTXPOW */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++ /* SIOCGIWTXPOW */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++ /* SIOCSIWRETRY */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++ /* SIOCGIWRETRY */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++ /* SIOCSIWENCODE */ ++ { IW_HEADER_TYPE_POINT, 4, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT}, ++ /* SIOCGIWENCODE */ ++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_DUMP | IW_DESCR_FLAG_RESTRICT}, ++ /* SIOCSIWPOWER */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++ /* SIOCGIWPOWER */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++}; ++ ++/* Size (in bytes) of the various private data types */ ++char priv_type_size[] = { 0, 1, 1, 0, 4, 4, 0, 0 }; ++ ++/************************ COMMON SUBROUTINES ************************/ ++/* ++ * Stuff that may be used in various place or doesn't fit in one ++ * of the section below. ++ */ ++ ++/* ---------------------------------------------------------------- */ ++/* ++ * Return the driver handler associated with a specific Wireless Extension. ++ * Called from various place, so make sure it remains efficient. ++ */ ++static inline iw_handler get_handler(struct net_device *dev, ++ unsigned int cmd) ++{ ++ unsigned int index; /* MUST be unsigned */ ++ ++ /* Check if we have some wireless handlers defined */ ++ if(dev->wireless_handlers == NULL) ++ return NULL; ++ ++ /* Try as a standard command */ ++ index = cmd - SIOCIWFIRST; ++ if(index < dev->wireless_handlers->num_standard) ++ return dev->wireless_handlers->standard[index]; ++ ++ /* Try as a private command */ ++ index = cmd - SIOCIWFIRSTPRIV; ++ if(index < dev->wireless_handlers->num_private) ++ return dev->wireless_handlers->private[index]; ++ ++ /* Not found */ ++ return NULL; ++} ++ ++/* ---------------------------------------------------------------- */ ++/* ++ * Get statistics out of the driver ++ */ ++static inline struct iw_statistics *get_wireless_stats(struct net_device *dev) ++{ ++ return (dev->get_wireless_stats ? ++ dev->get_wireless_stats(dev) : ++ (struct iw_statistics *) NULL); ++ /* In the future, get_wireless_stats may move from 'struct net_device' ++ * to 'struct iw_handler_def', to de-bloat struct net_device. ++ * Definitely worse a thought... */ ++} ++ ++/* ---------------------------------------------------------------- */ ++/* ++ * Call the commit handler in the driver ++ * (if exist and if conditions are right) ++ * ++ * Note : our current commit strategy is currently pretty dumb, ++ * but we will be able to improve on that... ++ * The goal is to try to agreagate as many changes as possible ++ * before doing the commit. Drivers that will define a commit handler ++ * are usually those that need a reset after changing parameters, so ++ * we want to minimise the number of reset. ++ * A cool idea is to use a timer : at each "set" command, we re-set the ++ * timer, when the timer eventually fires, we call the driver. ++ * Hopefully, more on that later. ++ * ++ * Also, I'm waiting to see how many people will complain about the ++ * netif_running(dev) test. I'm open on that one... ++ * Hopefully, the driver will remember to do a commit in "open()" ;-) ++ */ ++static inline int call_commit_handler(struct net_device * dev) ++{ ++ if((netif_running(dev)) && ++ (dev->wireless_handlers->standard[0] != NULL)) { ++ /* Call the commit handler on the driver */ ++ return dev->wireless_handlers->standard[0](dev, NULL, ++ NULL, NULL); ++ } else ++ return 0; /* Command completed successfully */ ++} ++ ++/* ---------------------------------------------------------------- */ ++/* ++ * Number of private arguments ++ */ ++static inline int get_priv_size(__u16 args) ++{ ++ int num = args & IW_PRIV_SIZE_MASK; ++ int type = (args & IW_PRIV_TYPE_MASK) >> 12; ++ ++ return num * priv_type_size[type]; ++} ++ ++ ++/******************** /proc/net/wireless SUPPORT ********************/ ++/* ++ * The /proc/net/wireless file is a human readable user-space interface ++ * exporting various wireless specific statistics from the wireless devices. ++ * This is the most popular part of the Wireless Extensions ;-) ++ * ++ * This interface is a pure clone of /proc/net/dev (in net/core/dev.c). ++ * The content of the file is basically the content of "struct iw_statistics". ++ */ ++ ++#ifdef CONFIG_PROC_FS ++ ++/* ---------------------------------------------------------------- */ ++/* ++ * Print one entry (line) of /proc/net/wireless ++ */ ++static inline int sprintf_wireless_stats(char *buffer, struct net_device *dev) ++{ ++ /* Get stats from the driver */ ++ struct iw_statistics *stats; ++ int size; ++ ++ stats = get_wireless_stats(dev); ++ if (stats != (struct iw_statistics *) NULL) { ++ size = sprintf(buffer, ++ "%6s: %04x %3d%c %3d%c %3d%c %6d %6d %6d %6d %6d %6d\n", ++ dev->name, ++ stats->status, ++ stats->qual.qual, ++ stats->qual.updated & 1 ? '.' : ' ', ++ stats->qual.level, ++ stats->qual.updated & 2 ? '.' : ' ', ++ stats->qual.noise, ++ stats->qual.updated & 4 ? '.' : ' ', ++ stats->discard.nwid, ++ stats->discard.code, ++ stats->discard.fragment, ++ stats->discard.retries, ++ stats->discard.misc, ++ stats->miss.beacon); ++ stats->qual.updated = 0; ++ } ++ else ++ size = 0; ++ ++ return size; ++} ++ ++/* ---------------------------------------------------------------- */ ++/* ++ * Print info for /proc/net/wireless (print all entries) ++ */ ++int dev_get_wireless_info(char * buffer, char **start, off_t offset, ++ int length) ++{ ++ int len = 0; ++ off_t begin = 0; ++ off_t pos = 0; ++ int size; ++ ++ struct net_device * dev; ++ ++ size = sprintf(buffer, ++ "Inter-| sta-| Quality | Discarded packets | Missed\n" ++ " face | tus | link level noise | nwid crypt frag retry misc | beacon\n" ++ ); ++ ++ pos += size; ++ len += size; ++ ++ read_lock(&dev_base_lock); ++ for (dev = dev_base; dev != NULL; dev = dev->next) { ++ size = sprintf_wireless_stats(buffer + len, dev); ++ len += size; ++ pos = begin + len; ++ ++ if (pos < offset) { ++ len = 0; ++ begin = pos; ++ } ++ if (pos > offset + length) ++ break; ++ } ++ read_unlock(&dev_base_lock); ++ ++ *start = buffer + (offset - begin); /* Start of wanted data */ ++ len -= (offset - begin); /* Start slop */ ++ if (len > length) ++ len = length; /* Ending slop */ ++ if (len < 0) ++ len = 0; ++ ++ return len; ++} ++#endif /* CONFIG_PROC_FS */ ++ ++/************************** IOCTL SUPPORT **************************/ ++/* ++ * The original user space API to configure all those Wireless Extensions ++ * is through IOCTLs. ++ * In there, we check if we need to call the new driver API (iw_handler) ++ * or just call the driver ioctl handler. ++ */ ++ ++/* ---------------------------------------------------------------- */ ++/* ++ * Allow programatic access to /proc/net/wireless even if /proc ++ * doesn't exist... Also more efficient... ++ */ ++static inline int dev_iwstats(struct net_device *dev, struct ifreq *ifr) ++{ ++ /* Get stats from the driver */ ++ struct iw_statistics *stats; ++ ++ stats = get_wireless_stats(dev); ++ if (stats != (struct iw_statistics *) NULL) { ++ struct iwreq * wrq = (struct iwreq *)ifr; ++ ++ /* Copy statistics to the user buffer */ ++ if(copy_to_user(wrq->u.data.pointer, stats, ++ sizeof(struct iw_statistics))) ++ return -EFAULT; ++ ++ /* Check if we need to clear the update flag */ ++ if(wrq->u.data.flags != 0) ++ stats->qual.updated = 0; ++ return 0; ++ } else ++ return -EOPNOTSUPP; ++} ++ ++/* ---------------------------------------------------------------- */ ++/* ++ * Export the driver private handler definition ++ * They will be picked up by tools like iwpriv... ++ */ ++static inline int ioctl_export_private(struct net_device * dev, ++ struct ifreq * ifr) ++{ ++ struct iwreq * iwr = (struct iwreq *) ifr; ++ ++ /* Check if the driver has something to export */ ++ if((dev->wireless_handlers->num_private_args == 0) || ++ (dev->wireless_handlers->private_args == NULL)) ++ return -EOPNOTSUPP; ++ ++ /* Check NULL pointer */ ++ if(iwr->u.data.pointer == NULL) ++ return -EFAULT; ++#ifdef WE_STRICT_WRITE ++ /* Check if there is enough buffer up there */ ++ if(iwr->u.data.length < (SIOCIWLASTPRIV - SIOCIWFIRSTPRIV + 1)) ++ return -E2BIG; ++#endif /* WE_STRICT_WRITE */ ++ ++ /* Set the number of available ioctls. */ ++ iwr->u.data.length = dev->wireless_handlers->num_private_args; ++ ++ /* Copy structure to the user buffer. */ ++ if (copy_to_user(iwr->u.data.pointer, ++ dev->wireless_handlers->private_args, ++ sizeof(struct iw_priv_args) * iwr->u.data.length)) ++ return -EFAULT; ++ ++ return 0; ++} ++ ++/* ---------------------------------------------------------------- */ ++/* ++ * Wrapper to call a standard Wireless Extension handler. ++ * We do various checks and also take care of moving data between ++ * user space and kernel space. ++ */ ++static inline int ioctl_standard_call(struct net_device * dev, ++ struct ifreq * ifr, ++ unsigned int cmd, ++ iw_handler handler) ++{ ++ struct iwreq * iwr = (struct iwreq *) ifr; ++ const struct iw_ioctl_description * descr; ++ struct iw_request_info info; ++ int ret = -EINVAL; ++ ++ /* Get the description of the IOCTL */ ++ descr = &(standard_ioctl[cmd - SIOCIWFIRST]); ++ ++#ifdef WE_IOCTL_DEBUG ++ printk(KERN_DEBUG "%s : Found standard handler for 0x%04X\n", ++ ifr->ifr_name, cmd); ++ printk(KERN_DEBUG "Header type : %d, token type : %d, token_size : %d, max_token : %d\n", descr->header_type, descr->token_type, descr->token_size, descr->max_tokens); ++#endif /* WE_IOCTL_DEBUG */ ++ ++ /* Prepare the call */ ++ info.cmd = cmd; ++ info.flags = 0; ++ ++ /* Check if we have a pointer to user space data or not */ ++ if(descr->header_type != IW_HEADER_TYPE_POINT) { ++ /* No extra arguments. Trivial to handle */ ++ ret = handler(dev, &info, &(iwr->u), NULL); ++ } else { ++ char * extra; ++ int err; ++ ++ /* Check what user space is giving us */ ++ if(IW_IS_SET(cmd)) { ++ /* Check NULL pointer */ ++ if((iwr->u.data.pointer == NULL) && ++ (iwr->u.data.length != 0)) ++ return -EFAULT; ++ /* Check if number of token fits within bounds */ ++ if(iwr->u.data.length > descr->max_tokens) ++ return -E2BIG; ++ if(iwr->u.data.length < descr->min_tokens) ++ return -EINVAL; ++ } else { ++ /* Check NULL pointer */ ++ if(iwr->u.data.pointer == NULL) ++ return -EFAULT; ++#ifdef WE_STRICT_WRITE ++ /* Check if there is enough buffer up there */ ++ if(iwr->u.data.length < descr->max_tokens) ++ return -E2BIG; ++#endif /* WE_STRICT_WRITE */ ++ } ++ ++#ifdef WE_IOCTL_DEBUG ++ printk(KERN_DEBUG "Malloc %d bytes\n", ++ descr->max_tokens * descr->token_size); ++#endif /* WE_IOCTL_DEBUG */ ++ ++ /* Always allocate for max space. Easier, and won't last ++ * long... */ ++ extra = kmalloc(descr->max_tokens * descr->token_size, ++ GFP_KERNEL); ++ if (extra == NULL) { ++ return -ENOMEM; ++ } ++ ++ /* If it is a SET, get all the extra data in here */ ++ if(IW_IS_SET(cmd) && (iwr->u.data.length != 0)) { ++ err = copy_from_user(extra, iwr->u.data.pointer, ++ iwr->u.data.length * ++ descr->token_size); ++ if (err) { ++ kfree(extra); ++ return -EFAULT; ++ } ++#ifdef WE_IOCTL_DEBUG ++ printk(KERN_DEBUG "Got %d bytes\n", ++ iwr->u.data.length * descr->token_size); ++#endif /* WE_IOCTL_DEBUG */ ++ } ++ ++ /* Call the handler */ ++ ret = handler(dev, &info, &(iwr->u), extra); ++ ++ /* If we have something to return to the user */ ++ if (!ret && IW_IS_GET(cmd)) { ++ err = copy_to_user(iwr->u.data.pointer, extra, ++ iwr->u.data.length * ++ descr->token_size); ++ if (err) ++ ret = -EFAULT; ++#ifdef WE_IOCTL_DEBUG ++ printk(KERN_DEBUG "Wrote %d bytes\n", ++ iwr->u.data.length * descr->token_size); ++#endif /* WE_IOCTL_DEBUG */ ++ } ++ ++ /* Cleanup - I told you it wasn't that long ;-) */ ++ kfree(extra); ++ } ++ ++ /* Call commit handler if needed and defined */ ++ if(ret == -EIWCOMMIT) ++ ret = call_commit_handler(dev); ++ ++ /* Here, we will generate the appropriate event if needed */ ++ ++ return ret; ++} ++ ++/* ---------------------------------------------------------------- */ ++/* ++ * Wrapper to call a private Wireless Extension handler. ++ * We do various checks and also take care of moving data between ++ * user space and kernel space. ++ * It's not as nice and slimline as the standard wrapper. The cause ++ * is struct iw_priv_args, which was not really designed for the ++ * job we are going here. ++ * ++ * IMPORTANT : This function prevent to set and get data on the same ++ * IOCTL and enforce the SET/GET convention. Not doing it would be ++ * far too hairy... ++ * If you need to set and get data at the same time, please don't use ++ * a iw_handler but process it in your ioctl handler (i.e. use the ++ * old driver API). ++ */ ++static inline int ioctl_private_call(struct net_device * dev, ++ struct ifreq * ifr, ++ unsigned int cmd, ++ iw_handler handler) ++{ ++ struct iwreq * iwr = (struct iwreq *) ifr; ++ struct iw_priv_args * descr = NULL; ++ struct iw_request_info info; ++ int extra_size = 0; ++ int i; ++ int ret = -EINVAL; ++ ++ /* Get the description of the IOCTL */ ++ for(i = 0; i < dev->wireless_handlers->num_private_args; i++) ++ if(cmd == dev->wireless_handlers->private_args[i].cmd) { ++ descr = &(dev->wireless_handlers->private_args[i]); ++ break; ++ } ++ ++#ifdef WE_IOCTL_DEBUG ++ printk(KERN_DEBUG "%s : Found private handler for 0x%04X\n", ++ ifr->ifr_name, cmd); ++ if(descr) { ++ printk(KERN_DEBUG "Name %s, set %X, get %X\n", ++ descr->name, descr->set_args, descr->get_args); ++ } ++#endif /* WE_IOCTL_DEBUG */ ++ ++ /* Compute the size of the set/get arguments */ ++ if(descr != NULL) { ++ if(IW_IS_SET(cmd)) { ++ /* Size of set arguments */ ++ extra_size = get_priv_size(descr->set_args); ++ ++ /* Does it fits in iwr ? */ ++ if((descr->set_args & IW_PRIV_SIZE_FIXED) && ++ (extra_size < IFNAMSIZ)) ++ extra_size = 0; ++ } else { ++ /* Size of set arguments */ ++ extra_size = get_priv_size(descr->get_args); ++ ++ /* Does it fits in iwr ? */ ++ if((descr->get_args & IW_PRIV_SIZE_FIXED) && ++ (extra_size < IFNAMSIZ)) ++ extra_size = 0; ++ } ++ } ++ ++ /* Prepare the call */ ++ info.cmd = cmd; ++ info.flags = 0; ++ ++ /* Check if we have a pointer to user space data or not. */ ++ if(extra_size == 0) { ++ /* No extra arguments. Trivial to handle */ ++ ret = handler(dev, &info, &(iwr->u), (char *) &(iwr->u)); ++ } else { ++ char * extra; ++ int err; ++ ++ /* Check what user space is giving us */ ++ if(IW_IS_SET(cmd)) { ++ /* Check NULL pointer */ ++ if((iwr->u.data.pointer == NULL) && ++ (iwr->u.data.length != 0)) ++ return -EFAULT; ++ ++ /* Does it fits within bounds ? */ ++ if(iwr->u.data.length > (descr->set_args & ++ IW_PRIV_SIZE_MASK)) ++ return -E2BIG; ++ } else { ++ /* Check NULL pointer */ ++ if(iwr->u.data.pointer == NULL) ++ return -EFAULT; ++ } ++ ++#ifdef WE_IOCTL_DEBUG ++ printk(KERN_DEBUG "Malloc %d bytes\n", extra_size); ++#endif /* WE_IOCTL_DEBUG */ ++ ++ /* Always allocate for max space. Easier, and won't last ++ * long... */ ++ extra = kmalloc(extra_size, GFP_KERNEL); ++ if (extra == NULL) { ++ return -ENOMEM; ++ } ++ ++ /* If it is a SET, get all the extra data in here */ ++ if(IW_IS_SET(cmd) && (iwr->u.data.length != 0)) { ++ err = copy_from_user(extra, iwr->u.data.pointer, ++ extra_size); ++ if (err) { ++ kfree(extra); ++ return -EFAULT; ++ } ++#ifdef WE_IOCTL_DEBUG ++ printk(KERN_DEBUG "Got %d elem\n", iwr->u.data.length); ++#endif /* WE_IOCTL_DEBUG */ ++ } ++ ++ /* Call the handler */ ++ ret = handler(dev, &info, &(iwr->u), extra); ++ ++ /* If we have something to return to the user */ ++ if (!ret && IW_IS_GET(cmd)) { ++ err = copy_to_user(iwr->u.data.pointer, extra, ++ extra_size); ++ if (err) ++ ret = -EFAULT; ++#ifdef WE_IOCTL_DEBUG ++ printk(KERN_DEBUG "Wrote %d elem\n", ++ iwr->u.data.length); ++#endif /* WE_IOCTL_DEBUG */ ++ } ++ ++ /* Cleanup - I told you it wasn't that long ;-) */ ++ kfree(extra); ++ } ++ ++ ++ /* Call commit handler if needed and defined */ ++ if(ret == -EIWCOMMIT) ++ ret = call_commit_handler(dev); ++ ++ return ret; ++} ++ ++/* ---------------------------------------------------------------- */ ++/* ++ * Main IOCTl dispatcher. Called from the main networking code ++ * (dev_ioctl() in net/core/dev.c). ++ * Check the type of IOCTL and call the appropriate wrapper... ++ */ ++int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd) ++{ ++ struct net_device *dev; ++ iw_handler handler; ++ ++ /* Permissions are already checked in dev_ioctl() before calling us. ++ * The copy_to/from_user() of ifr is also dealt with in there */ ++ ++ /* Make sure the device exist */ ++ if ((dev = __dev_get_by_name(ifr->ifr_name)) == NULL) ++ return -ENODEV; ++ ++ /* A bunch of special cases, then the generic case... ++ * Note that 'cmd' is already filtered in dev_ioctl() with ++ * (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) */ ++ switch(cmd) ++ { ++ case SIOCGIWSTATS: ++ /* Get Wireless Stats */ ++ return dev_iwstats(dev, ifr); ++ ++ case SIOCGIWPRIV: ++ /* Check if we have some wireless handlers defined */ ++ if(dev->wireless_handlers != NULL) { ++ /* We export to user space the definition of ++ * the private handler ourselves */ ++ return ioctl_export_private(dev, ifr); ++ } ++ // ## Fall-through for old API ## ++ default: ++ /* Generic IOCTL */ ++ /* Basic check */ ++ if (!netif_device_present(dev)) ++ return -ENODEV; ++ /* New driver API : try to find the handler */ ++ handler = get_handler(dev, cmd); ++ if(handler != NULL) { ++ /* Standard and private are not the same */ ++ if(cmd < SIOCIWFIRSTPRIV) ++ return ioctl_standard_call(dev, ++ ifr, ++ cmd, ++ handler); ++ else ++ return ioctl_private_call(dev, ++ ifr, ++ cmd, ++ handler); ++ } ++ /* Old driver API : call driver ioctl handler */ ++ if (dev->do_ioctl) { ++ return dev->do_ioctl(dev, ifr, cmd); ++ } ++ return -EOPNOTSUPP; ++ } ++ /* Not reached */ ++ return -EINVAL; ++} diff --git a/linux/montavista-sa-2.4.17-mvl21/iw_handlers.w14-5.diff b/linux/montavista-sa-2.4.17-mvl21/iw_handlers.w14-5.diff index e69de29bb2..539b160068 100644 --- a/linux/montavista-sa-2.4.17-mvl21/iw_handlers.w14-5.diff +++ b/linux/montavista-sa-2.4.17-mvl21/iw_handlers.w14-5.diff @@ -0,0 +1,838 @@ +diff -u -p -r --new-file linux/include/linux-w13/rtnetlink.h linux/include/linux/rtnetlink.h +--- linux/include/linux-w13/rtnetlink.h Thu Jun 6 14:44:08 2002 ++++ linux/include/linux/rtnetlink.h Thu Jun 6 15:47:44 2002 +@@ -440,12 +440,14 @@ enum + #define IFLA_COST IFLA_COST + IFLA_PRIORITY, + #define IFLA_PRIORITY IFLA_PRIORITY +- IFLA_MASTER ++ IFLA_MASTER, + #define IFLA_MASTER IFLA_MASTER ++ IFLA_WIRELESS, /* Wireless Extension event - see wireless.h */ ++#define IFLA_WIRELESS IFLA_WIRELESS + }; + + +-#define IFLA_MAX IFLA_MASTER ++#define IFLA_MAX IFLA_WIRELESS + + #define IFLA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifinfomsg)))) + #define IFLA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifinfomsg)) +diff -u -p -r --new-file linux/include/linux-w13/wireless.h linux/include/linux/wireless.h +--- linux/include/linux-w13/wireless.h Thu Jun 6 15:00:28 2002 ++++ linux/include/linux/wireless.h Thu Jun 6 15:47:44 2002 +@@ -1,10 +1,10 @@ + /* + * This file define a set of standard wireless extensions + * +- * Version : 13 6.12.01 ++ * Version : 14 25.1.02 + * + * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> +- * Copyright (c) 1997-2001 Jean Tourrilhes, All Rights Reserved. ++ * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved. + */ + + #ifndef _LINUX_WIRELESS_H +@@ -40,7 +40,7 @@ + * # include/linux/netdevice.h (one place) + * # include/linux/proc_fs.h (one place) + * +- * New driver API (2001 -> onward) : ++ * New driver API (2002 -> onward) : + * ------------------------------- + * This file is only concerned with the user space API and common definitions. + * The new driver API is defined and documented in : +@@ -49,6 +49,11 @@ + * Note as well that /proc/net/wireless implementation has now moved in : + * # include/linux/wireless.c + * ++ * Wireless Events (2002 -> onward) : ++ * -------------------------------- ++ * Events are defined at the end of this file, and implemented in : ++ * # include/linux/wireless.c ++ * + * Other comments : + * -------------- + * Do not add here things that are redundant with other mechanisms +@@ -75,7 +80,7 @@ + * (there is some stuff that will be added in the future...) + * I just plan to increment with each new version. + */ +-#define WIRELESS_EXT 13 ++#define WIRELESS_EXT 14 + + /* + * Changes : +@@ -141,6 +146,13 @@ + * - Document creation of new driver API. + * - Extract union iwreq_data from struct iwreq (for new driver API). + * - Rename SIOCSIWNAME as SIOCSIWCOMMIT ++ * ++ * V13 to V14 ++ * ---------- ++ * - Wireless Events support : define struct iw_event ++ * - Define additional specific event numbers ++ * - Add "addr" and "param" fields in union iwreq_data ++ * - AP scanning stuff (SIOCSIWSCAN and friends) + */ + + /**************************** CONSTANTS ****************************/ +@@ -175,6 +187,8 @@ + #define SIOCSIWAP 0x8B14 /* set access point MAC addresses */ + #define SIOCGIWAP 0x8B15 /* get access point MAC addresses */ + #define SIOCGIWAPLIST 0x8B17 /* get list of access point in range */ ++#define SIOCSIWSCAN 0x8B18 /* trigger scanning */ ++#define SIOCGIWSCAN 0x8B19 /* get scanning results */ + + /* 802.11 specific support */ + #define SIOCSIWESSID 0x8B1A /* set ESSID (network name) */ +@@ -238,6 +252,15 @@ + #define IW_IS_SET(cmd) (!((cmd) & 0x1)) + #define IW_IS_GET(cmd) ((cmd) & 0x1) + ++/* ----------------------- WIRELESS EVENTS ----------------------- */ ++/* Those are *NOT* ioctls, do not issue request on them !!! */ ++/* Most events use the same identifier as ioctl requests */ ++ ++#define IWEVTXDROP 0x8C00 /* Packet dropped to excessive retry */ ++#define IWEVQUAL 0x8C01 /* Quality part of statistics */ ++ ++#define IWEVFIRST 0x8C00 ++ + /* ------------------------- PRIVATE INFO ------------------------- */ + /* + * The following is used with SIOCGIWPRIV. It allow a driver to define +@@ -340,6 +363,19 @@ + #define IW_RETRY_MAX 0x0002 /* Value is a maximum */ + #define IW_RETRY_RELATIVE 0x0004 /* Value is not in seconds/ms/us */ + ++/* Scanning request flags */ ++#define IW_SCAN_DEFAULT 0x0000 /* Default scan of the driver */ ++#define IW_SCAN_ALL_ESSID 0x0001 /* Scan all ESSIDs */ ++#define IW_SCAN_THIS_ESSID 0x0002 /* Scan only this ESSID */ ++#define IW_SCAN_ALL_FREQ 0x0004 /* Scan all Frequencies */ ++#define IW_SCAN_THIS_FREQ 0x0008 /* Scan only this Frequency */ ++#define IW_SCAN_ALL_MODE 0x0010 /* Scan all Modes */ ++#define IW_SCAN_THIS_MODE 0x0020 /* Scan only this Mode */ ++#define IW_SCAN_ALL_RATE 0x0040 /* Scan all Bit-Rates */ ++#define IW_SCAN_THIS_RATE 0x0080 /* Scan only this Bit-Rate */ ++/* Maximum size of returned data */ ++#define IW_SCAN_MAX_DATA 4096 /* In bytes */ ++ + /****************************** TYPES ******************************/ + + /* --------------------------- SUBTYPES --------------------------- */ +@@ -466,9 +502,12 @@ union iwreq_data + + struct iw_point encoding; /* Encoding stuff : tokens */ + struct iw_param power; /* PM duration/timeout */ ++ struct iw_quality qual; /* Quality part of statistics */ + + struct sockaddr ap_addr; /* Access point address */ ++ struct sockaddr addr; /* Destination address (hw) */ + ++ struct iw_param param; /* Other small parameters */ + struct iw_point data; /* Other large parameters */ + }; + +@@ -595,5 +634,36 @@ struct iw_priv_args + __u16 get_args; /* Type and number of args */ + char name[IFNAMSIZ]; /* Name of the extension */ + }; ++ ++/* ----------------------- WIRELESS EVENTS ----------------------- */ ++/* ++ * Wireless events are carried through the rtnetlink socket to user ++ * space. They are encapsulated in the IFLA_WIRELESS field of ++ * a RTM_NEWLINK message. ++ */ ++ ++/* ++ * A Wireless Event. Contains basically the same data as the ioctl... ++ */ ++struct iw_event ++{ ++ __u16 len; /* Real lenght of this stuff */ ++ __u16 cmd; /* Wireless IOCTL */ ++ union iwreq_data u; /* IOCTL fixed payload */ ++}; ++ ++/* Size of the Event prefix (including padding and alignement junk) */ ++#define IW_EV_LCP_LEN (sizeof(struct iw_event) - sizeof(union iwreq_data)) ++/* Size of the various events */ ++#define IW_EV_CHAR_LEN (IW_EV_LCP_LEN + IFNAMSIZ) ++#define IW_EV_UINT_LEN (IW_EV_LCP_LEN + sizeof(__u32)) ++#define IW_EV_FREQ_LEN (IW_EV_LCP_LEN + sizeof(struct iw_freq)) ++#define IW_EV_POINT_LEN (IW_EV_LCP_LEN + sizeof(struct iw_point)) ++#define IW_EV_PARAM_LEN (IW_EV_LCP_LEN + sizeof(struct iw_param)) ++#define IW_EV_ADDR_LEN (IW_EV_LCP_LEN + sizeof(struct sockaddr)) ++#define IW_EV_QUAL_LEN (IW_EV_LCP_LEN + sizeof(struct iw_quality)) ++ ++/* Note : in the case of iw_point, the extra data will come at the ++ * end of the event */ + + #endif /* _LINUX_WIRELESS_H */ +diff -u -p -r --new-file linux/include/net-w13/iw_handler.h linux/include/net/iw_handler.h +--- linux/include/net-w13/iw_handler.h Thu Jun 6 15:06:16 2002 ++++ linux/include/net/iw_handler.h Thu Jun 6 15:48:06 2002 +@@ -1,10 +1,10 @@ + /* + * This file define the new driver API for Wireless Extensions + * +- * Version : 2 6.12.01 ++ * Version : 3 17.1.02 + * + * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> +- * Copyright (c) 2001 Jean Tourrilhes, All Rights Reserved. ++ * Copyright (c) 2001-2002 Jean Tourrilhes, All Rights Reserved. + */ + + #ifndef _IW_HANDLER_H +@@ -33,7 +33,7 @@ + * o The user space interface is tied to ioctl because of the use + * copy_to/from_user. + * +- * New driver API (2001 -> onward) : ++ * New driver API (2002 -> onward) : + * ------------------------------- + * The new driver API is just a bunch of standard functions (handlers), + * each handling a specific Wireless Extension. The driver just export +@@ -206,7 +206,18 @@ + * will be needed... + * I just plan to increment with each new version. + */ +-#define IW_HANDLER_VERSION 2 ++#define IW_HANDLER_VERSION 3 ++ ++/* ++ * Changes : ++ * ++ * V2 to V3 ++ * -------- ++ * - Move event definition in <linux/wireless.h> ++ * - Add Wireless Event support : ++ * o wireless_send_event() prototype ++ * o iwe_stream_add_event/point() inline functions ++ */ + + /**************************** CONSTANTS ****************************/ + +@@ -225,6 +236,7 @@ + #define IW_HEADER_TYPE_POINT 6 /* struct iw_point */ + #define IW_HEADER_TYPE_PARAM 7 /* struct iw_param */ + #define IW_HEADER_TYPE_ADDR 8 /* struct sockaddr */ ++#define IW_HEADER_TYPE_QUAL 9 /* struct iw_quality */ + + /* Handling flags */ + /* Most are not implemented. I just use them as a reminder of some +@@ -233,7 +245,8 @@ + /* Wrapper level flags */ + #define IW_DESCR_FLAG_DUMP 0x0001 /* Not part of the dump command */ + #define IW_DESCR_FLAG_EVENT 0x0002 /* Generate an event on SET */ +-#define IW_DESCR_FLAG_RESTRICT 0x0004 /* GET request is ROOT only */ ++#define IW_DESCR_FLAG_RESTRICT 0x0004 /* GET : request is ROOT only */ ++ /* SET : Omit payload from generated iwevent */ + /* Driver level flags */ + #define IW_DESCR_FLAG_WAIT 0x0100 /* Wait for driver event */ + +@@ -303,25 +316,6 @@ struct iw_handler_def + * 'struct net_device' to here, to minimise bloat. */ + }; + +-/* ----------------------- WIRELESS EVENTS ----------------------- */ +-/* +- * Currently we don't support events, so let's just plan for the +- * future... +- */ +- +-/* +- * A Wireless Event. +- */ +-// How do we define short header ? We don't want a flag on length. +-// Probably a flag on event ? Highest bit to zero... +-struct iw_event +-{ +- __u16 length; /* Lenght of this stuff */ +- __u16 event; /* Wireless IOCTL */ +- union iwreq_data header; /* IOCTL fixed payload */ +- char extra[0]; /* Optional IOCTL data */ +-}; +- + /* ---------------------- IOCTL DESCRIPTION ---------------------- */ + /* + * One of the main goal of the new interface is to deal entirely with +@@ -369,6 +363,88 @@ extern int dev_get_wireless_info(char * + extern int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd); + + /* Second : functions that may be called by driver modules */ +-/* None yet */ + +-#endif /* _LINUX_WIRELESS_H */ ++/* Send a single event to user space */ ++extern void wireless_send_event(struct net_device * dev, ++ unsigned int cmd, ++ union iwreq_data * wrqu, ++ char * extra); ++ ++/* We may need a function to send a stream of events to user space. ++ * More on that later... */ ++ ++/************************* INLINE FUNTIONS *************************/ ++/* ++ * Function that are so simple that it's more efficient inlining them ++ */ ++ ++/*------------------------------------------------------------------*/ ++/* ++ * Wrapper to add an Wireless Event to a stream of events. ++ */ ++static inline char * ++iwe_stream_add_event(char * stream, /* Stream of events */ ++ char * ends, /* End of stream */ ++ struct iw_event *iwe, /* Payload */ ++ int event_len) /* Real size of payload */ ++{ ++ /* Check if it's possible */ ++ if((stream + event_len) < ends) { ++ iwe->len = event_len; ++ memcpy(stream, (char *) iwe, event_len); ++ stream += event_len; ++ } ++ return stream; ++} ++ ++/*------------------------------------------------------------------*/ ++/* ++ * Wrapper to add an short Wireless Event containing a pointer to a ++ * stream of events. ++ */ ++static inline char * ++iwe_stream_add_point(char * stream, /* Stream of events */ ++ char * ends, /* End of stream */ ++ struct iw_event *iwe, /* Payload */ ++ char * extra) ++{ ++ int event_len = IW_EV_POINT_LEN + iwe->u.data.length; ++ /* Check if it's possible */ ++ if((stream + event_len) < ends) { ++ iwe->len = event_len; ++ memcpy(stream, (char *) iwe, IW_EV_POINT_LEN); ++ memcpy(stream + IW_EV_POINT_LEN, extra, iwe->u.data.length); ++ stream += event_len; ++ } ++ return stream; ++} ++ ++/*------------------------------------------------------------------*/ ++/* ++ * Wrapper to add a value to a Wireless Event in a stream of events. ++ * Be careful, this one is tricky to use properly : ++ * At the first run, you need to have (value = event + IW_EV_LCP_LEN). ++ */ ++static inline char * ++iwe_stream_add_value(char * event, /* Event in the stream */ ++ char * value, /* Value in event */ ++ char * ends, /* End of stream */ ++ struct iw_event *iwe, /* Payload */ ++ int event_len) /* Real size of payload */ ++{ ++ /* Don't duplicate LCP */ ++ event_len -= IW_EV_LCP_LEN; ++ ++ /* Check if it's possible */ ++ if((value + event_len) < ends) { ++ /* Add new value */ ++ memcpy(value, (char *) iwe + IW_EV_LCP_LEN, event_len); ++ value += event_len; ++ /* Patch LCP */ ++ iwe->len = value - event; ++ memcpy(event, (char *) iwe, IW_EV_LCP_LEN); ++ } ++ return value; ++} ++ ++#endif /* _IW_HANDLER_H */ +diff -u -p -r --new-file linux/net/netsyms-w13.c linux/net/netsyms.c +--- linux/net/netsyms-w13.c Thu Jun 6 15:46:34 2002 ++++ linux/net/netsyms.c Thu Jun 6 15:47:44 2002 +@@ -588,4 +588,10 @@ EXPORT_SYMBOL(register_gifconf); + EXPORT_SYMBOL(net_call_rx_atomic); + EXPORT_SYMBOL(softnet_data); + ++#if defined(CONFIG_NET_RADIO) || defined(CONFIG_NET_PCMCIA_RADIO) ++/* Don't include the whole header mess for a single function */ ++extern void wireless_send_event(struct net_device *dev, unsigned int cmd, union iwreq_data *wrqu, char *extra); ++EXPORT_SYMBOL(wireless_send_event); ++#endif /* CONFIG_NET_RADIO || CONFIG_NET_PCMCIA_RADIO */ ++ + #endif /* CONFIG_NET */ +diff -u -p -r --new-file linux/net/core/wireless-w13.c linux/net/core/wireless.c +--- linux/net/core/wireless-w13.c Thu Jun 6 15:46:45 2002 ++++ linux/net/core/wireless.c Thu Jun 6 15:48:06 2002 +@@ -2,7 +2,7 @@ + * This file implement the Wireless Extensions APIs. + * + * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> +- * Copyright (c) 1997-2001 Jean Tourrilhes, All Rights Reserved. ++ * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved. + * + * (As all part of the Linux kernel, this file is GPL) + */ +@@ -25,6 +25,16 @@ + * o Added iw_handler handling ;-) + * o Added standard ioctl description + * o Initial dumb commit strategy based on orinoco.c ++ * ++ * v3 - 19.12.01 - Jean II ++ * o Make sure we don't go out of standard_ioctl[] in ioctl_standard_call ++ * o Add event dispatcher function ++ * o Add event description ++ * o Propagate events as rtnetlink IFLA_WIRELESS option ++ * o Generate event on selected SET requests ++ * ++ * v4 - 18.04.01 - Jean II ++ * o Fix stupid off by one in iw_ioctl_description : IW_ESSID_MAX_SIZE + 1 + */ + + /***************************** INCLUDES *****************************/ +@@ -33,6 +43,7 @@ + #include <linux/config.h> /* Not needed ??? */ + #include <linux/types.h> /* off_t */ + #include <linux/netdevice.h> /* struct ifreq, dev_get_by_name() */ ++#include <linux/rtnetlink.h> /* rtnetlink stuff */ + + #include <linux/wireless.h> /* Pretty obvious */ + #include <net/iw_handler.h> /* New driver API */ +@@ -44,14 +55,23 @@ + + /* Debuging stuff */ + #undef WE_IOCTL_DEBUG /* Debug IOCTL API */ ++#undef WE_EVENT_DEBUG /* Debug Event dispatcher */ ++ ++/* Options */ ++#define WE_EVENT_NETLINK /* Propagate events using rtnetlink */ ++#define WE_SET_EVENT /* Generate an event on some set commands */ + + /************************* GLOBAL VARIABLES *************************/ + /* + * You should not use global variables, because or re-entrancy. + * On our case, it's only const, so it's OK... + */ ++/* ++ * Meta-data about all the standard Wireless Extension request we ++ * know about. ++ */ + static const struct iw_ioctl_description standard_ioctl[] = { +- /* SIOCSIWCOMMIT (internal) */ ++ /* SIOCSIWCOMMIT */ + { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, + /* SIOCGIWNAME */ + { IW_HEADER_TYPE_CHAR, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP}, +@@ -99,18 +119,18 @@ static const struct iw_ioctl_description + { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, + /* SIOCGIWAPLIST */ + { IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_AP, 0}, +- /* -- hole -- */ +- { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, +- /* -- hole -- */ +- { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, ++ /* SIOCSIWSCAN */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++ /* SIOCGIWSCAN */ ++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_SCAN_MAX_DATA, 0}, + /* SIOCSIWESSID */ +- { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, IW_DESCR_FLAG_EVENT}, ++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, IW_DESCR_FLAG_EVENT}, + /* SIOCGIWESSID */ +- { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, IW_DESCR_FLAG_DUMP}, ++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, IW_DESCR_FLAG_DUMP}, + /* SIOCSIWNICKN */ +- { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, 0}, ++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, 0}, + /* SIOCGIWNICKN */ +- { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, 0}, ++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, 0}, + /* -- hole -- */ + { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, + /* -- hole -- */ +@@ -136,7 +156,7 @@ static const struct iw_ioctl_description + /* SIOCGIWRETRY */ + { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, + /* SIOCSIWENCODE */ +- { IW_HEADER_TYPE_POINT, 4, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT}, ++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT}, + /* SIOCGIWENCODE */ + { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_DUMP | IW_DESCR_FLAG_RESTRICT}, + /* SIOCSIWPOWER */ +@@ -144,9 +164,38 @@ static const struct iw_ioctl_description + /* SIOCGIWPOWER */ + { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, + }; ++static const int standard_ioctl_num = (sizeof(standard_ioctl) / ++ sizeof(struct iw_ioctl_description)); ++ ++/* ++ * Meta-data about all the additional standard Wireless Extension events ++ * we know about. ++ */ ++static const struct iw_ioctl_description standard_event[] = { ++ /* IWEVTXDROP */ ++ { IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0}, ++ /* IWEVQUAL */ ++ { IW_HEADER_TYPE_QUAL, 0, 0, 0, 0, 0}, ++}; ++static const int standard_event_num = (sizeof(standard_event) / ++ sizeof(struct iw_ioctl_description)); + + /* Size (in bytes) of the various private data types */ +-char priv_type_size[] = { 0, 1, 1, 0, 4, 4, 0, 0 }; ++static const char priv_type_size[] = { 0, 1, 1, 0, 4, 4, 0, 0 }; ++ ++/* Size (in bytes) of various events */ ++static const int event_type_size[] = { ++ IW_EV_LCP_LEN, ++ 0, ++ IW_EV_CHAR_LEN, ++ 0, ++ IW_EV_UINT_LEN, ++ IW_EV_FREQ_LEN, ++ IW_EV_POINT_LEN, /* Without variable payload */ ++ IW_EV_PARAM_LEN, ++ IW_EV_ADDR_LEN, ++ IW_EV_QUAL_LEN, ++}; + + /************************ COMMON SUBROUTINES ************************/ + /* +@@ -162,7 +211,8 @@ char priv_type_size[] = { 0, 1, 1, 0, 4, + static inline iw_handler get_handler(struct net_device *dev, + unsigned int cmd) + { +- unsigned int index; /* MUST be unsigned */ ++ /* Don't "optimise" the following variable, it will crash */ ++ unsigned int index; /* *MUST* be unsigned */ + + /* Check if we have some wireless handlers defined */ + if(dev->wireless_handlers == NULL) +@@ -269,9 +319,9 @@ static inline int sprintf_wireless_stats + stats->status, + stats->qual.qual, + stats->qual.updated & 1 ? '.' : ' ', +- stats->qual.level, ++ ((__u8) stats->qual.level), + stats->qual.updated & 2 ? '.' : ' ', +- stats->qual.noise, ++ ((__u8) stats->qual.noise), + stats->qual.updated & 4 ? '.' : ' ', + stats->discard.nwid, + stats->discard.code, +@@ -423,12 +473,14 @@ static inline int ioctl_standard_call(st + int ret = -EINVAL; + + /* Get the description of the IOCTL */ ++ if((cmd - SIOCIWFIRST) >= standard_ioctl_num) ++ return -EOPNOTSUPP; + descr = &(standard_ioctl[cmd - SIOCIWFIRST]); + + #ifdef WE_IOCTL_DEBUG +- printk(KERN_DEBUG "%s : Found standard handler for 0x%04X\n", ++ printk(KERN_DEBUG "%s (WE) : Found standard handler for 0x%04X\n", + ifr->ifr_name, cmd); +- printk(KERN_DEBUG "Header type : %d, token type : %d, token_size : %d, max_token : %d\n", descr->header_type, descr->token_type, descr->token_size, descr->max_tokens); ++ printk(KERN_DEBUG "%s (WE) : Header type : %d, Token type : %d, size : %d, token : %d\n", dev->name, descr->header_type, descr->token_type, descr->token_size, descr->max_tokens); + #endif /* WE_IOCTL_DEBUG */ + + /* Prepare the call */ +@@ -437,8 +489,16 @@ static inline int ioctl_standard_call(st + + /* Check if we have a pointer to user space data or not */ + if(descr->header_type != IW_HEADER_TYPE_POINT) { ++ + /* No extra arguments. Trivial to handle */ + ret = handler(dev, &info, &(iwr->u), NULL); ++ ++#ifdef WE_SET_EVENT ++ /* Generate an event to notify listeners of the change */ ++ if((descr->flags & IW_DESCR_FLAG_EVENT) && ++ ((ret == 0) || (ret == -EIWCOMMIT))) ++ wireless_send_event(dev, cmd, &(iwr->u), NULL); ++#endif /* WE_SET_EVENT */ + } else { + char * extra; + int err; +@@ -466,8 +526,8 @@ static inline int ioctl_standard_call(st + } + + #ifdef WE_IOCTL_DEBUG +- printk(KERN_DEBUG "Malloc %d bytes\n", +- descr->max_tokens * descr->token_size); ++ printk(KERN_DEBUG "%s (WE) : Malloc %d bytes\n", ++ dev->name, descr->max_tokens * descr->token_size); + #endif /* WE_IOCTL_DEBUG */ + + /* Always allocate for max space. Easier, and won't last +@@ -488,7 +548,8 @@ static inline int ioctl_standard_call(st + return -EFAULT; + } + #ifdef WE_IOCTL_DEBUG +- printk(KERN_DEBUG "Got %d bytes\n", ++ printk(KERN_DEBUG "%s (WE) : Got %d bytes\n", ++ dev->name, + iwr->u.data.length * descr->token_size); + #endif /* WE_IOCTL_DEBUG */ + } +@@ -504,11 +565,26 @@ static inline int ioctl_standard_call(st + if (err) + ret = -EFAULT; + #ifdef WE_IOCTL_DEBUG +- printk(KERN_DEBUG "Wrote %d bytes\n", ++ printk(KERN_DEBUG "%s (WE) : Wrote %d bytes\n", ++ dev->name, + iwr->u.data.length * descr->token_size); + #endif /* WE_IOCTL_DEBUG */ + } + ++#ifdef WE_SET_EVENT ++ /* Generate an event to notify listeners of the change */ ++ if((descr->flags & IW_DESCR_FLAG_EVENT) && ++ ((ret == 0) || (ret == -EIWCOMMIT))) { ++ if(descr->flags & IW_DESCR_FLAG_RESTRICT) ++ /* If the event is restricted, don't ++ * export the payload */ ++ wireless_send_event(dev, cmd, &(iwr->u), NULL); ++ else ++ wireless_send_event(dev, cmd, &(iwr->u), ++ extra); ++ } ++#endif /* WE_SET_EVENT */ ++ + /* Cleanup - I told you it wasn't that long ;-) */ + kfree(extra); + } +@@ -558,11 +634,12 @@ static inline int ioctl_private_call(str + } + + #ifdef WE_IOCTL_DEBUG +- printk(KERN_DEBUG "%s : Found private handler for 0x%04X\n", ++ printk(KERN_DEBUG "%s (WE) : Found private handler for 0x%04X\n", + ifr->ifr_name, cmd); + if(descr) { +- printk(KERN_DEBUG "Name %s, set %X, get %X\n", +- descr->name, descr->set_args, descr->get_args); ++ printk(KERN_DEBUG "%s (WE) : Name %s, set %X, get %X\n", ++ dev->name, descr->name, ++ descr->set_args, descr->get_args); + } + #endif /* WE_IOCTL_DEBUG */ + +@@ -617,7 +694,8 @@ static inline int ioctl_private_call(str + } + + #ifdef WE_IOCTL_DEBUG +- printk(KERN_DEBUG "Malloc %d bytes\n", extra_size); ++ printk(KERN_DEBUG "%s (WE) : Malloc %d bytes\n", ++ dev->name, extra_size); + #endif /* WE_IOCTL_DEBUG */ + + /* Always allocate for max space. Easier, and won't last +@@ -636,7 +714,8 @@ static inline int ioctl_private_call(str + return -EFAULT; + } + #ifdef WE_IOCTL_DEBUG +- printk(KERN_DEBUG "Got %d elem\n", iwr->u.data.length); ++ printk(KERN_DEBUG "%s (WE) : Got %d elem\n", ++ dev->name, iwr->u.data.length); + #endif /* WE_IOCTL_DEBUG */ + } + +@@ -650,8 +729,8 @@ static inline int ioctl_private_call(str + if (err) + ret = -EFAULT; + #ifdef WE_IOCTL_DEBUG +- printk(KERN_DEBUG "Wrote %d elem\n", +- iwr->u.data.length); ++ printk(KERN_DEBUG "%s (WE) : Wrote %d elem\n", ++ dev->name, iwr->u.data.length); + #endif /* WE_IOCTL_DEBUG */ + } + +@@ -730,4 +809,178 @@ int wireless_process_ioctl(struct ifreq + } + /* Not reached */ + return -EINVAL; ++} ++ ++/************************* EVENT PROCESSING *************************/ ++/* ++ * Process events generated by the wireless layer or the driver. ++ * Most often, the event will be propagated through rtnetlink ++ */ ++ ++#ifdef WE_EVENT_NETLINK ++/* "rtnl" is defined in net/core/rtnetlink.c, but we need it here. ++ * It is declared in <linux/rtnetlink.h> */ ++ ++/* ---------------------------------------------------------------- */ ++/* ++ * Fill a rtnetlink message with our event data. ++ * Note that we propage only the specified event and don't dump the ++ * current wireless config. Dumping the wireless config is far too ++ * expensive (for each parameter, the driver need to query the hardware). ++ */ ++static inline int rtnetlink_fill_iwinfo(struct sk_buff * skb, ++ struct net_device * dev, ++ int type, ++ char * event, ++ int event_len) ++{ ++ struct ifinfomsg *r; ++ struct nlmsghdr *nlh; ++ unsigned char *b = skb->tail; ++ ++ nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(*r)); ++ r = NLMSG_DATA(nlh); ++ r->ifi_family = AF_UNSPEC; ++ r->ifi_type = dev->type; ++ r->ifi_index = dev->ifindex; ++ r->ifi_flags = dev->flags; ++ r->ifi_change = 0; /* Wireless changes don't affect those flags */ ++ ++ /* Add the wireless events in the netlink packet */ ++ RTA_PUT(skb, IFLA_WIRELESS, ++ event_len, event); ++ ++ nlh->nlmsg_len = skb->tail - b; ++ return skb->len; ++ ++nlmsg_failure: ++rtattr_failure: ++ skb_trim(skb, b - skb->data); ++ return -1; ++} ++ ++/* ---------------------------------------------------------------- */ ++/* ++ * Create and broadcast and send it on the standard rtnetlink socket ++ * This is a pure clone rtmsg_ifinfo() in net/core/rtnetlink.c ++ * Andrzej Krzysztofowicz mandated that I used a IFLA_XXX field ++ * within a RTM_NEWLINK event. ++ */ ++static inline void rtmsg_iwinfo(struct net_device * dev, ++ char * event, ++ int event_len) ++{ ++ struct sk_buff *skb; ++ int size = NLMSG_GOODSIZE; ++ ++ skb = alloc_skb(size, GFP_ATOMIC); ++ if (!skb) ++ return; ++ ++ if (rtnetlink_fill_iwinfo(skb, dev, RTM_NEWLINK, ++ event, event_len) < 0) { ++ kfree_skb(skb); ++ return; ++ } ++ NETLINK_CB(skb).dst_groups = RTMGRP_LINK; ++ netlink_broadcast(rtnl, skb, 0, RTMGRP_LINK, GFP_ATOMIC); ++} ++#endif /* WE_EVENT_NETLINK */ ++ ++/* ---------------------------------------------------------------- */ ++/* ++ * Main event dispatcher. Called from other parts and drivers. ++ * Send the event on the apropriate channels. ++ * May be called from interrupt context. ++ */ ++void wireless_send_event(struct net_device * dev, ++ unsigned int cmd, ++ union iwreq_data * wrqu, ++ char * extra) ++{ ++ const struct iw_ioctl_description * descr = NULL; ++ int extra_len = 0; ++ struct iw_event *event; /* Mallocated whole event */ ++ int event_len; /* Its size */ ++ int hdr_len; /* Size of the event header */ ++ /* Don't "optimise" the following variable, it will crash */ ++ unsigned cmd_index; /* *MUST* be unsigned */ ++ ++ /* Get the description of the IOCTL */ ++ if(cmd <= SIOCIWLAST) { ++ cmd_index = cmd - SIOCIWFIRST; ++ if(cmd_index < standard_ioctl_num) ++ descr = &(standard_ioctl[cmd_index]); ++ } else { ++ cmd_index = cmd - IWEVFIRST; ++ if(cmd_index < standard_event_num) ++ descr = &(standard_event[cmd_index]); ++ } ++ /* Don't accept unknown events */ ++ if(descr == NULL) { ++ /* Note : we don't return an error to the driver, because ++ * the driver would not know what to do about it. It can't ++ * return an error to the user, because the event is not ++ * initiated by a user request. ++ * The best the driver could do is to log an error message. ++ * We will do it ourselves instead... ++ */ ++ printk(KERN_ERR "%s (WE) : Invalid Wireless Event (0x%04X)\n", ++ dev->name, cmd); ++ return; ++ } ++#ifdef WE_EVENT_DEBUG ++ printk(KERN_DEBUG "%s (WE) : Got event 0x%04X\n", ++ dev->name, cmd); ++ printk(KERN_DEBUG "%s (WE) : Header type : %d, Token type : %d, size : %d, token : %d\n", dev->name, descr->header_type, descr->token_type, descr->token_size, descr->max_tokens); ++#endif /* WE_EVENT_DEBUG */ ++ ++ /* Check extra parameters and set extra_len */ ++ if(descr->header_type == IW_HEADER_TYPE_POINT) { ++ /* Check if number of token fits within bounds */ ++ if(wrqu->data.length > descr->max_tokens) { ++ printk(KERN_ERR "%s (WE) : Wireless Event too big (%d)\n", dev->name, wrqu->data.length); ++ return; ++ } ++ if(wrqu->data.length < descr->min_tokens) { ++ printk(KERN_ERR "%s (WE) : Wireless Event too small (%d)\n", dev->name, wrqu->data.length); ++ return; ++ } ++ /* Calculate extra_len - extra is NULL for restricted events */ ++ if(extra != NULL) ++ extra_len = wrqu->data.length * descr->token_size; ++#ifdef WE_EVENT_DEBUG ++ printk(KERN_DEBUG "%s (WE) : Event 0x%04X, tokens %d, extra_len %d\n", dev->name, cmd, wrqu->data.length, extra_len); ++#endif /* WE_EVENT_DEBUG */ ++ } ++ ++ /* Total length of the event */ ++ hdr_len = event_type_size[descr->header_type]; ++ event_len = hdr_len + extra_len; ++ ++#ifdef WE_EVENT_DEBUG ++ printk(KERN_DEBUG "%s (WE) : Event 0x%04X, hdr_len %d, event_len %d\n", dev->name, cmd, hdr_len, event_len); ++#endif /* WE_EVENT_DEBUG */ ++ ++ /* Create temporary buffer to hold the event */ ++ event = kmalloc(event_len, GFP_ATOMIC); ++ if(event == NULL) ++ return; ++ ++ /* Fill event */ ++ event->len = event_len; ++ event->cmd = cmd; ++ memcpy(&event->u, wrqu, hdr_len - IW_EV_LCP_LEN); ++ if(extra != NULL) ++ memcpy(((char *) event) + hdr_len, extra, extra_len); ++ ++#ifdef WE_EVENT_NETLINK ++ /* rtnetlink event channel */ ++ rtmsg_iwinfo(dev, (char *) event, event_len); ++#endif /* WE_EVENT_NETLINK */ ++ ++ /* Cleanup */ ++ kfree(event); ++ ++ return; /* Always success, I guess ;-) */ + } diff --git a/linux/montavista-sa-2.4.17-mvl21/machine_name.patch b/linux/montavista-sa-2.4.17-mvl21/machine_name.patch index e69de29bb2..8b7ad2b143 100644 --- a/linux/montavista-sa-2.4.17-mvl21/machine_name.patch +++ b/linux/montavista-sa-2.4.17-mvl21/machine_name.patch @@ -0,0 +1,19 @@ +Change the Name showed by /proc/cpuinfo + + + +# +# Patch managed by http://www.holgerschurig.de/patcher.html +# + +--- linux-2.4.17_mvl21/arch/arm/mach-sa1100/assabet.c~machine_name ++++ linux-2.4.17_mvl21/arch/arm/mach-sa1100/assabet.c +@@ -374,7 +374,7 @@ + } + + +-MACHINE_START(ASSABET, "Intel-Assabet") ++MACHINE_START(ASSABET, "Tradesquare.NL Tuxpad 1") + BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) + BOOT_PARAMS(0xc0000100) + FIXUP(fixup_assabet) diff --git a/linux/montavista-sa-2.4.17-mvl21/mkdep.patch b/linux/montavista-sa-2.4.17-mvl21/mkdep.patch index e69de29bb2..4daeaa11be 100644 --- a/linux/montavista-sa-2.4.17-mvl21/mkdep.patch +++ b/linux/montavista-sa-2.4.17-mvl21/mkdep.patch @@ -0,0 +1,16 @@ + +# +# Made by http://www.mn-logistik.de/unsupported/pxa250/patcher +# + +--- linux/Makefile~mkdep 2003-12-19 09:36:51.000000000 -0800 ++++ linux/Makefile 2003-12-19 09:57:44.000000000 -0800 +@@ -458,7 +458,7 @@ + + dep-files: scripts/mkdep archdep include/linux/version.h + scripts/mkdep -- init/*.c > .depend +- scripts/mkdep -- `find $(FINDHPATH) -name SCCS -prune -o -follow -name \*.h ! -name modversions.h -print` > .hdepend ++ $(foreach, dir, $(FINDHPATH), scripts/mkdep -- `find $(dir) -name SCCS -prune -o -follow -name \*.h ! -name modversions.h -print` >> .hdepend) + $(MAKE) $(patsubst %,_sfdep_%,$(SUBDIRS)) _FASTDEP_ALL_SUB_DIRS="$(SUBDIRS)" + ifdef CONFIG_MODVERSIONS + $(MAKE) update-modverfile diff --git a/linux/montavista-sa-2.4.17-mvl21/remove-montavista-init-stupidity.patch b/linux/montavista-sa-2.4.17-mvl21/remove-montavista-init-stupidity.patch index e69de29bb2..0fd0a96659 100644 --- a/linux/montavista-sa-2.4.17-mvl21/remove-montavista-init-stupidity.patch +++ b/linux/montavista-sa-2.4.17-mvl21/remove-montavista-init-stupidity.patch @@ -0,0 +1,23 @@ + +# +# Patch managed by http://www.holgerschurig.de/patcher.html +# + +--- linux-2.4.17_mvl21/init/main.c~remove-montavista-init-stupidity ++++ linux-2.4.17_mvl21/init/main.c +@@ -852,15 +852,11 @@ + * trying to recover a really broken machine. + */ + +-#ifndef CONFIG_SA1100_BEAGLE + if (execute_command) + execve(execute_command,argv_init,envp_init); + execve("/sbin/init",argv_init,envp_init); + execve("/etc/init",argv_init,envp_init); + execve("/bin/init",argv_init,envp_init); +-#else +- strcpy( argv_init[0], "--login" ); +-#endif + execve("/bin/sh",argv_init,envp_init); + panic("No init found. Try passing init= option to kernel."); + } diff --git a/linux/montavista-sa-2.4.17-mvl21/ucb1x_kill-zombie.patch b/linux/montavista-sa-2.4.17-mvl21/ucb1x_kill-zombie.patch index e69de29bb2..77fdfa6846 100644 --- a/linux/montavista-sa-2.4.17-mvl21/ucb1x_kill-zombie.patch +++ b/linux/montavista-sa-2.4.17-mvl21/ucb1x_kill-zombie.patch @@ -0,0 +1,15 @@ + +# +# Patch managed by http://www.holgerschurig.de/patcher.html +# + +--- linux-2.4.17_mvl21/drivers/misc/beagle-ts.c~ucb1x_kill_daemon ++++ linux-2.4.17_mvl21/drivers/misc/beagle-ts.c +@@ -372,6 +372,7 @@ + ts->rtask = tsk; + + daemonize(); ++ reparent_to_init(); + tsk->tty = NULL; + //tsk->policy = SCHED_FIFO; + //tsk->rt_priority = 1; |