diff -du -r pcmcia-cs-3.1.31/wireless/hermes.h pcmcia-cs-3.1.31-patched/wireless/hermes.h --- pcmcia-cs-3.1.31/wireless/hermes.h Tue Oct 9 19:34:06 2001 +++ pcmcia-cs-3.1.31-patched/wireless/hermes.h Wed Feb 27 15:12:46 2002 @@ -233,8 +233,60 @@ /* Wavelan-II Management Protocol frame */ #define HERMES_RXSTAT_WMP (0x6000) +/* Inquiry constants and data types */ + +#define HERMES_INQ_TALLIES (0xF100) +#define HERMES_INQ_SCAN (0xF101) +#define HERMES_INQ_LINKSTATUS (0xF200) + #ifdef __KERNEL__ +struct hermes_tallies_frame { + u16 TxUnicastFrames; + u16 TxMulticastFrames; + u16 TxFragments; + u16 TxUnicastOctets; + u16 TxMulticastOctets; + u16 TxDeferredTransmissions; + u16 TxSingleRetryFrames; + u16 TxMultipleRetryFrames; + u16 TxRetryLimitExceeded; + u16 TxDiscards; + u16 RxUnicastFrames; + u16 RxMulticastFrames; + u16 RxFragments; + u16 RxUnicastOctets; + u16 RxMulticastOctets; + u16 RxFCSErrors; + u16 RxDiscards_NoBuffer; + u16 TxDiscardsWrongSA; + u16 RxWEPUndecryptable; + u16 RxMsgInMsgFragments; + u16 RxMsgInBadMsgFragments; + /* Those last are probably not available in very old firmwares */ + u16 RxDiscards_WEPICVError; + u16 RxDiscards_WEPExcluded; +} __attribute__ ((packed)); + +/* modified by patrik@cqure.net */ +/* Grabbed from wlan-ng - Thanks Mark... - Jean II + * This is the result of a scan inquiry command */ +/* Structure describing info about an Access Point */ +struct hermes_scan_apinfo { + u16 channel; /* Channel where the AP sits */ + u16 level; /* Signal level */ + u16 noise; /* Noise level */ + u8 bssid[ETH_ALEN]; /* MAC address of the Access Point */ + u16 beacon_interv; /* Beacon Interval ? */ + u16 capabilities; /* Capabilities ? */ + u16 essidlen; /* ESSID length */ + u8 essid[32]; /* ESSID of the network */ +} __attribute__ ((packed)); +/* Container */ +struct hermes_scan_frame { + struct hermes_scan_apinfo aps[35]; /* Scan result */ +} __attribute__ ((packed)); + /* Basic control structure */ typedef struct hermes { uint iobase; @@ -313,6 +365,15 @@ return hermes_docmd_wait(hw, HERMES_CMD_ENABLE | (port << 8), 0, &resp); +} + +/* Initiate an INQUIRE command (tallies or scan). The result will come as an + * information frame in __dldwd_ev_info() */ +static inline int hermes_inquire(hermes_t *hw, u16 rid) +{ + hermes_response_t resp; + + return hermes_docmd_wait(hw, HERMES_CMD_INQ, rid, &resp); } #define HERMES_BYTES_TO_RECLEN(n) ( ((n) % 2) ? (((n)+1)/2)+1 : ((n)/2)+1 ) diff -du -r pcmcia-cs-3.1.31/wireless/orinoco.c pcmcia-cs-3.1.31-patched/wireless/orinoco.c --- pcmcia-cs-3.1.31/wireless/orinoco.c Fri Oct 19 20:53:20 2001 +++ pcmcia-cs-3.1.31-patched/wireless/orinoco.c Wed Feb 27 15:42:15 2002 @@ -237,6 +237,8 @@ #include #include #include +#include +#include #include #include @@ -341,6 +343,13 @@ uint16_t qual, signal, noise; } __PACKED__ dldwd_commsqual_t; +/* sniffing stuff added by Patrik Karlsson, patrik@cqure.net 20020201 */ +/* Netlink interface(s) */ +static struct sock *nl_indicate = NULL; + +#define APSTATUS_NL_SOCK_IND NETLINK_USERSOCK +#define APSTATUS_NL_MCAST_GRP_SNIFF 0x00000002 + #define TX_TIMEOUT (4*HZ) /* 4 second timeout */ /* @@ -399,6 +408,9 @@ static int dldwd_proc_init(void); static void dldwd_proc_cleanup(void); +/* dummy functions */ +void p80211ind_rx(struct sock *sk, int len); + /* * Inline functions */ @@ -1083,9 +1095,110 @@ static void __dldwd_ev_info(dldwd_priv_t *priv, hermes_t *hw) { - DEBUG(3, "%s: Information frame received.\n", priv->ndev.name); - /* We don't actually do anything about it - we assume the MAC - controller can deal with it */ + struct net_device *dev = &priv->ndev; + u16 infofid; + struct { + u16 len; + u16 type; + } __attribute__ ((packed)) info; + int err; + + /* This is an answer to an INQUIRE command that we did earlier, + * or an information "event" generated by the card + * The controller return to us a pseudo frame containing + * the information in question - Jean II */ + infofid = hermes_read_regn(hw, INFOFID); + DEBUG(3, "%s: __dldwd_ev_info(): INFOFID=0x%04x\n", dev->name, + infofid); + + /* Read the info frame header - don't try too hard */ + err = hermes_bap_pread(hw, IRQ_BAP, &info, sizeof(info), + infofid, 0); + if (err) { + printk(KERN_ERR "%s: error %d reading info frame. " + "Frame dropped.\n", dev->name, err); + return; + } + + switch (le16_to_cpu(info.type)) { + + /* + * do the actual scanning, 20020201 patrik@cqure.net + */ + case HERMES_INQ_SCAN: { + struct hermes_scan_frame scan; + struct sk_buff *skb; + int len = le16_to_cpu(info.len) - 1; + + /* len seems to be 25 even if its longer */ + if ( len >= 25 ) + len = sizeof(struct hermes_scan_apinfo); + + hermes_read_words(hw, HERMES_DATA1, (void *)&scan, len); + + if ( ( skb = alloc_skb(len, GFP_ATOMIC) ) == NULL ) { + DEBUG(2, "alloc_skb failed trying to allocate %d bytes\n", len); + return; + } + + skb_put(skb, len); + memcpy(skb->data, &scan, len); + + + /* create a netlink socket to listen to */ + nl_indicate = netlink_kernel_create( APSTATUS_NL_SOCK_IND, &p80211ind_rx); + + netlink_broadcast(nl_indicate, skb, 0, APSTATUS_NL_MCAST_GRP_SNIFF, + GFP_ATOMIC); + + sock_release(nl_indicate->socket); + + break; + + } + case HERMES_INQ_TALLIES: { + struct hermes_tallies_frame tallies; + struct iw_statistics *wstats = &priv->wstats; + int len = le16_to_cpu(info.len) - 1; + + if (len > (sizeof(tallies) / 2)) { + DEBUG(1, "%s: tallies frame too long.\n", dev->name); + len = sizeof(tallies) / 2; + } + + /* Read directly the data (no seek) */ + hermes_read_words(hw, HERMES_DATA1, (void *) &tallies, len); + + /* Increment our various counters */ + /* wstats->discard.nwid - no wrong BSSID stuff */ + wstats->discard.code += + le16_to_cpu(tallies.RxWEPUndecryptable); + if (len == (sizeof(tallies) / 2)) + wstats->discard.code += + le16_to_cpu(tallies.RxDiscards_WEPICVError) + + le16_to_cpu(tallies.RxDiscards_WEPExcluded); + wstats->discard.misc += + le16_to_cpu(tallies.TxDiscardsWrongSA); +#if WIRELESS_EXT > 11 + wstats->discard.fragment += + le16_to_cpu(tallies.RxMsgInBadMsgFragments); + wstats->discard.retries += + le16_to_cpu(tallies.TxRetryLimitExceeded); + /* wstats->miss.beacon - no match */ +#if ORINOCO_DEBUG > 3 + /* Hack for debugging - should not be taken as an example */ + wstats->discard.nwid += le16_to_cpu(tallies.TxUnicastFrames); + wstats->miss.beacon += le16_to_cpu(tallies.RxUnicastFrames); +#endif +#endif /* WIRELESS_EXT > 11 */ + } + break; + default: + DEBUG(1, "%s: Unknown information frame received (type %04x).\n", + priv->ndev.name, le16_to_cpu(info.type)); + /* We don't actually do anything about it */ + break; + } } static void __dldwd_ev_rx(dldwd_priv_t *priv, hermes_t *hw) @@ -3602,6 +3715,17 @@ total, buf); } +/* + * Empty dummy function, theres nothing to see here + */ +static int +orinoco_proc_get_hermes_cmds(char *page, char **start, off_t requested_offset, + int requested_len, int *eof, void *data) +{ + return 0; +} + + /* initialise the /proc subsystem for the hermes driver, creating the * separate entries */ static int @@ -3624,6 +3748,43 @@ return err; } +/* copy-paste linux-wlan-ng */ +/* userland data not supported */ +void p80211ind_rx(struct sock *sk, int len) +{ + return; +} + + +int +orinoco_send_scan_cmd(dldwd_priv_t *priv) { + + hermes_inquire(&priv->hw, HERMES_INQ_SCAN); + + return 0; +} + +int +orinoco_proc_set_hermes_cmds(struct file *file, const char *buffer, + unsigned long count, void *context) +{ + char buf[256]; + + /* copy - paste code from elsewere in kernel */ + if (count > 250) + return -EPERM; + if (copy_from_user(buf, buffer, count)) + return -EFAULT; + + buf[count] = 0; + + if (!strncmp(buf, "apscan", 6)) { + orinoco_send_scan_cmd(context); + } + + return -EL3RST; +} + int dldwd_proc_dev_init(dldwd_priv_t *dev) { @@ -3653,6 +3814,16 @@ printk(KERN_ERR "Unable to initialise /proc/hermes/%s/recs.\n", ndev->name); goto fail; } + + dev->dir_cmds = NULL; + dev->dir_cmds = create_proc_read_entry("cmds", S_IFREG | S_IRUGO, + dev->dir_dev, orinoco_proc_get_hermes_cmds, dev); + if (dev->dir_cmds == NULL) { + printk(KERN_ERR "Unable to initialise /proc/hermes/%s/cmds.\n", ndev->name); + goto fail; + } + + dev->dir_cmds->write_proc = orinoco_proc_set_hermes_cmds; return 0; fail: diff -du -r pcmcia-cs-3.1.31/wireless/orinoco.h pcmcia-cs-3.1.31-patched/wireless/orinoco.h --- pcmcia-cs-3.1.31/wireless/orinoco.h Tue Oct 9 20:01:32 2001 +++ pcmcia-cs-3.1.31-patched/wireless/orinoco.h Wed Feb 27 14:36:47 2002 @@ -102,6 +102,7 @@ struct proc_dir_entry *dir_dev; struct proc_dir_entry *dir_regs; struct proc_dir_entry *dir_recs; + struct proc_dir_entry *dir_cmds; } dldwd_priv_t; /*====================================================================*/