Only in airo-021-dragorn/driver: Makefile
diff -u -r airo-021-pristine/driver/airo.c airo-021-dragorn/driver/airo.c
--- airo-021-pristine/driver/airo.c	2004-04-08 10:42:45.000000000 -0400
+++ airo-021-dragorn/driver/airo.c	2004-08-05 00:37:36.000000000 -0400
@@ -26,7 +26,29 @@
                           added driver version request
                           added RF monitor support
 			  fixed wireless-tools support
-    
+  
+    Kismet/Dragorn patch 0.1
+    Additional/repaired functionality for use with Kismet (and in general)
+    dragorn@kismetwireless.net
+    0.2         Fixed up some more netif_queue ops in monitor mode
+                Rewrote packet/fid scheduler to get more throughput and to
+                 prevent dropping packets like crazy in high-load situations
+                 leading to link failures
+    0.1         Monitor mode, wireless extentions turned on by default
+                Removed capabilities check for WEP (seems to be broken, at
+                 least on my hardware.)  This lets users set WEP keys
+                 normally.  This will probably break on something, but it
+                 works for me.
+                Fixed linktype in monitor mode (set to 80211, not ETHER)
+                Fixed packet type (RAW_80211 instead of ETHER in SKB)
+                Changed [s|g]etRFMonitor ioctls to use integers instead of
+                 chars (sorry, but 'on' and 'off' is just annoying.)
+                Fixed transmit queue to not inject 802.3 packets into the
+                 802.11 packet stream while in monitor mode
+                Added nasty kluge to remember the last channel set in the
+                 airo_info record since the firmware doesn't seem willing
+                 to give it to us, even in monitor mode.
+
 ======================================================================*/
 
 #ifndef __KERNEL__
@@ -147,16 +169,22 @@
                      must have WIRELESS_EXT (include linux/wireless.h)
 #define INCLUDE_RFMONITOR
  */
+#define INCLUDE_RFMONITOR
+
+// Define the raw packet SKB type
+#ifdef INCLUDE_RFMONITOR
+#define ETH_P_80211_RAW        (ETH_P_ECONET + 1)
+#endif
 
 /* Include Wireless Extension definition and check version - Jean II */
-/*
+
 #include <linux/wireless.h>
 #define WIRELESS_SPY		// enable iwspy support
 #if WIRELESS_EXT < 9
 #warning "Wireless extension v9 or newer required - please upgrade your kernel"
 #undef WIRELESS_EXT
 #endif
-*/
+
 #define CISCO_EXT		// enable Cisco extensions
 
 #ifdef CISCO_EXT
@@ -953,6 +981,24 @@
 static int getQuality(StatusRid *statusRid, CapabilityRid *capsRid);
 #endif
 
+/* Linked queue of FIDs 
+ * In an attempt to improve throughput, we'll add a linked queue of 
+ * available FIDs.  Instead of doing an iterative search to get the next
+ * available FID, we can just pop the head of the queue, and stick it
+ * back when we're done - dragorn */
+struct fid_rec {
+    int fid;
+    int len;
+    struct fid_rec *next;
+};
+
+/* Add a fid to the available queue */
+static void alloc_avail_fid(struct airo_info *ai, int in_fid);
+/* Grab the next available fid (and remove it from the queue) */
+static int fetch_avail_fid(struct airo_info *ai, int in_len);
+/* Complete transmission on a fid */
+static int complete_tx_fid(struct airo_info *ai, int in_fid);
+
 struct airo_info {
   struct net_device_stats	stats;
   int open;
@@ -962,9 +1008,17 @@
   struct net_device             *dev;
   /* Note, we can have MAX_FIDS outstanding.  FIDs are 16-bits, so we
    *     use the high bit to mark wether it is in use. 
+   *
+   *     -- nyet, we're using 2 queues now -- dragorn
    */
 #define MAX_FIDS 6
-  int                           fids[MAX_FIDS];
+  /* int                           fids[MAX_FIDS]; */
+  /* FID's available for tranmit */
+  struct fid_rec *avail_queue;
+
+  /* FID's currently being used to transmit */
+  struct fid_rec *tx_queue;
+
   int registered;
   ConfigRid config;
   /* MIC stuff         */
@@ -1001,6 +1055,8 @@
   int (*bap_read)(struct airo_info*, u16 *pu16Dst, int bytelen, 
 		  int whichbap);
 #ifdef WIRELESS_EXT
+  int   last_channel;  // Last channel we were set to since we can't 
+                       //get it, apparently, from firmware --dragorn
   int			need_commit;	// Need to set config
   struct iw_statistics	wstats;		// wireless stats
 #ifdef WIRELESS_SPY
@@ -1011,6 +1067,76 @@
 #endif 
 };
 
