patch-2.3.24 linux/drivers/net/pcmcia/ray_cs.c

Next file: linux/drivers/net/pcmcia/ray_cs.h
Previous file: linux/drivers/net/irda/w83977af_ir.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.23/linux/drivers/net/pcmcia/ray_cs.c linux/drivers/net/pcmcia/ray_cs.c
@@ -38,6 +38,7 @@
 
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
+#include <linux/if_arp.h>
 #include <linux/ioport.h>
 #include <linux/skbuff.h>
 
@@ -49,6 +50,19 @@
 #include <pcmcia/ds.h>
 #include <pcmcia/mem_op.h>
 
+#ifdef HAS_WIRELESS_EXTENSIONS
+#include <linux/wireless.h>
+#if WIRELESS_EXT < 8
+#warning "Wireless extension v8 or newer required"
+#endif	/* WIRELESS_EXT < 8 */
+/* Warning : these stuff will slow down the driver... */
+#define WIRELESS_SPY		/* Enable spying addresses */
+/* Definitions we need for spy */
+typedef struct iw_statistics	iw_stats;
+typedef struct iw_quality	iw_qual;
+typedef u_char	mac_addr[ETH_ALEN];	/* Hardware address */
+#endif	/* HAS_WIRELESS_EXTENSIONS */
+
 #include "rayctl.h"
 #include "ray_cs.h"
 
@@ -72,67 +86,68 @@
 #define DEBUG(n, args...)
 #endif
 /** Prototypes based on PCMCIA skeleton driver *******************************/
-void ray_config(dev_link_t *link);
-void ray_release(u_long arg);
-int ray_event(event_t event, int priority, event_callback_args_t *args);
-dev_link_t *ray_attach(void);
-void ray_detach(dev_link_t *);
+static void ray_config(dev_link_t *link);
+static void ray_release(u_long arg);
+static int ray_event(event_t event, int priority, event_callback_args_t *args);
+static dev_link_t *ray_attach(void);
+static void ray_detach(dev_link_t *);
 
 /***** Prototypes indicated by device structure ******************************/
-int ray_dev_close(struct net_device *dev);
-int ray_dev_config(struct net_device *dev, struct ifmap *map);
-struct enet_statistics *ray_get_stats(struct net_device *dev);
-int ray_dev_init(struct net_device *dev);
-int ray_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
-int ray_open(struct net_device *dev);
-int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static int ray_dev_close(struct net_device *dev);
+static int ray_dev_config(struct net_device *dev, struct ifmap *map);
+static struct enet_statistics *ray_get_stats(struct net_device *dev);
+static int ray_dev_init(struct net_device *dev);
+static int ray_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
+static int ray_open(struct net_device *dev);
+static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev);
 static void set_multicast_list(struct net_device *dev);
 static void ray_update_multi_list(struct net_device *dev, int all);
