home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.ee.pdx.edu
/
2014.02.ftp.ee.pdx.edu.tar
/
ftp.ee.pdx.edu
/
pub
/
mobile
/
wi.44.patches
/
if_wi.c.diff
< prev
next >
Wrap
Text File
|
2002-01-17
|
16KB
|
594 lines
*** ../wavelan.orig/if_wi.c Thu Jan 17 11:21:23 2002
--- if_wi.c Thu Jan 17 13:47:50 2002
***************
*** 145,150 ****
--- 145,151 ----
static int wi_seek __P((struct wi_softc *, int, int, int));
static int wi_alloc_nicmem __P((struct wi_softc *, int, int *));
static void wi_inquire __P((void *));
+ static void wi_wait_scan __P((void *));
static void wi_setdef __P((struct wi_softc *, struct wi_req *));
static int wi_mgmt_xmit __P((struct wi_softc *, caddr_t, int));
***************
*** 166,171 ****
--- 167,175 ----
static int wi_alloc __P((device_t, int));
static void wi_free __P((device_t));
+ static void wi_get_firmware __P((struct wi_softc *, u_int16_t *, u_int16_t *,
+ u_int16_t *));
+
static int wi_get_cur_ssid __P((struct wi_softc *, char *, int *));
static int wi_media_change __P((struct ifnet *));
***************
*** 436,441 ****
--- 440,446 ----
struct wi_ltv_gen gen;
struct ifnet *ifp;
int error;
+ u_int16_t v, maj, min;
sc = device_get_softc(dev);
ifp = &sc->arpcom.ac_if;
***************
*** 472,477 ****
--- 477,486 ----
device_printf(dev, "Ethernet address: %6D\n",
sc->arpcom.ac_enaddr, ":");
+ wi_get_firmware( sc, &v, &maj, &min);
+ printf("wi%d: (hw type=%d, firmware=0x%02x:%02x)\n",
+ sc->wi_unit, v, maj, min);
+
ifp->if_softc = sc;
ifp->if_unit = sc->wi_unit;
ifp->if_name = "wi";
***************
*** 506,511 ****
--- 515,521 ----
sc->wi_create_ibss = WI_DEFAULT_CREATE_IBSS;
sc->wi_pm_enabled = WI_DEFAULT_PM_ENABLED;
sc->wi_max_sleep = WI_DEFAULT_MAX_SLEEP;
+ sc->wi_monitor = WI_DEFAULT_MONITOR;
/*
* Read the default channel from the NIC. This may vary
***************
*** 534,539 ****
--- 544,553 ----
bzero((char *)&sc->wi_stats, sizeof(sc->wi_stats));
+ bzero((char *)&sc->wi_aps, sizeof(sc->wi_aps));
+ sc->wi_scanning=0;
+ sc->wi_naps=0;
+
wi_init(sc);
wi_stop(sc);
***************
*** 565,570 ****
--- 579,585 ----
*/
ether_ifattach(ifp, ETHER_BPF_SUPPORTED);
callout_handle_init(&sc->wi_stat_ch);
+ callout_handle_init(&sc->wi_scan_ch);
return(0);
}
***************
*** 577,582 ****
--- 592,598 ----
struct wi_frame rx_frame;
struct mbuf *m;
int id;
+ int hdrlen,hdroff,datalen;
ifp = &sc->arpcom.ac_if;
***************
*** 593,598 ****
--- 609,743 ----
return;
}
+ /* If monitoring packet came in... */
+ if((rx_frame.wi_status&WI_STAT_MAC_PORT)==WI_STAT_MAC_PORT)
+ {
+ /* Depending on the monitoring mode... */
+ switch(sc->wi_monitor&WI_MONITOR_HTYPE)
+ {
+ case WI_MONITOR_WAVELAN:
+ /* Passing whole WaveLAN header */
+ hdroff = 0;
+ hdrlen = sizeof(struct wi_80211_hdr) + WI_802_11_OFFSET_HDR;
+ break;
+ case WI_MONITOR_80211:
+ /* Passing 802.11 header */
+ hdroff = WI_802_11_OFFSET_HDR;
+ hdrlen = sizeof(struct wi_80211_hdr);
+ break;
+ case WI_MONITOR_ETHER:
+ /* Faking Ethernet header */
+ hdroff = -1;
+ hdrlen = sizeof(struct ether_header);
+ break;
+ default:
+ return;
+ }
+
+ /* Depending on the packet type... */
+ switch(rx_frame.wi_frame_ctl&WI_FCTL_FTYPE)
+ {
+ case WI_FTYPE_MGMT:
+ if((rx_frame.wi_frame_ctl&WI_FCTL_STYPE)==WI_STYPE_MGMT_BEACON)
+ { if(!(sc->wi_monitor&WI_MONITOR_BEACONS)) return; }
+ else
+ { if(!(sc->wi_monitor&WI_MONITOR_MGMT)) return; }
+ datalen = rx_frame.wi_dat_len;
+ hdrlen -= 6;
+ break;
+ case WI_FTYPE_CTL:
+ if(!(sc->wi_monitor&WI_MONITOR_CTRL)) return;
+ datalen = 0;
+ switch(rx_frame.wi_frame_ctl&WI_FCTL_STYPE)
+ {
+ case WI_STYPE_CTL_ACK:
+ case WI_STYPE_CTL_CTS:
+ hdrlen -= 20;
+ break;
+ default:
+ hdrlen -= 14;
+ break;
+ }
+ break;
+ case WI_FTYPE_DATA:
+ if(!(sc->wi_monitor&WI_MONITOR_DATA)) return;
+ datalen = rx_frame.wi_dat_len;
+ break;
+ default:
+ return;
+ }
+
+ /* Check for mbuf overflow */
+ if(hdrlen+datalen>MCLBYTES)
+ {
+ device_printf
+ (
+ sc->dev,
+ "oversized packet received (wi_dat_len=%d, wi_frame_ctl=0x%04x)\n",
+ rx_frame.wi_dat_len,
+ rx_frame.wi_frame_ctl
+ );
+ ifp->if_ierrors++;
+ return;
+ }
+
+ MGETHDR(m,M_DONTWAIT,MT_DATA);
+ if(m==NULL)
+ {
+ ifp->if_ierrors++;
+ return;
+ }
+
+ MCLGET(m,M_DONTWAIT);
+ if(!(m->m_flags&M_EXT))
+ {
+ m_freem(m);
+ ifp->if_ierrors++;
+ return;
+ }
+
+ /* Set header/packet lengths and interface */
+ eh = mtod(m, struct ether_header *);
+ m->m_pkthdr.rcvif = ifp;
+ m->m_pkthdr.len = m->m_len = hdrlen + datalen;
+
+ /* If real header requested, copy it */
+ if(hdroff>=0)
+ bcopy((char *)&rx_frame+hdroff,mtod(m,caddr_t),hdrlen);
+ else
+ {
+ /* Fake Ethernet header */
+ eh->ether_type = ETHERTYPE_LOOPBACK;
+ bcopy((char *)&rx_frame.wi_addr1,(char *)&eh->ether_dhost,ETHER_ADDR_LEN);
+ bcopy((char *)&rx_frame.wi_addr2,(char *)&eh->ether_shost,ETHER_ADDR_LEN);
+ /* We now have a header */
+ hdrlen = sizeof(struct ether_header);
+ }
+
+ /* Read data, if present */
+ if(datalen)
+ if(wi_read_data(sc,id,WI_802_11_OFFSET_RAW,mtod(m,caddr_t)+hdrlen,datalen))
+ {
+ m_freem(m);
+ ifp->if_ierrors++;
+ return;
+ }
+
+ #ifdef WICACHE
+ if(hdroff<0) wi_cache_store(sc,eh,m,rx_frame.wi_q_info);
+ #endif
+
+ /* One more packet received */
+ ifp->if_ipackets++;
+
+ /* Feed packet to BPF */
+ if(ifp->if_bpf) bpf_mtap(ifp,m);
+
+ /* Done logging */
+ m_freem(m);
+ return;
+ }
+
MGETHDR(m, M_DONTWAIT, MT_DATA);
if (m == NULL) {
ifp->if_ierrors++;
***************
*** 610,616 ****
if (rx_frame.wi_status == WI_STAT_1042 ||
rx_frame.wi_status == WI_STAT_TUNNEL ||
! rx_frame.wi_status == WI_STAT_WMP_MSG) {
if((rx_frame.wi_dat_len + WI_SNAPHDR_LEN) > MCLBYTES) {
device_printf(sc->dev, "oversized packet received "
"(wi_dat_len=%d, wi_status=0x%x)\n",
--- 755,762 ----
if (rx_frame.wi_status == WI_STAT_1042 ||
rx_frame.wi_status == WI_STAT_TUNNEL ||
! rx_frame.wi_status == WI_STAT_WMP_MSG ||
! ((rx_frame.wi_status & WI_STAT_MAC_PORT) == WI_STAT_MAC_PORT)) {
if((rx_frame.wi_dat_len + WI_SNAPHDR_LEN) > MCLBYTES) {
device_printf(sc->dev, "oversized packet received "
"(wi_dat_len=%d, wi_status=0x%x)\n",
***************
*** 719,732 ****
return;
}
void wi_update_stats(sc)
struct wi_softc *sc;
{
struct wi_ltv_gen gen;
u_int16_t id;
struct ifnet *ifp;
u_int32_t *ptr;
! int len, i;
u_int16_t t;
ifp = &sc->arpcom.ac_if;
--- 865,922 ----
return;
}
+ void wi_wait_scan(xsc)
+ void *xsc;
+ {
+ struct wi_softc *sc;
+ struct ifnet *ifp;
+ int rc;
+
+ sc = xsc;
+ ifp = &sc->arpcom.ac_if;
+
+ /* If not scanning, ignore */
+ if (!sc->wi_scanning)
+ return;
+
+ /* If transmitting... wait for later to make INQUIRE
+ */
+ if (ifp->if_flags & IFF_OACTIVE) {
+ sc->wi_scan_ch = timeout(wi_wait_scan, sc, hz*1);
+ return;
+ }
+
+ /* try INQUIRE -- this will cause info interrupt
+ */
+ rc = wi_cmd(sc, WI_CMD_INQUIRE, WI_INFO_SCAN_RESULTS);
+
+ /* If not ready, call this function later
+ */
+ if (rc == ETIMEDOUT) {
+ sc->wi_scan_ch = timeout(wi_wait_scan, sc, hz*1);
+ }
+ return;
+ }
+
+ /*
+ * copy hw stats structure to softc clone of it
+ *
+ * important side effect: BSD if collisions are updated
+ * because of this, therefore this routine is called once
+ * a minute.
+ *
+ * It is also printed out via wicontrol -i wi0 -o
+ */
void wi_update_stats(sc)
struct wi_softc *sc;
{
struct wi_ltv_gen gen;
+ struct wi_scan_data_p2 ap2; /* prism2 output */
+ struct wi_scan_data ap; /* lucent output */
u_int16_t id;
struct ifnet *ifp;
u_int32_t *ptr;
! int len, i, j;
u_int16_t t;
ifp = &sc->arpcom.ac_if;
***************
*** 735,761 ****
wi_read_data(sc, id, 0, (char *)&gen, 4);
! if (gen.wi_type != WI_INFO_COUNTERS)
! return;
! len = (gen.wi_len - 1 < sizeof(sc->wi_stats) / 4) ?
! gen.wi_len - 1 : sizeof(sc->wi_stats) / 4;
! ptr = (u_int32_t *)&sc->wi_stats;
! for (i = 0; i < len - 1; i++) {
! t = CSR_READ_2(sc, WI_DATA1);
#ifdef WI_HERMES_STATS_WAR
! if (t > 0xF000)
! t = ~t & 0xFFFF;
#endif
! ptr[i] += t;
! }
!
! ifp->if_collisions = sc->wi_stats.wi_tx_single_retries +
! sc->wi_stats.wi_tx_multi_retries +
! sc->wi_stats.wi_tx_retry_limit;
! return;
}
static void wi_intr(xsc)
--- 925,1019 ----
wi_read_data(sc, id, 0, (char *)&gen, 4);
! switch(gen.wi_type)
! {
! case WI_INFO_SCAN_RESULTS:
! /* lucent entries are shorter than prism2
! */
! if(gen.wi_len<3)
! break;
! if (!sc->wi_prism2) {
! len = 2*(gen.wi_len)/sizeof(ap);
! len = len>MAXAPINFO? MAXAPINFO:len;
! sc->wi_naps = len;
! for(i=0;i<len;i++)
! {
! for(j=0;j<sizeof(ap)/2;j++)
! ((u_int16_t *)&ap)[j] = CSR_READ_2(sc, WI_DATA1);
! bcopy(ap.wi_bssid,sc->wi_aps[i].bssid,6);
! sc->wi_aps[i].channel = ap.wi_channel;
! sc->wi_aps[i].signal = ap.wi_signal-149;
! sc->wi_aps[i].noise = ap.wi_noise-149;
! sc->wi_aps[i].quality = sc->wi_aps[i].signal-sc->wi_aps[i].noise;
! sc->wi_aps[i].capinfo = ap.wi_capinfo;
! sc->wi_aps[i].interval = ap.wi_interval;
! /* prevent disasters
! */
! if (ap.wi_namelen > 32)
! ap.wi_namelen = 32;
! sc->wi_aps[i].namelen = ap.wi_namelen;
! bcopy(ap.wi_name, sc->wi_aps[i].name,
! ap.wi_namelen);
! }
! sc->wi_scanning = 0;
! break;
! }
! /* prism2
! */
! /* Compute number of AP entries
! * Note: there is some sort of pre-header that
! * is being skipped
! */
! len = 2*(gen.wi_len-3)/sizeof(ap2);
! len = len>MAXAPINFO? MAXAPINFO:len;
! sc->wi_naps = len;
! /* Read and ignore the first word */
! t = CSR_READ_2(sc, WI_DATA1);
! /* Read the rest */
! for(i=0;i<len;i++)
! {
! for(j=0;j<sizeof(ap2)/2;j++)
! ((u_int16_t *)&ap2)[j] = CSR_READ_2(sc, WI_DATA1);
! bcopy(ap2.wi_bssid,sc->wi_aps[i].bssid,6);
! sc->wi_aps[i].channel = ap2.wi_channel1;
! sc->wi_aps[i].signal = ap2.wi_signal-149;
! sc->wi_aps[i].noise = ap2.wi_noise-149;
! sc->wi_aps[i].quality = sc->wi_aps[i].signal-sc->wi_aps[i].noise;
! sc->wi_aps[i].capinfo = ap2.wi_capinfo;
! sc->wi_aps[i].interval = ap2.wi_interval;
! /* prevent disasters
! */
! if (ap2.wi_namelen > 32)
! ap2.wi_namelen = 32;
! sc->wi_aps[i].namelen = ap2.wi_namelen;
! bcopy(ap2.wi_name, sc->wi_aps[i].name,
! ap2.wi_namelen);
! }
! /* Done scanning
! */
! sc->wi_scanning = 0;
! break;
!
! case WI_INFO_COUNTERS:
! len = (gen.wi_len - 1 < sizeof(sc->wi_stats) / 4) ?
! gen.wi_len - 1 : sizeof(sc->wi_stats) / 4;
! ptr = (u_int32_t *)&sc->wi_stats;
! for (i = 0; i < len - 1; i++) {
! t = CSR_READ_2(sc, WI_DATA1);
#ifdef WI_HERMES_STATS_WAR
! if (t > 0xF000)
! t = ~t & 0xFFFF;
#endif
! ptr[i] += t;
! }
! ifp->if_collisions = sc->wi_stats.wi_tx_single_retries
! + sc->wi_stats.wi_tx_multi_retries
! + sc->wi_stats.wi_tx_retry_limit;
! break;
! }
}
static void wi_intr(xsc)
***************
*** 1402,1410 ****
--- 1660,1688 ----
if (wreq.wi_type == WI_RID_DEFLT_CRYPT_KEYS && suser(p))
break;
if (wreq.wi_type == WI_RID_IFACE_STATS) {
+ /* call update routine to make sure data
+ * is as up to date as possible
+ */
+ wi_update_stats(sc);
bcopy((char *)&sc->wi_stats, (char *)&wreq.wi_val,
sizeof(sc->wi_stats));
wreq.wi_len = (sizeof(sc->wi_stats) / 2) + 1;
+ /* copyout AP info
+ */
+ } else if (wreq.wi_type == WI_RID_READ_APS) {
+ if (sc->wi_scanning)
+ {
+ error = EINVAL;
+ break;
+ }
+ else
+ {
+ len = sc->wi_naps*sizeof(struct wi_apinfo);
+ len = len>WI_MAX_DATALEN? WI_MAX_DATALEN:len;
+ len = len/sizeof(struct wi_apinfo);
+ bcopy((char *)&len, (char *)&wreq.wi_val, sizeof(len));
+ bcopy((char *)&sc->wi_aps, (char *)&wreq.wi_val+sizeof(len), len*sizeof(struct wi_apinfo));
+ }
} else if (wreq.wi_type == WI_RID_DEFLT_CRYPT_KEYS) {
bcopy((char *)&sc->wi_keys, (char *)&wreq,
sizeof(struct wi_ltv_keys));
***************
*** 1444,1449 ****
--- 1722,1762 ----
} else if (wreq.wi_type == WI_RID_MGMT_XMIT) {
error = wi_mgmt_xmit(sc, (caddr_t)&wreq.wi_val,
wreq.wi_len);
+ } else if (wreq.wi_type == WI_RID_SCAN_APS) {
+ if (wreq.wi_len != 4)
+ {
+ error = EINVAL;
+ break;
+ }
+ if (!sc->wi_scanning)
+ {
+ if (sc->wi_prism2) {
+ wreq.wi_type = WI_RID_SCAN_REQUEST;
+ error = wi_write_record(sc, (struct wi_ltv_gen *)&wreq);
+ }
+ if(!error)
+ {
+ sc->wi_scanning = 1;
+ sc->wi_scan_ch = timeout(wi_wait_scan, sc, hz*1);
+ }
+ }
+ } else if (wreq.wi_type == WI_RID_MONITOR_MODE) {
+ sc->wi_monitor = wreq.wi_val[0];
+ wi_init(sc);
+ switch(sc->wi_monitor&WI_MONITOR_HTYPE)
+ {
+ case WI_MONITOR_WAVELAN:
+ bpfattach(ifp,DLT_WAVELAN_HEADER,sizeof(struct wi_frame));
+ break;
+ case WI_MONITOR_80211:
+ bpfattach(ifp,DLT_IEEE802_11,sizeof(struct wi_80211_hdr));
+ break;
+ case WI_MONITOR_ETHER:
+ case WI_MONITOR_OFF:
+ default:
+ bpfattach(ifp,DLT_EN10MB,sizeof(struct wi_80211_hdr));
+ break;
+ }
} else {
error = wi_write_record(sc, (struct wi_ltv_gen *)&wreq);
if (!error)
***************
*** 1742,1747 ****
--- 2055,2076 ----
/* Enable desired port */
wi_cmd(sc, WI_CMD_ENABLE|sc->wi_portnum, 0);
+ /* Turn monitoring on/off */
+ if(sc->wi_monitor)
+ {
+ if(wi_cmd(sc,WI_CMD_TEST|WI_TEST_MONITOR,0)) sc->wi_monitor=0;
+ }
+ else
+ {
+ wi_cmd(sc,WI_CMD_TEST|WI_TEST_STOP,0);
+ }
+
+ /* scanning variable is modal, therefore reinit to OFF, in
+ * case it was on.
+ */
+ sc->wi_scanning=0;
+ sc->wi_naps=0;
+
if (wi_alloc_nicmem(sc, ETHER_MAX_LEN + sizeof(struct wi_frame) + 8, &id))
device_printf(sc->dev, "tx buffer allocation failed\n");
sc->wi_tx_data_id = id;
***************
*** 1913,1918 ****
--- 2242,2248 ----
}
untimeout(wi_inquire, sc, sc->wi_stat_ch);
+ untimeout(wi_wait_scan, sc, sc->wi_scan_ch);
ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE);
***************
*** 1998,2003 ****
--- 2328,2360 ----
return;
}
+
+ /* borrowed from linux wvlan driver.
+ * get version, firmware info. There is more info
+ * but don't know what it means.
+ * data[1] is vendor, 2 & 3 are firmware # in major/minor order.
+ * lucent is vendor 1, 2 and 6 are prism apparently.
+ */
+
+ static void wi_get_firmware( struct wi_softc *sc, u_int16_t *v,
+ u_int16_t *maj, u_int16_t *min)
+ {
+ struct wi_ltv_staid staid;
+ int rc;
+
+ staid.wi_len = 32;
+ staid.wi_type = WI_RID_STAID;
+ rc = wi_read_record(sc, (struct wi_ltv_gen *)&staid);
+ /*
+ if (rc < 0) {
+ printf("rc %d\n", rc);
+ }
+ */
+ *v = staid.wi_data[1]; /* hardware type */
+ *maj = staid.wi_data[2]; /* firmware major */
+ *min = staid.wi_data[3]; /* firmware minor */
+ }
+
#ifdef WICACHE
/* wavelan signal strength cache code.