+
+/* Add a fid to the available queue */
+static void alloc_avail_fid(struct airo_info *ai, int in_fid) {
+    struct fid_rec *nrec;
+
+	nrec = kmalloc(sizeof(struct fid_rec), GFP_KERNEL);
+    
+    nrec->fid = in_fid;
+    nrec->next = NULL;
+
+    nrec->fid = in_fid;
+    nrec->next = ai->avail_queue;
+
+    ai->avail_queue = nrec;
+
+    return;
+}
+
+/* Grab the next available fid (and remove it from the queue) */
+static int fetch_avail_fid(struct airo_info *ai, int in_len) {
+    struct fid_rec *head;
+
+    if (ai->avail_queue == NULL)
+        return 0;
+
+    head = ai->avail_queue;
+
+    /* strip it off the head.  If we're the last element, next is null,
+     * and the compare tests the head... blah blah blah, this is safe. */
+    ai->avail_queue = head->next;
+
+    /* Add it to the tx queue */
+    head->next = ai->tx_queue;
+    ai->tx_queue = head;
+  
+    /* Remember the length */
+    head->len = in_len;
+
+    return head->fid;
+}
+
+/* Complete a fid */
+static int complete_tx_fid(struct airo_info *ai, int in_fid) {
+    struct fid_rec *x = NULL;
+    struct fid_rec *prex = NULL;
+
+    /* Iterative search, but hopefully shorter and in an intelligent 
+     * order, vs. pure iterative over all fids */
+    x = ai->tx_queue;
+    while (x != NULL) {
+        if (x->fid == in_fid) {
+            if (prex == NULL) 
+                ai->tx_queue = x->next;
+            else 
+                prex->next = x->next;
+        
+            /* Merge it back into the available fids */
+            x->next = ai->avail_queue;
+            ai->avail_queue = x;
+
+            return x->len;
+        }
+
+        prex = x;
+        x = x->next;
+    }
+
+    return -1;
+}
+
 static inline int bap_read(struct airo_info *ai, u16 *pu16Dst, int bytelen, 
 			   int whichbap) {
 	return ai->bap_read(ai, pu16Dst, bytelen, whichbap);
@@ -1045,17 +1171,33 @@
   u16 status;
   u32 flags;
   s8 *buffer;
-  int i;
   struct airo_info *priv = (struct airo_info*)dev->priv;
+  int fid;
+#if 0
+  int i;
   u32 *fids = priv->fids;
+#endif
   
   if ( skb == NULL ) {
     printk( KERN_ERR "airo:  skb == NULL!!!\n" );
     return 0;
   }
-	
+
+  /* Blow up if we're still transmitting a la orinoco - dragorn */
+  if (!netif_running(dev)) {
+    printk( KERN_ERR "airo: Tx on stopped device.\n");
+    return 1;
+  }
+
+  if (netif_queue_stopped(dev)) {
+      printk(KERN_ERR "airo: Tx while transmitter busy\n");
+      return 1;
+  }
+
   /* Find a vacant FID */
   spin_lock_irqsave(&priv->bap1_lock, flags);
+
+#if 0
   for( i = 0; i < MAX_FIDS; i++ ) {
     if ( !( fids[i] & 0xffff0000 ) ) break;
   }
@@ -1065,14 +1207,44 @@
     retval = -EBUSY;
     goto tx_done;
   }