-int encapsulate_frame(ray_dev_t *local, struct tx_msg *ptx, UCHAR msg_type,
-                unsigned char *data, int len);
-int translate_frame(ray_dev_t *local, struct tx_msg *ptx,
+static int translate_frame(ray_dev_t *local, struct tx_msg *ptx,
                 unsigned char *data, int len);
-void ray_build_header(ray_dev_t *local, struct tx_msg *ptx, UCHAR msg_type,
+static void ray_build_header(ray_dev_t *local, struct tx_msg *ptx, UCHAR msg_type,
                 unsigned char *data);
-void untranslate(ray_dev_t *local, struct sk_buff *skb, int len);
+static void untranslate(ray_dev_t *local, struct sk_buff *skb, int len);
+#if WIRELESS_EXT > 7	/* If wireless extension exist in the kernel */
+static iw_stats * ray_get_wireless_stats(struct device *	dev);
+#endif	/* WIRELESS_EXT > 7 */
 
 /***** Prototypes for raylink functions **************************************/
-int asc_to_int(char a);
-void authenticate(ray_dev_t *local);
-int build_auth_frame(ray_dev_t *local, UCHAR *dest, int auth_type);
-void authenticate_timeout(u_long);
-int get_free_ccs(ray_dev_t *local);
-int get_free_tx_ccs(ray_dev_t *local);
-void init_startup_params(ray_dev_t *local);
-int parse_addr(char *in_str, UCHAR *out);
-int ray_hw_xmit(unsigned char* data, int len, struct net_device* dev, UCHAR type);
-int ray_init(struct net_device *dev);
-int interrupt_ecf(ray_dev_t *local, int ccs);
-void ray_reset(struct net_device *dev);
-void ray_update_parm(struct net_device *dev, UCHAR objid, UCHAR *value, int len);
-void verify_dl_startup(u_long);
+static int asc_to_int(char a);
+static void authenticate(ray_dev_t *local);
+static int build_auth_frame(ray_dev_t *local, UCHAR *dest, int auth_type);
+static void authenticate_timeout(u_long);
+static int get_free_ccs(ray_dev_t *local);
+static int get_free_tx_ccs(ray_dev_t *local);
+static void init_startup_params(ray_dev_t *local);
+static int parse_addr(char *in_str, UCHAR *out);
+static int ray_hw_xmit(unsigned char* data, int len, struct net_device* dev, UCHAR type);
+static int ray_init(struct net_device *dev);
+static int interrupt_ecf(ray_dev_t *local, int ccs);
+static void ray_reset(struct net_device *dev);
+static void ray_update_parm(struct net_device *dev, UCHAR objid, UCHAR *value, int len);
+static void verify_dl_startup(u_long);
 
 /* Prototypes for interrpt time functions **********************************/
-void ray_interrupt(int reg, void *dev_id, struct pt_regs *regs);
-void clear_interrupt(ray_dev_t *local);
-void rx_deauthenticate(ray_dev_t *local, struct rcs *prcs, 
+static void ray_interrupt (int reg, void *dev_id, struct pt_regs *regs);
+static void clear_interrupt(ray_dev_t *local);
+static void rx_deauthenticate(ray_dev_t *local, struct rcs *prcs, 
                        unsigned int pkt_addr, int rx_len);
-int copy_from_rx_buff(ray_dev_t *local, UCHAR *dest, int pkt_addr, int len);
-void ray_rx(struct net_device *dev, ray_dev_t *local, struct rcs *prcs);
-void release_frag_chain(ray_dev_t *local, struct rcs *prcs);
-void rx_authenticate(ray_dev_t *local, struct rcs *prcs,
+static int copy_from_rx_buff(ray_dev_t *local, UCHAR *dest, int pkt_addr, int len);
+static void ray_rx(struct net_device *dev, ray_dev_t *local, struct rcs *prcs);
+static void release_frag_chain(ray_dev_t *local, struct rcs *prcs);
+static void rx_authenticate(ray_dev_t *local, struct rcs *prcs,
                      unsigned int pkt_addr, int rx_len);
-void rx_data(struct net_device *dev, struct rcs *prcs, unsigned int pkt_addr, 
+static void rx_data(struct net_device *dev, struct rcs *prcs, unsigned int pkt_addr, 
              int rx_len);
-void associate(ray_dev_t *local);
+static void associate(ray_dev_t *local);
 
 /* Card command functions */
-int dl_startup_params(struct net_device *dev);
-void join_net(u_long local);
-void start_net(u_long local);
+static int dl_startup_params(struct net_device *dev);
+static void join_net(u_long local);
+static void start_net(u_long local);
 /* void start_net(ray_dev_t *local); */
 
-int ray_cs_proc_read(char *buf, char **start, off_t off, int len, int spare);
+static int ray_cs_proc_read(char *buf, char **start, off_t off, int len, int spare);
 /* Create symbol table for registering with kernel in init_module */
 EXPORT_SYMBOL(ray_dev_ioctl);
 EXPORT_SYMBOL(ray_rx);
@@ -283,6 +298,14 @@
 /*===========================================================================*/
 static unsigned char eth2_llc[] = {0xaa, 0xaa, 3, 0, 0, 0};
 
+static char hop_pattern_length[] = { 1,
+	     USA_HOP_MOD,             EUROPE_HOP_MOD,
+	     JAPAN_HOP_MOD,           KOREA_HOP_MOD,
+	     SPAIN_HOP_MOD,           FRANCE_HOP_MOD,
+	     ISRAEL_HOP_MOD,          AUSTRALIA_HOP_MOD,
+	     JAPAN_TEST_HOP_MOD
+};
+
 static char rcsid[] = "Raylink/WebGear wireless LAN - Corey <Thomas corey@world.std.com>";
 
 #ifdef CONFIG_PROC_FS
@@ -298,7 +321,7 @@
 };
 #endif
 /*===========================================================================*/
-void cs_error(client_handle_t handle, int func, int ret)
+static void cs_error(client_handle_t handle, int func, int ret)
 {
     error_info_t err = { func, ret };
     CardServices(ReportError, handle, &err);
@@ -311,7 +334,7 @@
     configure the card at this point -- we wait until we receive a
     card insertion event.
 =============================================================================*/
-dev_link_t *ray_attach(void)
+static dev_link_t *ray_attach(void)
 {
     client_reg_t client_reg;
     dev_link_t *link;
@@ -367,6 +390,9 @@
     dev->set_config = &ray_dev_config;
     dev->get_stats  = &ray_get_stats;
     dev->do_ioctl = &ray_dev_ioctl;
+#if WIRELESS_EXT > 7	/* If wireless extension exist in the kernel */
+    dev->get_wireless_stats = ray_get_wireless_stats;
+#endif
 
     dev->set_multicast_list = &set_multicast_list;
 
@@ -411,7 +437,7 @@
     structures are freed.  Otherwise, the structures will be freed
     when the device is released.
 =============================================================================*/
-void ray_detach(dev_link_t *link)
+static void ray_detach(dev_link_t *link)
 {
     dev_link_t **linkp;
     struct net_device *dev;
@@ -470,7 +496,7 @@
 #define CS_CHECK(fn, args...) \
 while ((last_ret=CardServices(last_fn=(fn),args))!=0) goto cs_failed
 #define MAX_TUPLE_SIZE 128
-void ray_config(dev_link_t *link)
+static void ray_config(dev_link_t *link)
 {
     client_handle_t handle = link->handle;
     tuple_t tuple;
@@ -585,7 +611,7 @@
     ray_release((u_long)link);
 } /* ray_config */
 /*===========================================================================*/
-int ray_init(struct net_device *dev)
+static int ray_init(struct net_device *dev)
 {
     int i;
     UCHAR *p;
@@ -648,7 +674,7 @@
 } /* ray_init */
 /*===========================================================================*/
 /* Download startup parameters to the card and command it to read them       */
-int dl_startup_params(struct net_device *dev)
+static int dl_startup_params(struct net_device *dev)
 {
     int ccsindex;
     ray_dev_t *local = (ray_dev_t *)dev->priv;
@@ -694,16 +720,9 @@
     return 0;
 } /* dl_startup_params */
 /*===========================================================================*/
-void init_startup_params(ray_dev_t *local)
+static void init_startup_params(ray_dev_t *local)
 {
     int i; 
-    static char hop_pattern_length[] = { 1,
-                     USA_HOP_MOD,             EUROPE_HOP_MOD,
-                     JAPAN_HOP_MOD,           KOREA_HOP_MOD,
-                     SPAIN_HOP_MOD,           FRANCE_HOP_MOD,
-                     ISRAEL_HOP_MOD,          AUSTRALIA_HOP_MOD,
-                     JAPAN_TEST_HOP_MOD
-    };
 
     if (country > JAPAN_TEST) country = USA;
     else
@@ -762,7 +781,7 @@
         strncpy(local->sparm.b4.a_current_ess_id, essid, ESSID_SIZE);
 } /* init_startup_params */ 
 /*===========================================================================*/
-void verify_dl_startup(u_long data)
+static void verify_dl_startup(u_long data)
 {
     ray_dev_t *local = (ray_dev_t *)data;
     struct ccs *pccs = ((struct ccs *)(local->sram + CCS_BASE)) + local->dl_param_ccs;
@@ -779,7 +798,7 @@
     printk(KERN_DEBUG "verify_dl_startup parameters sent via ccs %d:\n",
            local->dl_param_ccs);
         for (i=0; i<sizeof(struct b5_startup_params); i++) {
-            printk(" %2x", readb(local->sram + HOST_TO_ECF_BASE + i));
+            printk(" %2x", (unsigned int) readb(local->sram + HOST_TO_ECF_BASE + i));
         }
     printk("\n");
     }
@@ -802,7 +821,7 @@
 } /* end verify_dl_startup */
 /*===========================================================================*/
 /* Command card to start a network */
-void start_net(u_long data)
+static void start_net(u_long data)
 {
     ray_dev_t *local = (ray_dev_t *)data;
     struct ccs *pccs;
@@ -828,7 +847,7 @@
 } /* end start_net */
 /*===========================================================================*/
 /* Command card to join a network */
-void join_net(u_long data)
+static void join_net(u_long data)
 {
     ray_dev_t *local = (ray_dev_t *)data;
 
@@ -860,7 +879,7 @@
     device, and release the PCMCIA configuration.  If the device is
     still open, this will be postponed until it is closed.
 =============================================================================*/
-void ray_release(u_long arg)
+static void ray_release(u_long arg)
 {
     dev_link_t *link = (dev_link_t *)arg;
     struct net_device *dev = link->priv; 
@@ -912,7 +931,7 @@
     actually access the device should check this flag to make sure
     the card is still present.
 =============================================================================*/
-int ray_event(event_t event, int priority,
+static int ray_event(event_t event, int priority,
                      event_callback_args_t *args)
 {
     dev_link_t *link = args->client_data;
@@ -991,7 +1010,7 @@
     return 0;
 }
 /*===========================================================================*/
-int ray_dev_config(struct net_device *dev, struct ifmap *map)
+static int ray_dev_config(struct net_device *dev, struct ifmap *map)
 {
     ray_dev_t *local = dev->priv;
     dev_link_t *link = local->finder;
@@ -1005,7 +1024,7 @@
     return 0;
 }
 /*===========================================================================*/
-int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
     ray_dev_t *local = dev->priv;
     dev_link_t *link = local->finder;
@@ -1047,7 +1066,7 @@
     return 0;
 } /* ray_dev_start_xmit */
 /*===========================================================================*/
-int ray_hw_xmit(unsigned char* data, int len, struct net_device* dev, 
+static int ray_hw_xmit(unsigned char* data, int len, struct net_device* dev, 
                 UCHAR msg_type)
 {
     ray_dev_t *local = (ray_dev_t *)dev->priv;
@@ -1089,7 +1108,7 @@
     }
     else { /* Encapsulate frame */
         /* TBD TIB length will move address of ptx->var */
-        memcpy( (UCHAR *)&ptx->var, data, len);
+        memcpy_toio(&ptx->var, data, len);
         offset = 0;
     }
 
@@ -1121,7 +1140,7 @@
     return XMIT_OK;
 } /* end ray_hw_xmit */
 /*===========================================================================*/
-int translate_frame(ray_dev_t *local, struct tx_msg *ptx, unsigned char *data,
+static int translate_frame(ray_dev_t *local, struct tx_msg *ptx, unsigned char *data,
                     int len)
 {
     unsigned short int proto = ((struct ethhdr *)data)->h_proto;
@@ -1137,7 +1156,7 @@
         /* Copy body of ethernet packet without ethernet header */
         memcpy_toio((UCHAR *)&ptx->var + sizeof(struct snaphdr_t), \
                     data + ETH_HLEN,  len - ETH_HLEN);
-        return sizeof(struct snaphdr_t) - ETH_HLEN;
+        return (int) sizeof(struct snaphdr_t) - ETH_HLEN;
     }
     else { /* already  802 type, and proto is length */
         DEBUG(3,"ray_cs translate_frame 802\n");
@@ -1152,15 +1171,16 @@
     /* TBD do other frame types */
 } /* end translate_frame */
 /*===========================================================================*/
-void ray_build_header(ray_dev_t *local, struct tx_msg *ptx, UCHAR msg_type,
+static void ray_build_header(ray_dev_t *local, struct tx_msg *ptx, UCHAR msg_type,
                 unsigned char *data)
 {
     writeb(PROTOCOL_VER | msg_type, &ptx->mac.frame_ctl_1);
 /*** IEEE 802.11 Address field assignments *************
-                     addr_1       addr_2     addr_3
-     AP              destination  AP(BSSID)  source
-     Infra Terminal  AP           terminal   destination
-     Adhoc           destination  terminal   BSSID
+                TODS FROMDS   addr_1     addr_2          addr_3   addr_4
+Adhoc           0    0        dest       src (terminal)  BSSID    N/A
+AP to Terminal  0    1        dest       AP(BSSID)       source   N/A
+Terminal to AP  1    0        AP(BSSID)  src (terminal)  dest     N/A
+AP to AP        1    1        dest AP    src AP          dest     source      
 *******************************************************/
     if (local->net_type == ADHOC) {   
         writeb(0, &ptx->mac.frame_ctl_2);
@@ -1186,11 +1206,14 @@
     }
 } /* end encapsulate_frame */
 /*===========================================================================*/
-int ray_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+static int ray_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
     ray_dev_t *local = (ray_dev_t *)dev->priv;
     dev_link_t *link = local->finder;
     int err = 0;
+#if WIRELESS_EXT > 7
+    struct iwreq *wrq = (struct iwreq *) ifr;
+#endif	/* WIRELESS_EXT > 7 */
 
     if (!(link->state & DEV_PRESENT)) {
         DEBUG(2,"ray_dev_ioctl - device not present\n");
@@ -1200,6 +1223,257 @@
     /* Validate the command */
     switch (cmd)
     {
+#if WIRELESS_EXT > 7
+      /* --------------- WIRELESS EXTENSIONS --------------- */
+      /* Get name */
+    case SIOCGIWNAME:
+      strcpy(wrq->u.name, "IEEE 802.11-FH");
+      break;
+
+      /* Get frequency/channel */
+    case SIOCGIWFREQ:
+      wrq->u.freq.m = local->sparm.b5.a_hop_pattern;
+      wrq->u.freq.e = 0;
+      break;
+
+      /* Get current network name (ESSID) */
+    case SIOCGIWESSID:
+      if (wrq->u.data.pointer)
+	{
+	  char essid[IW_ESSID_MAX_SIZE + 1];
+	  /* Get the essid that was set */
+	  memcpy(essid, local->sparm.b5.a_current_ess_id,
+		 IW_ESSID_MAX_SIZE);
+	  essid[IW_ESSID_MAX_SIZE] = '\0';
+
+	  /* Push it out ! */
+	  wrq->u.data.length = strlen(essid) + 1;
+	  wrq->u.data.flags = 1; /* active */
+	  copy_to_user(wrq->u.data.pointer, essid, sizeof(essid));
+	}
+      break;
+
+      /* Get current Access Point (BSSID in our case) */
+    case SIOCGIWAP:
+      memcpy(wrq->u.ap_addr.sa_data, local->bss_id, ETH_ALEN);
+      wrq->u.ap_addr.sa_family = ARPHRD_ETHER;
+      break;
+
+      /* Get the current bit-rate */
+    case SIOCGIWRATE:
+      if(local->net_default_tx_rate == 3)
+	wrq->u.bitrate.value = 2000000;		/* Hum... */
+      else
+	wrq->u.bitrate.value = local->net_default_tx_rate * 500000;
+      wrq->u.bitrate.fixed = 0;		/* We are in auto mode */
+      break;
+
+      /* Set the desired bit-rate */
+    case SIOCSIWRATE:
+      /* Check if rate is in range */
+      if((wrq->u.bitrate.value != 1000000) &&
+	 (wrq->u.bitrate.value != 2000000))
+	{
+	  err = -EINVAL;
+	  break;
+	}
+      /* Hack for 1.5 Mb/s instead of 2 Mb/s */
+      if((local->fw_ver == 0x55) &&		/* Please check */
+	 (wrq->u.bitrate.value == 2000000))
+	local->net_default_tx_rate = 3;
+      else
+	local->net_default_tx_rate = wrq->u.bitrate.value/500000;
+      break;
+
+      /* Get the current RTS threshold */
+    case SIOCGIWRTS:
+      wrq->u.rts.value = (local->sparm.b5.a_rts_threshold[0] << 8)
+	+ local->sparm.b5.a_rts_threshold[1];
+#if WIRELESS_EXT > 8
+      wrq->u.rts.disabled = (wrq->u.rts.value == 32767);
+#endif /* WIRELESS_EXT > 8 */
+      wrq->u.rts.fixed = 1;
+      break;
+
+      /* Get the current fragmentation threshold */
+    case SIOCGIWFRAG:
+      wrq->u.frag.value = (local->sparm.b5.a_frag_threshold[0] << 8)
+	+ local->sparm.b5.a_frag_threshold[1];
+#if WIRELESS_EXT > 8
+      wrq->u.frag.disabled = (wrq->u.frag.value == 32767);
+#endif /* WIRELESS_EXT > 8 */
+      wrq->u.frag.fixed = 1;
+      break;
+#endif	/* WIRELESS_EXT > 7 */
+#if WIRELESS_EXT > 8
+
+      /* Get the current mode of operation */
+    case SIOCGIWMODE:
+      if(local->sparm.b5.a_network_type)
+	wrq->u.mode = IW_MODE_INFRA;
+      else
+	wrq->u.mode = IW_MODE_ADHOC;
+      break;
+#endif /* WIRELESS_EXT > 8 */
+#if WIRELESS_EXT > 7
+      /* ------------------ IWSPY SUPPORT ------------------ */
+      /* Define the range (variations) of above parameters */
+    case SIOCGIWRANGE:
+      /* Basic checking... */
+      if(wrq->u.data.pointer != (caddr_t) 0)
+	{
+	  struct iw_range	range;
+	  memset((char *) &range, 0, sizeof(struct iw_range));
+
+	  /* Set the length (useless : its constant...) */
+	  wrq->u.data.length = sizeof(struct iw_range);
+
+	  /* Set information in the range struct */
+	  range.throughput = 1.1 * 1000 * 1000;	/* Put the right number here */
+	  range.num_channels = hop_pattern_length[(int)country]; 
+	  range.num_frequency = 0;
+	  range.max_qual.qual = 0;
+	  range.max_qual.level = 255;	/* What's the correct value ? */
+	  range.max_qual.noise = 255;	/* Idem */
+	  range.num_bitrates = 2;
+	  range.bitrate[0] = 1000000;	/* 1 Mb/s */
+	  range.bitrate[1] = 2000000;	/* 2 Mb/s */
+
+	  /* Copy structure to the user buffer */
+	  if(copy_to_user(wrq->u.data.pointer, &range,
+			  sizeof(struct iw_range)))
+	    err = -EFAULT;
+	}
+      break;
+
+#ifdef WIRELESS_SPY
+      /* Set addresses to spy */
+    case SIOCSIWSPY:
+      /* Check the number of addresses */
+      if(wrq->u.data.length > IW_MAX_SPY)
+	{
+	  err = -E2BIG;
+	  break;
+	}
+      local->spy_number = wrq->u.data.length;
+
+      /* If there is some addresses to copy */
+      if(local->spy_number > 0)
+	{
+	  struct sockaddr	address[IW_MAX_SPY];
+	  int			i;
+
+	  /* Copy addresses to the driver */
+	  if(copy_from_user(address, wrq->u.data.pointer,
+			    sizeof(struct sockaddr) * local->spy_number))
+	    {
+	      err = -EFAULT;
+	      break;
+	    }
+
+	  /* Copy addresses to the lp structure */
+	  for(i = 0; i < local->spy_number; i++)
+	    memcpy(local->spy_address[i], address[i].sa_data, ETH_ALEN);
+
+	  /* Reset structure... */
+	  memset(local->spy_stat, 0x00, sizeof(iw_qual) * IW_MAX_SPY);
+
+#ifdef DEBUG_IOCTL_INFO
+	  printk(KERN_DEBUG "SetSpy - Set of new addresses is :\n");
+	  for(i = 0; i < local->spy_number; i++)
+	    printk(KERN_DEBUG "%02X:%02X:%02X:%02X:%02X:%02X\n",
+		   local->spy_address[i][0],
+		   local->spy_address[i][1],
+		   local->spy_address[i][2],
+		   local->spy_address[i][3],
+		   local->spy_address[i][4],
+		   local->spy_address[i][5]);
+#endif	/* DEBUG_IOCTL_INFO */
+	}
+      break;
+
+      /* Get the spy list and spy stats */
+    case SIOCGIWSPY:
+      /* Set the number of addresses */
+      wrq->u.data.length = local->spy_number;
+
+      /* If the user want to have the addresses back... */
+      if((local->spy_number > 0) && (wrq->u.data.pointer != (caddr_t) 0))
+	{
+	  struct sockaddr	address[IW_MAX_SPY];
+	  int			i;
+
+	  /* Copy addresses from the lp structure */
+	  for(i = 0; i < local->spy_number; i++)
+	    {
+	      memcpy(address[i].sa_data, local->spy_address[i], ETH_ALEN);
+	      address[i].sa_family = ARPHRD_ETHER;
+	    }
+
+	  /* Copy addresses to the user buffer */
+	  if(copy_to_user(wrq->u.data.pointer, address,
+		       sizeof(struct sockaddr) * local->spy_number))
+	    {
+	      err = -EFAULT;
+	      break;
+	    }
+
+	  /* Copy stats to the user buffer (just after) */
+	  if(copy_to_user(wrq->u.data.pointer +
+		       (sizeof(struct sockaddr) * local->spy_number),
+		       local->spy_stat, sizeof(iw_qual) * local->spy_number))
+	    {
+	      err = -EFAULT;
+	      break;
+	    }
+
+	  /* Reset updated flags */
+	  for(i = 0; i < local->spy_number; i++)
+	    local->spy_stat[i].updated = 0x0;
+	}	/* if(pointer != NULL) */
+
+      break;
+#endif	/* WIRELESS_SPY */
+
+      /* ------------------ PRIVATE IOCTL ------------------ */
+#define SIOCSIPFRAMING	SIOCDEVPRIVATE		/* Set framing mode */
+#define SIOCGIPFRAMING	SIOCDEVPRIVATE + 1	/* Get framing mode */
+#define SIOCGIPCOUNTRY	SIOCDEVPRIVATE + 3	/* Get country code */
+    case SIOCSIPFRAMING:
+      if(!suser())	/* For private IOCTLs, we need to check permissions */
+	{
+	  err = -EPERM;
+	  break;
+	}
+      translate = *(wrq->u.name);	/* Set framing mode */
+      break;
+    case SIOCGIPFRAMING:
+      *(wrq->u.name) = translate;
+      break;
+    case SIOCGIPCOUNTRY:
+      *(wrq->u.name) = country;
+      break;
+    case SIOCGIWPRIV:
+      /* Export our "private" intercace */
+      if(wrq->u.data.pointer != (caddr_t) 0)
+	{
+	  struct iw_priv_args	priv[] =
+	  {	/* cmd,		set_args,	get_args,	name */
+	    { SIOCSIPFRAMING, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "set_framing" },
+	    { SIOCGIPFRAMING, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "get_framing" },
+	    { SIOCGIPCOUNTRY, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "get_country" },
+	  };
+	  /* Set the number of ioctl available */
+	  wrq->u.data.length = 3;
+	  /* Copy structure to the user buffer */
+	  if(copy_to_user(wrq->u.data.pointer, (u_char *) priv,
+		       sizeof(priv)))
+	    err = -EFAULT;
+	}
+      break;
+#endif	/* WIRELESS_EXT > 7 */
+
+
         default:
             DEBUG(0,"ray_dev_ioctl cmd = 0x%x\n", cmd);
             err = -EOPNOTSUPP;
@@ -1207,7 +1481,38 @@
     return err;
 } /* end ray_dev_ioctl */
 /*===========================================================================*/
-int ray_open(struct net_device *dev)
+#if WIRELESS_EXT > 7	/* If wireless extension exist in the kernel */
+static iw_stats * ray_get_wireless_stats(struct device *	dev)
+{
+  ray_dev_t *	local = (ray_dev_t *) dev->priv;
+  dev_link_t *link = local->finder;
+  struct status *p = (struct status *)(local->sram + STATUS_BASE);
+
+  if(local == (ray_dev_t *) NULL)
+    return (iw_stats *) NULL;
+
+  local->wstats.status = local->card_status;
+#ifdef WIRELESS_SPY
+  if((local->spy_number > 0) && (local->sparm.b5.a_network_type == 0))
+    {
+      /* Get it from the first node in spy list */
+      local->wstats.qual.qual = local->spy_stat[0].qual;
+      local->wstats.qual.level = local->spy_stat[0].level;
+      local->wstats.qual.noise = local->spy_stat[0].noise;
+      local->wstats.qual.updated = local->spy_stat[0].updated;
+    }
+#endif /* WIRELESS_SPY */
+
+  if((link->state & DEV_PRESENT)) {
+    local->wstats.qual.noise = readb(&p->rxnoise);
+    local->wstats.qual.updated |= 4;
+  }
+
+  return &local->wstats;
+} /* end ray_get_wireless_stats */
+#endif	/* WIRELESS_EXT > 7 */
+/*===========================================================================*/
+static int ray_open(struct net_device *dev)
 {
     dev_link_t *link;
     ray_dev_t *local = (ray_dev_t *)dev->priv;
@@ -1232,7 +1537,7 @@
     return 0;
 } /* end ray_open */
 /*===========================================================================*/
-int ray_dev_close(struct net_device *dev)
+static int ray_dev_close(struct net_device *dev)
 {
     dev_link_t *link;
 
@@ -1255,14 +1560,14 @@
     return 0;
 } /* end ray_dev_close */
 /*===========================================================================*/
-void ray_reset(struct net_device *dev) {
+static void ray_reset(struct net_device *dev) {
     DEBUG(1,"ray_reset entered\n");
     return;
 }
 /*===========================================================================*/
 /* Cause a firmware interrupt if it is ready for one                         */
 /* Return nonzero if not ready                                               */
-int interrupt_ecf(ray_dev_t *local, int ccs)
+static int interrupt_ecf(ray_dev_t *local, int ccs)
 {
     int i = 50;
     dev_link_t *link = local->finder;
@@ -1288,7 +1593,7 @@
 /*===========================================================================*/
 /* Get next free transmit CCS                                                */
 /* Return - index of current tx ccs                                          */
-int get_free_tx_ccs(ray_dev_t *local)
+static int get_free_tx_ccs(ray_dev_t *local)
 {
     int i;
     struct ccs *pccs = (struct ccs *)(local->sram + CCS_BASE);
@@ -1319,7 +1624,7 @@
 /*===========================================================================*/
 /* Get next free CCS                                                         */
 /* Return - index of current ccs                                             */
-int get_free_ccs(ray_dev_t *local)
+static int get_free_ccs(ray_dev_t *local)
 {
     int i;
     struct ccs *pccs = (struct ccs *)(local->sram + CCS_BASE);
@@ -1347,7 +1652,7 @@
     return ECCSFULL;
 } /* get_free_ccs */
 /*===========================================================================*/
-void authenticate_timeout(u_long data)
+static void authenticate_timeout(u_long data)
 {
     ray_dev_t *local = (ray_dev_t *)data;
     del_timer(&local->timer);
@@ -1356,7 +1661,7 @@
     join_net((u_long)local);
 }
 /*===========================================================================*/
-int asc_to_int(char a)
+static int asc_to_int(char a)
 {
     if (a < '0') return -1;
     if (a <= '9') return (a - '0');
@@ -1367,7 +1672,7 @@
     return -1;
 }
 /*===========================================================================*/
-int parse_addr(char *in_str, UCHAR *out)
+static int parse_addr(char *in_str, UCHAR *out)
 {
     int len;
     int i,j,k;
@@ -1395,7 +1700,7 @@
     return status;
 }
 /*===========================================================================*/
-struct enet_statistics *ray_get_stats(struct net_device *dev)
+static struct enet_statistics *ray_get_stats(struct net_device *dev)
 {
     ray_dev_t *local = (ray_dev_t *)dev->priv;
     dev_link_t *link = local->finder;
@@ -1425,7 +1730,7 @@
     return &local->stats;
 }
 /*===========================================================================*/
-void ray_update_parm(struct net_device *dev, UCHAR objid, UCHAR *value, int len)
+static void ray_update_parm(struct net_device *dev, UCHAR objid, UCHAR *value, int len)
 {
     ray_dev_t *local = (ray_dev_t *)dev->priv;
     dev_link_t *link = local->finder;
@@ -1542,7 +1847,7 @@
 /*=============================================================================
  * All routines below here are run at interrupt time.
 =============================================================================*/
-void ray_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+static void ray_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 {
     struct net_device *dev = (struct net_device *)dev_id;
     dev_link_t *link;
@@ -1727,7 +2032,7 @@
             break;
         default:
             DEBUG(1,"ray_cs Unexpected interrupt for RCS 0x%x cmd = 0x%x\n",\
-                  rcsindex, readb(&prcs->interrupt_id));
+                  rcsindex, (unsigned int) readb(&prcs->interrupt_id));
             break;
         }
         writeb(CCS_BUFFER_FREE, &prcs->buffer_status);
@@ -1736,7 +2041,7 @@
     dev->interrupt = 0;
 } /* ray_interrupt */
 /*===========================================================================*/
-void ray_rx(struct net_device *dev, ray_dev_t *local, struct rcs *prcs)
+static void ray_rx(struct net_device *dev, ray_dev_t *local, struct rcs *prcs)
 {
     int rx_len;
     unsigned int pkt_addr;
@@ -1750,6 +2055,7 @@
     rx_len = (readb(&prcs->var.rx_packet.rx_data_length[0]) << 8)
         + readb(&prcs->var.rx_packet.rx_data_length[1]);
 
+    local->last_rsl = readb(&prcs->var.rx_packet.rx_sig_lev);
     pmsg = local->rmem + pkt_addr;
     switch(readb(pmsg))
     {
@@ -1778,17 +2084,18 @@
                           rx_len < sizeof(struct beacon_rx) ? 
                           rx_len : sizeof(struct beacon_rx));
 
+	local->beacon_rxed = 1;
         /* Get the statistics so the card counters never overflow */
         ray_get_stats(dev);
             break;
     default:
-        DEBUG(0,"ray_cs unknown pkt type %2x\n", readb(pmsg));
+        DEBUG(0,"ray_cs unknown pkt type %2x\n", (unsigned int) readb(pmsg));
         break;
     }
 
 } /* end ray_rx */
 /*===========================================================================*/
-void rx_data(struct net_device *dev, struct rcs *prcs, unsigned int pkt_addr, 
+static void rx_data(struct net_device *dev, struct rcs *prcs, unsigned int pkt_addr, 
              int rx_len)
 {
     struct sk_buff *skb = NULL;
@@ -1797,6 +2104,10 @@
     UCHAR *rx_ptr;
     int total_len;
     int tmp;
+#ifdef WIRELESS_SPY
+    int siglev = prcs->var.rx_packet.rx_sig_lev;
+    u_char linksrcaddr[ETH_ALEN];	/* Other end of the wireless link */
+#endif
 
     if (!sniffer) {
         if (translate) {
@@ -1819,7 +2130,7 @@
     }
     DEBUG(4,"ray_cs rx_data packet\n");
     /* If fragmented packet, verify sizes of fragments add up */
-    if (prcs->var.rx_packet.next_frag_rcs_index != 0xFF) {
+    if (readb(&prcs->var.rx_packet.next_frag_rcs_index) != 0xFF) {
         DEBUG(1,"ray_cs rx'ed fragment\n");
         tmp = (readb(&prcs->var.rx_packet.totalpacketlength[0]) << 8)
             +  readb(&prcs->var.rx_packet.totalpacketlength[1]);
@@ -1865,7 +2176,10 @@
     rx_ptr = skb_put( skb, total_len);
     /* Copy the whole packet to sk_buff */
     rx_ptr += copy_from_rx_buff(local, rx_ptr, pkt_addr & RX_BUFF_END, rx_len);
-
+    /* Get source address */
+#ifdef WIRELESS_SPY
+    memcpy(linksrcaddr, ((struct mac_header *)skb->data)->addr_2, ETH_ALEN);
+#endif
     /* Now, deal with encapsulation/translation/sniffer */
     if (!sniffer) {
         if (!translate) { 
@@ -1909,9 +2223,39 @@
 
     local->stats.rx_packets++;
     local->stats.rx_bytes += skb->len;
+
+    /* Gather signal strength per address */
+#ifdef WIRELESS_SPY
+    /* For the Access Point or the node having started the ad-hoc net
+     * note : ad-hoc work only in some specific configurations, but we
+     * kludge in ray_get_wireless_stats... */
+    if(!memcmp(linksrcaddr, local->bss_id, ETH_ALEN))
+      {
+	/* Update statistics */
+	/*local->wstats.qual.qual = none ? */
+	local->wstats.qual.level = siglev;
+	/*local->wstats.qual.noise = none ? */
+	local->wstats.qual.updated = 0x2;
+      }
+    /* Now, for the addresses in the spy list */
+    {
+      int	i;
+      /* Look all addresses */
+      for(i = 0; i < local->spy_number; i++)
+	/* If match */
+	if(!memcmp(linksrcaddr, local->spy_address[i], ETH_ALEN))
+	  {
+	    /* Update statistics */
+	    /*local->spy_stat[i].qual = none ? */
+	    local->spy_stat[i].level = siglev;
+	    /*local->spy_stat[i].noise = none ? */
+	    local->spy_stat[i].updated = 0x2;
+	  }
+    }
+#endif	/* WIRELESS_SPY */
 } /* end rx_data */
 /*===========================================================================*/
-void untranslate(ray_dev_t *local, struct sk_buff *skb, int len)
+static void untranslate(ray_dev_t *local, struct sk_buff *skb, int len)
 {
     snaphdr_t *psnap = (snaphdr_t *)(skb->data + RX_MAC_HEADER_LENGTH);
     struct mac_header *pmac = (struct mac_header *)skb->data;
@@ -1923,11 +2267,23 @@
     UCHAR srcaddr[ADDRLEN];
     UCHAR destaddr[ADDRLEN];
 
-    if (local->sparm.b5.a_acting_as_ap_status != TYPE_STA)
-        memcpy(destaddr, pmac->addr_3, ADDRLEN);
-    else
-        memcpy(destaddr, pmac->addr_1, ADDRLEN);
-    memcpy(srcaddr, pmac->addr_2, ADDRLEN);
+    if (pmac->frame_ctl_2 & FC2_FROM_DS) {
+	if (pmac->frame_ctl_2 & FC2_TO_DS) { /* AP to AP */
+	    memcpy(destaddr, pmac->addr_3, ADDRLEN);
+	    memcpy(srcaddr, ((unsigned char *)pmac->addr_3) + ADDRLEN, ADDRLEN);
+	} else { /* AP to terminal */
+	    memcpy(destaddr, pmac->addr_1, ADDRLEN);
+	    memcpy(srcaddr, pmac->addr_3, ADDRLEN); 
+	}
+    } else { /* Terminal to AP */
+	if (pmac->frame_ctl_2 & FC2_TO_DS) {
+	    memcpy(destaddr, pmac->addr_3, ADDRLEN);
+	    memcpy(srcaddr, pmac->addr_2, ADDRLEN); 
+	} else { /* Adhoc */
+	    memcpy(destaddr, pmac->addr_1, ADDRLEN);
+	    memcpy(srcaddr, pmac->addr_2, ADDRLEN); 
+	}
+    }
 
 #ifdef PCMCIA_DEBUG
     if (pc_debug > 3) {
@@ -2005,7 +2361,7 @@
  * pkt_addr = source address in receive buffer
  * len      = length of packet to copy
  */
-int copy_from_rx_buff(ray_dev_t *local, UCHAR *dest, int pkt_addr, int length)
+static int copy_from_rx_buff(ray_dev_t *local, UCHAR *dest, int pkt_addr, int length)
 {
     int wrap_bytes = (pkt_addr + length) - (RX_BUFF_END + 1);
     if (wrap_bytes <= 0)
@@ -2020,7 +2376,7 @@
     return length;
 }
 /*===========================================================================*/
-void release_frag_chain(ray_dev_t *local, struct rcs* prcs)
+static void release_frag_chain(ray_dev_t *local, struct rcs* prcs)
 {
     struct rcs *prcslink = prcs;
     int tmp = 17;
@@ -2038,7 +2394,7 @@
     writeb(CCS_BUFFER_FREE, &prcslink->buffer_status);
 }
 /*===========================================================================*/
-void authenticate(ray_dev_t *local)
+static void authenticate(ray_dev_t *local)
 {
     dev_link_t *link = local->finder;
     DEBUG(0,"ray_cs Starting authentication.\n");
@@ -2060,7 +2416,7 @@
     local->authentication_state = AWAITING_RESPONSE;
 } /* end authenticate */
 /*===========================================================================*/
-void rx_authenticate(ray_dev_t *local, struct rcs *prcs,
+static void rx_authenticate(ray_dev_t *local, struct rcs *prcs,
                      unsigned int pkt_addr, int rx_len)
 {
     UCHAR buff[256];
@@ -2103,7 +2459,7 @@
 
 } /* end rx_authenticate */
 /*===========================================================================*/
-void associate(ray_dev_t *local)
+static void associate(ray_dev_t *local)
 {
     struct ccs *pccs;
     dev_link_t *link = local->finder;
@@ -2141,7 +2497,7 @@
 
 } /* end associate */
 /*===========================================================================*/
-void rx_deauthenticate(ray_dev_t *local, struct rcs *prcs, 
+static void rx_deauthenticate(ray_dev_t *local, struct rcs *prcs, 
                        unsigned int pkt_addr, int rx_len)
 {
 /*  UCHAR buff[256];
@@ -2154,7 +2510,7 @@
  */
 }
 /*===========================================================================*/
-void clear_interrupt(ray_dev_t *local)
+static void clear_interrupt(ray_dev_t *local)
 {
     writeb(0, local->amem + CIS_OFFSET + HCS_INTR_OFFSET);
 }
@@ -2183,7 +2539,7 @@
 static char *framing[] = {"Encapsulation", "Translation"}
 ;
 /*===========================================================================*/
-int ray_cs_proc_read(char *buf, char **start, off_t offset, 
+static int ray_cs_proc_read(char *buf, char **start, off_t offset, 
                      int len, int unused)
 {
 /* Print current values which are not available via other means
@@ -2229,10 +2585,13 @@
 
     len += sprintf(buf + len, "Framing mode         = %s\n",framing[translate]);
 
-    /* Pull some fields out of last beacon received */
-    len += sprintf(buf + len, "Beacon Interval      = %d Kus\n", 
-                   local->last_bcn.beacon_intvl[0]
-                   + 256 * local->last_bcn.beacon_intvl[1]);
+    len += sprintf(buf + len, "Last pkt signal lvl  = %d\n", local->last_rsl);
+
+    if (local->beacon_rxed) {
+	/* Pull some fields out of last beacon received */
+	len += sprintf(buf + len, "Beacon Interval      = %d Kus\n", 
+		       local->last_bcn.beacon_intvl[0]
+		       + 256 * local->last_bcn.beacon_intvl[1]);
     
     p = local->last_bcn.elements;
     if (p[0] == C_ESSID_ELEMENT_ID) p += p[1] + 2;
@@ -2253,25 +2612,28 @@
         return len;
     }
 
-    if (p[0] == C_FH_PARAM_SET_ELEMENT_ID) {
-        pfh = (struct freq_hop_element *)p;
-        len += sprintf(buf + len, "Hop dwell            = %d Kus\n",
-                       pfh->dwell_time[0] + 256 * pfh->dwell_time[1]);
-        len += sprintf(buf + len, "Hop set              = %d \n", pfh->hop_set);
-        len += sprintf(buf + len, "Hop pattern          = %d \n", pfh->hop_pattern);
-        len += sprintf(buf + len, "Hop index            = %d \n", pfh->hop_index);
-        p += p[1] + 2;
-    }
-    else {
-        len += sprintf(buf + len, "Parse beacon failed at FH param element\n");
-        return len;
+	if (p[0] == C_FH_PARAM_SET_ELEMENT_ID) {
+	    pfh = (struct freq_hop_element *)p;
+	    len += sprintf(buf + len, "Hop dwell            = %d Kus\n",
+			   pfh->dwell_time[0] + 256 * pfh->dwell_time[1]);
+	    len += sprintf(buf + len, "Hop set              = %d \n", pfh->hop_set);
+	    len += sprintf(buf + len, "Hop pattern          = %d \n", pfh->hop_pattern);
+	    len += sprintf(buf + len, "Hop index            = %d \n", pfh->hop_index);
+	    p += p[1] + 2;
+	}
+	else {
+	    len += sprintf(buf + len, "Parse beacon failed at FH param element\n");
+	    return len;
+	}
+    } else {
+	len += sprintf(buf + len, "No beacons received\n");
     }
     return len;
 }
 
 #endif
 /*===========================================================================*/
-int  build_auth_frame(ray_dev_t *local, UCHAR *dest, int auth_type)
+static int build_auth_frame(ray_dev_t *local, UCHAR *dest, int auth_type)
 {
     int addr;
     struct ccs *pccs;

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)