summaryrefslogtreecommitdiff
path: root/linux/montavista-sa-2.4.17-mvl21
diff options
context:
space:
mode:
Diffstat (limited to 'linux/montavista-sa-2.4.17-mvl21')
-rw-r--r--linux/montavista-sa-2.4.17-mvl21/apm-hh-merge.patch561
-rw-r--r--linux/montavista-sa-2.4.17-mvl21/beagle-sound.patch57
-rw-r--r--linux/montavista-sa-2.4.17-mvl21/disable-pcmcia-probe.patch17
-rw-r--r--linux/montavista-sa-2.4.17-mvl21/iw240_we15-6.diff399
-rw-r--r--linux/montavista-sa-2.4.17-mvl21/iw_handlers.w13-5.diff1513
-rw-r--r--linux/montavista-sa-2.4.17-mvl21/iw_handlers.w14-5.diff838
-rw-r--r--linux/montavista-sa-2.4.17-mvl21/machine_name.patch19
-rw-r--r--linux/montavista-sa-2.4.17-mvl21/mkdep.patch16
-rw-r--r--linux/montavista-sa-2.4.17-mvl21/remove-montavista-init-stupidity.patch23
-rw-r--r--linux/montavista-sa-2.4.17-mvl21/ucb1x_kill-zombie.patch15
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;