-  
+#endif
+
+  /* Dump out an error counter if we try to transmit a frame while in
+     monitor mode.  We can stop the queue here, too -- dragorn */
+  if (priv->flags&FLAG_RFMONITOR) {
+      netif_stop_queue(dev);
+      retval = -EBUSY;
+      goto tx_done;
+  }
+
   len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; /* check min length*/
   buffer = skb->data;
+ 
+  /* Find an available fid */
+  if ((fid = fetch_avail_fid(priv, len)) == 0) {
+    /* If there are none, we need to stop the queue, and we'll restart it
+     * in the tx interrupt handler */
+    netif_stop_queue(dev);
+    retval = -EBUSY;
+    goto tx_done;
+  }
   
   status = transmit_802_3_packet( priv, 
-				  fids[i],
+				  fid,
 				  skb->data, len );
+
+  if (status == SUCCESS) {
+      dev->trans_start = jiffies;
+  } else {
+      /* Dequeue if there was an error, but this shouldn't happen often 
+       * so we'll ignore the inefficiencies of doing it this way, for now.
+       * This isn't HORRIBLE either since it's at the beginning of the 
+       * queue and should be found with 1 op. */
+      ((struct airo_info *) dev->priv)->stats.tx_errors++;
+      complete_tx_fid(dev->priv, fid);
+  }
   
+#if 0
   if ( status == SUCCESS ) {
     /* Mark fid as used & save length for later */
     fids[i] |= (len << 16); 
@@ -1080,6 +1252,8 @@
   } else {
 	  ((struct airo_info*)dev->priv)->stats.tx_errors++;
 	}
+#endif
+
  tx_done:
   spin_unlock_irqrestore(&priv->bap1_lock, flags);
   KFREE_SKB( skb, FREE_WRITE );
@@ -1220,7 +1394,7 @@
   }
   /* Allocate the transmit buffers */
   for( i = 0; i < MAX_FIDS; i++ ) {
-    ai->fids[i] = transmit_allocate( ai, 2000 );
+    alloc_avail_fid(ai, transmit_allocate(ai, 2000));
   }
   
   setup_proc_entry( dev, (struct airo_info*)dev->priv );
@@ -1249,8 +1423,9 @@
 			);
 		/* Allocate the transmit buffers */
 		for( i = 0; i < MAX_FIDS; i++ ) {
-			((struct airo_info*)dev->priv)->fids[i] =
-				transmit_allocate( ai, 2000 );
+            alloc_avail_fid((struct airo_info *) dev->priv, 
+                            transmit_allocate((struct airo_info *) dev->priv, 
+                                              2000));
 		}
 	}
 	enable_interrupts( ai );
@@ -1377,7 +1552,11 @@
           memcpy(buffer,apriv->micrxbuf+20,len);
           skb->mac.raw = skb->data;
           skb->pkt_type = PACKET_OTHERHOST;
+
+          /* What?  No.  These are raw 802.11 frames  -- dragorn
           skb->protocol = htons(ETH_P_802_2);
+          */
+          skb->protocol = htons(ETH_P_80211_RAW); 
           skb->dev = dev;
           skb->ip_summed = CHECKSUM_NONE;
           netif_rx( skb );
@@ -1471,11 +1650,42 @@
   if (  status & ( EV_TX|EV_TXEXC ) ) {
     int i;
     int len = 0;
-    int full = 1;
+    int full = 0;
+#if 0
     int index = -1;
+#endif
     
     fid = IN4500(apriv, TXCOMPLFID);
+
+    /* New scheduler -- dragorn */
+
+    /* if the head of the avail queue is null, we're probbaly full up,
+     * so schedule a test to see if we should wake */
+    if (apriv->avail_queue == NULL)
+        full = 1;
+
+    /* Move the fid back to the available queue, if we can */
+    if ((len = complete_tx_fid(apriv, fid)) < 0) {
+        /* I really don't know how this error could be generated... */
+        printk(KERN_ERR "airo: Transmit FID not in txqueue: %d\n",
+               fid);
+    }
+
+    if ((status & EV_TX) && len > 0) {
+        apriv->stats.tx_packets++;
+#if LINUX_VERSION_CODE > 0x20127
+        apriv->stats.tx_bytes += len;
+#endif
+    } else {
+        apriv->stats.tx_errors++;
+    }
+
+    /* Wake up the queue if we were full and now we're not */
+    if (full && apriv->avail_queue != NULL && netif_queue_stopped(dev)) {
+        netif_wake_queue(dev);
+    }
     
+#if 0
     for( i = 0; i < MAX_FIDS; i++ ) {
       if (!(apriv->fids[i] & 0xffff0000)) full = 0;
       if ( ( apriv->fids[i] & 0xffff ) == fid ) {
@@ -1485,7 +1695,8 @@
 	apriv->fids[i] &= 0xffff; 
       }
     }
-    if (full) netif_wake_queue(dev);
+
+    /* if (full) netif_wake_queue(dev); */
     if (index==-1) {
       printk( KERN_ERR "airo: Unallocated FID was used to xmit\n" );
     }
@@ -1498,6 +1709,8 @@
     } else {
       apriv->stats.tx_errors++;
     }
+#endif
+
   }
   /* MIC was setting this off */
   if ( status & ~STATUS_INTS ) 
@@ -1567,9 +1780,24 @@
     configRid.refreshInterval = 0xffff;
     configRid.authType = AUTH_OPEN;
     PC4500_writerid(ai, 0xff10, &configRid, sizeof(ConfigRid));
+
+    /* Set the link type correctly.  -- Dragorn */
+    ai->dev->type = ARPHRD_IEEE80211;
+
+    /* and stop the queue since we can't tx in rfmon */
+    netif_stop_queue(ai->dev);
+
   } else {
     PC4500_readrid(ai, 0xff21, &configRid, sizeof(ConfigRid));
     PC4500_writerid(ai, 0xff10, &configRid, sizeof(ConfigRid));
+  
+    /* Set the link type back -- Dragorn */
+    ai->dev->type = ARPHRD_ETHER;
+
+    /* And wake the network queue if it's stopped since we turned it off 
+     * if there was any attempt to tx in rfmon */
+    if (netif_queue_stopped(ai->dev))
+        netif_wake_queue(ai->dev);
   }
   memset(&cmd, 0, sizeof(cmd));
   cmd.cmd = MAC_ENABLE;
@@ -1715,6 +1943,10 @@
     }
   }
 
+  /* Initialize the queues -- dragorn */
+  ai->avail_queue = NULL;
+  ai->tx_queue = NULL;
+  
   /* Setup the SSIDs if present */
   if ( ssids[0] ) {
     int i = 0;
@@ -2046,7 +2278,7 @@
   Cmd cmd;
   Resp rsp;
   //  u8 mictxbuf[2048];
-	
+
   if (len < 12) {
     printk( KERN_WARNING "Short packet %d\n", len );
     return ERROR;
@@ -3537,6 +3769,7 @@
 			} else {
 				/* Yes ! We can set it !!! */
 				config.channelSet = (u16)cpu_to_le16(channel);
+                local->last_channel = channel - 1;
 				local->need_commit = 1;
 			}
 		}
@@ -3545,11 +3778,19 @@
 	// Get frequency/channel
 	case SIOCGIWFREQ:
 #ifdef WEXT_USECHANNELS
-		wrq->u.freq.m = ((int) le16_to_cpu(status_rid.channel) + 1);
+        /* Use the last set if we can't get it out of the status rid - dragorn */
+        if ((int) le16_to_cpu(status.channel) == 0) {
+            wrq->u.freq.m = local->last_channel;
+        } else {
+            wrq->u.freq.m = ((int) le16_to_cpu(config.channel) + 1);
+        }
 		wrq->u.freq.e = 0;
 #else
 		{
-			int f = (int) le16_to_cpu(status_rid.channel);
+            /* and again  -d */
+			int f = (int) le16_to_cpu(config.channel);
+            if (f == 0) 
+                f = local->last_channel;
 			wrq->u.freq.m = frequency_list[f] * 100000;
 			wrq->u.freq.e = 1;
 		}
@@ -3832,10 +4073,12 @@
 	// Set WEP keys and mode
 	case SIOCSIWENCODE:
 		/* Is WEP supported ? */
+        /* THis seems broken? --dragorn
 		if(!(cap_rid.softCap & 2)) {
 			rc = -EOPNOTSUPP;
 			break;
 		}
+        */
 		/* Basic checking: do we have a key to set ? */
 		if (wrq->u.encoding.pointer != (caddr_t) 0) {
 			wep_key_t key;
@@ -4228,13 +4471,14 @@
                           IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 16,
                           "getProductName" },
 #ifdef INCLUDE_RFMONITOR
+                        /* Strings are no good.  Change to int.  --dragorn */
                         { SIOCIWFIRSTPRIV+12,
-                          IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 3,
+                          IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
                           0,
                           "setRFMonitor" },
                         { SIOCIWFIRSTPRIV+13,
                           0,
-                          IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 3,
+                          IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
                           "getRFMonitor" },
 #endif
 			};
@@ -4324,6 +4568,8 @@
 #ifdef INCLUDE_RFMONITOR
        case SIOCIWFIRSTPRIV+12:	/* rf monitor */
          rc = 0;
+
+         /* String-based controls?  This just sucks.  --dragorn
          if (!strcmp(wrq->u.name, "on")) {
            local->flags |= FLAG_RFMONITOR;
          } else if (!strcmp(wrq->u.name, "off")) {
@@ -4331,6 +4577,17 @@
          } else {
            rc = -EINVAL;
          }
+         */
+
+         /* Lets do this more nicely */
+         if (wrq->u.name[0] == 1) {
+             local->flags |= FLAG_RFMONITOR;
+         } else if (wrq->u.name[0] == 0) {
+             local->flags &= ~FLAG_RFMONITOR;
+         } else {
+             rc = -EINVAL;
+         }
+
          if (rc == 0) {
            set_rfmonitor(local);
          }
@@ -4338,9 +4595,15 @@
        case SIOCIWFIRSTPRIV+13:	/* rf monitor */
          PC4500_readrid(local, 0xff20, &config, sizeof(ConfigRid));
          if (config.rmode == (0x300 | RXMODE_RFMON_ANYBSS)) {
-           strcpy(wrq->u.name, "on");
+             /* Strings suck --dragorn 
+                strcpy(wrq->u.name, "on");
+              */
+             int *val = (int *) wrq->u.name;
+             (*val) = 1;
          } else {
-           strcpy(wrq->u.name, "off");
+             /* strcpy(wrq->u.name, "off"); */
+             int *val = (int *) wrq->u.name;
+             (*val) = 0;
          }
          rc = 0;
          break;
@@ -4914,7 +5177,7 @@
   status = setup_card(ai, dev->dev_addr,&((struct airo_info*)dev->priv)->config);
   
   for( i = 0; i < MAX_FIDS; i++ ) {
-    ai->fids[i] = transmit_allocate( ai, 2000 );
+    alloc_avail_fid(ai, transmit_allocate(ai, 2000));
   }
   
   mdelay(1024);          /* Added 12/7/00 */

