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 >
Text File  |  2002-01-17  |  16KB  |  594 lines

  1. *** ../wavelan.orig/if_wi.c    Thu Jan 17 11:21:23 2002
  2. --- if_wi.c    Thu Jan 17 13:47:50 2002
  3. ***************
  4. *** 145,150 ****
  5. --- 145,151 ----
  6.   static int wi_seek        __P((struct wi_softc *, int, int, int));
  7.   static int wi_alloc_nicmem    __P((struct wi_softc *, int, int *));
  8.   static void wi_inquire        __P((void *));
  9. + static void wi_wait_scan    __P((void *));
  10.   static void wi_setdef        __P((struct wi_softc *, struct wi_req *));
  11.   static int wi_mgmt_xmit        __P((struct wi_softc *, caddr_t, int));
  12.   
  13. ***************
  14. *** 166,171 ****
  15. --- 167,175 ----
  16.   
  17.   static int wi_alloc        __P((device_t, int));
  18.   static void wi_free        __P((device_t));
  19. + static void wi_get_firmware     __P((struct wi_softc *, u_int16_t *, u_int16_t *,
  20. +  u_int16_t *));
  21.   
  22.   static int wi_get_cur_ssid    __P((struct wi_softc *, char *, int *));
  23.   static int wi_media_change    __P((struct ifnet *));
  24. ***************
  25. *** 436,441 ****
  26. --- 440,446 ----
  27.       struct wi_ltv_gen    gen;
  28.       struct ifnet        *ifp;
  29.       int            error;
  30. +      u_int16_t               v, maj, min;
  31.   
  32.       sc = device_get_softc(dev);
  33.       ifp = &sc->arpcom.ac_if;
  34. ***************
  35. *** 472,477 ****
  36. --- 477,486 ----
  37.       device_printf(dev, "Ethernet address: %6D\n",
  38.           sc->arpcom.ac_enaddr, ":");
  39.   
  40. +         wi_get_firmware( sc, &v, &maj, &min);
  41. +         printf("wi%d: (hw type=%d, firmware=0x%02x:%02x)\n",
  42. +             sc->wi_unit, v, maj, min);
  43.       ifp->if_softc = sc;
  44.       ifp->if_unit = sc->wi_unit;
  45.       ifp->if_name = "wi";
  46. ***************
  47. *** 506,511 ****
  48. --- 515,521 ----
  49.       sc->wi_create_ibss = WI_DEFAULT_CREATE_IBSS;
  50.       sc->wi_pm_enabled = WI_DEFAULT_PM_ENABLED;
  51.       sc->wi_max_sleep = WI_DEFAULT_MAX_SLEEP;
  52. +     sc->wi_monitor = WI_DEFAULT_MONITOR;
  53.   
  54.       /*
  55.        * Read the default channel from the NIC. This may vary
  56. ***************
  57. *** 534,539 ****
  58. --- 544,553 ----
  59.   
  60.       bzero((char *)&sc->wi_stats, sizeof(sc->wi_stats));
  61.   
  62. +     bzero((char *)&sc->wi_aps, sizeof(sc->wi_aps));
  63. +     sc->wi_scanning=0;
  64. +     sc->wi_naps=0;
  65.       wi_init(sc);
  66.       wi_stop(sc);
  67.   
  68. ***************
  69. *** 565,570 ****
  70. --- 579,585 ----
  71.        */
  72.       ether_ifattach(ifp, ETHER_BPF_SUPPORTED);
  73.       callout_handle_init(&sc->wi_stat_ch);
  74. +         callout_handle_init(&sc->wi_scan_ch);
  75.   
  76.       return(0);
  77.   }
  78. ***************
  79. *** 577,582 ****
  80. --- 592,598 ----
  81.       struct wi_frame        rx_frame;
  82.       struct mbuf        *m;
  83.       int            id;
  84. +     int            hdrlen,hdroff,datalen;
  85.   
  86.       ifp = &sc->arpcom.ac_if;
  87.   
  88. ***************
  89. *** 593,598 ****
  90. --- 609,743 ----
  91.           return;
  92.       }
  93.   
  94. +     /* If monitoring packet came in... */
  95. +     if((rx_frame.wi_status&WI_STAT_MAC_PORT)==WI_STAT_MAC_PORT)
  96. +     {
  97. +         /* Depending on the monitoring mode... */
  98. +         switch(sc->wi_monitor&WI_MONITOR_HTYPE)
  99. +         {
  100. +             case WI_MONITOR_WAVELAN:
  101. +                 /* Passing whole WaveLAN header */
  102. +                 hdroff = 0;
  103. +                 hdrlen = sizeof(struct wi_80211_hdr) + WI_802_11_OFFSET_HDR;
  104. +                 break;
  105. +             case WI_MONITOR_80211:
  106. +                 /* Passing 802.11 header */
  107. +                 hdroff = WI_802_11_OFFSET_HDR;
  108. +                 hdrlen = sizeof(struct wi_80211_hdr);
  109. +                 break;
  110. +             case WI_MONITOR_ETHER:
  111. +                 /* Faking Ethernet header */
  112. +                 hdroff = -1;
  113. +                 hdrlen = sizeof(struct ether_header);
  114. +                 break;
  115. +             default:
  116. +                 return;
  117. +         }
  118. +         /* Depending on the packet type... */
  119. +         switch(rx_frame.wi_frame_ctl&WI_FCTL_FTYPE)
  120. +         {
  121. +             case WI_FTYPE_MGMT:
  122. +                 if((rx_frame.wi_frame_ctl&WI_FCTL_STYPE)==WI_STYPE_MGMT_BEACON)
  123. +                 { if(!(sc->wi_monitor&WI_MONITOR_BEACONS)) return; }
  124. +                 else
  125. +                 { if(!(sc->wi_monitor&WI_MONITOR_MGMT)) return; }
  126. +                 datalen = rx_frame.wi_dat_len;
  127. +                 hdrlen -= 6;
  128. +                 break;
  129. +             case WI_FTYPE_CTL:
  130. +                 if(!(sc->wi_monitor&WI_MONITOR_CTRL)) return;
  131. +                 datalen = 0;
  132. +                 switch(rx_frame.wi_frame_ctl&WI_FCTL_STYPE)
  133. +                 {
  134. +                     case WI_STYPE_CTL_ACK:
  135. +                     case WI_STYPE_CTL_CTS:
  136. +                         hdrlen -= 20;
  137. +                         break;
  138. +                     default:
  139. +                         hdrlen -= 14;
  140. +                         break;
  141. +                 }
  142. +                 break;
  143. +             case WI_FTYPE_DATA:
  144. +                 if(!(sc->wi_monitor&WI_MONITOR_DATA)) return;
  145. +                 datalen = rx_frame.wi_dat_len;
  146. +                 break;
  147. +             default:
  148. +                 return;
  149. +         }
  150. +         /* Check for mbuf overflow */
  151. +         if(hdrlen+datalen>MCLBYTES)
  152. +         {
  153. +             device_printf
  154. +             (
  155. +                 sc->dev,
  156. +                 "oversized packet received (wi_dat_len=%d, wi_frame_ctl=0x%04x)\n",
  157. +                 rx_frame.wi_dat_len,
  158. +                 rx_frame.wi_frame_ctl
  159. +             );
  160. +             ifp->if_ierrors++;
  161. +             return;
  162. +         }
  163. +         MGETHDR(m,M_DONTWAIT,MT_DATA);
  164. +         if(m==NULL)
  165. +         {
  166. +             ifp->if_ierrors++;
  167. +             return;
  168. +         }
  169. +         MCLGET(m,M_DONTWAIT);
  170. +         if(!(m->m_flags&M_EXT))
  171. +         {
  172. +             m_freem(m);
  173. +             ifp->if_ierrors++;
  174. +             return;
  175. +         }
  176. +         /* Set header/packet lengths and interface */
  177. +         eh = mtod(m, struct ether_header *);
  178. +         m->m_pkthdr.rcvif = ifp;
  179. +         m->m_pkthdr.len   = m->m_len = hdrlen + datalen;
  180. +         /* If real header requested, copy it */
  181. +         if(hdroff>=0)
  182. +             bcopy((char *)&rx_frame+hdroff,mtod(m,caddr_t),hdrlen);
  183. +         else
  184. +         {
  185. +             /* Fake Ethernet header */
  186. +             eh->ether_type = ETHERTYPE_LOOPBACK;
  187. +             bcopy((char *)&rx_frame.wi_addr1,(char *)&eh->ether_dhost,ETHER_ADDR_LEN);
  188. +             bcopy((char *)&rx_frame.wi_addr2,(char *)&eh->ether_shost,ETHER_ADDR_LEN);
  189. +             /* We now have a header */
  190. +             hdrlen = sizeof(struct ether_header);
  191. +         }
  192. +         /* Read data, if present */
  193. +         if(datalen)
  194. +             if(wi_read_data(sc,id,WI_802_11_OFFSET_RAW,mtod(m,caddr_t)+hdrlen,datalen))
  195. +             {
  196. +                 m_freem(m);
  197. +                 ifp->if_ierrors++;
  198. +                 return;
  199. +             }
  200. + #ifdef WICACHE
  201. +         if(hdroff<0) wi_cache_store(sc,eh,m,rx_frame.wi_q_info);
  202. + #endif  
  203. +         /* One more packet received */
  204. +         ifp->if_ipackets++;
  205. +         /* Feed packet to BPF */
  206. +         if(ifp->if_bpf) bpf_mtap(ifp,m);
  207. +         /* Done logging */
  208. +         m_freem(m);
  209. +         return;
  210. +     }
  211.       MGETHDR(m, M_DONTWAIT, MT_DATA);
  212.       if (m == NULL) {
  213.           ifp->if_ierrors++;
  214. ***************
  215. *** 610,616 ****
  216.   
  217.       if (rx_frame.wi_status == WI_STAT_1042 ||
  218.           rx_frame.wi_status == WI_STAT_TUNNEL ||
  219. !         rx_frame.wi_status == WI_STAT_WMP_MSG) {
  220.           if((rx_frame.wi_dat_len + WI_SNAPHDR_LEN) > MCLBYTES) {
  221.               device_printf(sc->dev, "oversized packet received "
  222.                   "(wi_dat_len=%d, wi_status=0x%x)\n",
  223. --- 755,762 ----
  224.   
  225.       if (rx_frame.wi_status == WI_STAT_1042 ||
  226.           rx_frame.wi_status == WI_STAT_TUNNEL ||
  227. !         rx_frame.wi_status == WI_STAT_WMP_MSG ||
  228. !         ((rx_frame.wi_status & WI_STAT_MAC_PORT) == WI_STAT_MAC_PORT)) {
  229.           if((rx_frame.wi_dat_len + WI_SNAPHDR_LEN) > MCLBYTES) {
  230.               device_printf(sc->dev, "oversized packet received "
  231.                   "(wi_dat_len=%d, wi_status=0x%x)\n",
  232. ***************
  233. *** 719,732 ****
  234.       return;
  235.   }
  236.   
  237.   void wi_update_stats(sc)
  238.       struct wi_softc        *sc;
  239.   {
  240.       struct wi_ltv_gen    gen;
  241.       u_int16_t        id;
  242.       struct ifnet        *ifp;
  243.       u_int32_t        *ptr;
  244. !     int            len, i;
  245.       u_int16_t        t;
  246.   
  247.       ifp = &sc->arpcom.ac_if;
  248. --- 865,922 ----
  249.       return;
  250.   }
  251.   
  252. + void wi_wait_scan(xsc)
  253. +      void            *xsc;
  254. + {
  255. +      struct wi_softc        *sc;
  256. +      struct ifnet        *ifp;
  257. +     int rc;
  258. +  
  259. +      sc = xsc;
  260. +      ifp = &sc->arpcom.ac_if;
  261. +  
  262. +      /* If not scanning, ignore */
  263. +      if (!sc->wi_scanning)
  264. +          return;
  265. +      /* If transmitting... wait for later to make INQUIRE
  266. +     */
  267. +      if (ifp->if_flags & IFF_OACTIVE) {
  268. +          sc->wi_scan_ch = timeout(wi_wait_scan, sc, hz*1);
  269. +         return;
  270. +     }
  271. +  
  272. +     /* try INQUIRE -- this will cause info interrupt 
  273. +     */
  274. +      rc = wi_cmd(sc, WI_CMD_INQUIRE, WI_INFO_SCAN_RESULTS);
  275. +  
  276. +      /* If not ready, call this function later
  277. +     */
  278. +     if (rc == ETIMEDOUT) {
  279. +          sc->wi_scan_ch = timeout(wi_wait_scan, sc, hz*1);
  280. +     }
  281. +      return;
  282. + }
  283. + /*
  284. +  * copy hw stats structure to softc clone of it
  285. +  *
  286. +  * important side effect: BSD if collisions are updated
  287. +  * because of this, therefore this routine is called once
  288. +  * a minute.  
  289. +  *
  290. +  * It is also printed out via wicontrol -i wi0 -o
  291. +  */
  292.   void wi_update_stats(sc)
  293.       struct wi_softc        *sc;
  294.   {
  295.       struct wi_ltv_gen    gen;
  296. +     struct wi_scan_data_p2  ap2;  /* prism2 output */
  297. +     struct wi_scan_data     ap;   /* lucent output */
  298.       u_int16_t        id;
  299.       struct ifnet        *ifp;
  300.       u_int32_t        *ptr;
  301. !     int            len, i, j;
  302.       u_int16_t        t;
  303.   
  304.       ifp = &sc->arpcom.ac_if;
  305. ***************
  306. *** 735,761 ****
  307.   
  308.       wi_read_data(sc, id, 0, (char *)&gen, 4);
  309.   
  310. !     if (gen.wi_type != WI_INFO_COUNTERS)
  311. !         return;
  312.   
  313. !     len = (gen.wi_len - 1 < sizeof(sc->wi_stats) / 4) ?
  314. !         gen.wi_len - 1 : sizeof(sc->wi_stats) / 4;
  315. !     ptr = (u_int32_t *)&sc->wi_stats;
  316.   
  317. !     for (i = 0; i < len - 1; i++) {
  318. !         t = CSR_READ_2(sc, WI_DATA1);
  319.   #ifdef WI_HERMES_STATS_WAR
  320. !         if (t > 0xF000)
  321. !             t = ~t & 0xFFFF;
  322.   #endif
  323. !         ptr[i] += t;
  324. !     }
  325. !     ifp->if_collisions = sc->wi_stats.wi_tx_single_retries +
  326. !         sc->wi_stats.wi_tx_multi_retries +
  327. !         sc->wi_stats.wi_tx_retry_limit;
  328.   
  329. !     return;
  330.   }
  331.   
  332.   static void wi_intr(xsc)
  333. --- 925,1019 ----
  334.   
  335.       wi_read_data(sc, id, 0, (char *)&gen, 4);
  336.   
  337. !     switch(gen.wi_type)
  338. !     {
  339. !         case WI_INFO_SCAN_RESULTS:
  340. !             /* lucent entries are shorter than prism2 
  341. !             */
  342. !             if(gen.wi_len<3)
  343. !                 break;
  344. !             if (!sc->wi_prism2) {
  345. !                             len = 2*(gen.wi_len)/sizeof(ap);
  346. !                 len = len>MAXAPINFO? MAXAPINFO:len;
  347. !                 sc->wi_naps = len;
  348. !                 for(i=0;i<len;i++)
  349. !                 {
  350. !                     for(j=0;j<sizeof(ap)/2;j++)
  351. !                         ((u_int16_t *)&ap)[j] = CSR_READ_2(sc, WI_DATA1);
  352. !                     bcopy(ap.wi_bssid,sc->wi_aps[i].bssid,6);
  353. !                     sc->wi_aps[i].channel = ap.wi_channel;
  354. !                     sc->wi_aps[i].signal  = ap.wi_signal-149;
  355. !                     sc->wi_aps[i].noise   = ap.wi_noise-149;
  356. !                     sc->wi_aps[i].quality = sc->wi_aps[i].signal-sc->wi_aps[i].noise;
  357. !                     sc->wi_aps[i].capinfo = ap.wi_capinfo;
  358. !                     sc->wi_aps[i].interval = ap.wi_interval;
  359. !                     /* prevent disasters
  360. !                     */
  361. !                     if (ap.wi_namelen > 32)
  362. !                         ap.wi_namelen = 32;
  363. !                     sc->wi_aps[i].namelen = ap.wi_namelen;
  364. !                     bcopy(ap.wi_name, sc->wi_aps[i].name,
  365. !                         ap.wi_namelen);
  366. !                 }
  367. !                 sc->wi_scanning = 0;
  368. !                 break;
  369. !             }
  370. !             /* prism2 
  371. !             */
  372. !             /* Compute number of AP entries 
  373. !              * Note: there is some sort of pre-header that
  374. !              * is being skipped
  375. !             */
  376. !                         len = 2*(gen.wi_len-3)/sizeof(ap2);
  377. !             len = len>MAXAPINFO? MAXAPINFO:len;
  378. !             sc->wi_naps = len;
  379. !             /* Read and ignore the first word */
  380. !             t = CSR_READ_2(sc, WI_DATA1);
  381. !             /* Read the rest */
  382. !             for(i=0;i<len;i++)
  383. !             {
  384. !                 for(j=0;j<sizeof(ap2)/2;j++)
  385. !                     ((u_int16_t *)&ap2)[j] = CSR_READ_2(sc, WI_DATA1);
  386. !                 bcopy(ap2.wi_bssid,sc->wi_aps[i].bssid,6);
  387. !                 sc->wi_aps[i].channel = ap2.wi_channel1;
  388. !                 sc->wi_aps[i].signal  = ap2.wi_signal-149;
  389. !                 sc->wi_aps[i].noise   = ap2.wi_noise-149;
  390. !                 sc->wi_aps[i].quality = sc->wi_aps[i].signal-sc->wi_aps[i].noise;
  391. !                 sc->wi_aps[i].capinfo = ap2.wi_capinfo;
  392. !                 sc->wi_aps[i].interval = ap2.wi_interval;
  393. !                 /* prevent disasters
  394. !                 */
  395. !                 if (ap2.wi_namelen > 32)
  396. !                     ap2.wi_namelen = 32;
  397. !                 sc->wi_aps[i].namelen = ap2.wi_namelen;
  398. !                 bcopy(ap2.wi_name, sc->wi_aps[i].name,
  399. !                         ap2.wi_namelen);
  400.   
  401. !             }
  402. !             /* Done scanning 
  403. !             */
  404. !             sc->wi_scanning = 0;
  405. !             break;
  406. !         case WI_INFO_COUNTERS:
  407. !             len = (gen.wi_len - 1 < sizeof(sc->wi_stats) / 4) ?
  408. !                 gen.wi_len - 1 : sizeof(sc->wi_stats) / 4;
  409. !             ptr = (u_int32_t *)&sc->wi_stats;
  410.   
  411. !             for (i = 0; i < len - 1; i++) {
  412. !                 t = CSR_READ_2(sc, WI_DATA1);
  413.   #ifdef WI_HERMES_STATS_WAR
  414. !                 if (t > 0xF000)
  415. !                     t = ~t & 0xFFFF;
  416.   #endif
  417. !                 ptr[i] += t;
  418. !             }
  419.   
  420. !             ifp->if_collisions = sc->wi_stats.wi_tx_single_retries
  421. !                        + sc->wi_stats.wi_tx_multi_retries
  422. !                        + sc->wi_stats.wi_tx_retry_limit;
  423. !             break;
  424. !     }
  425.   }
  426.   
  427.   static void wi_intr(xsc)
  428. ***************
  429. *** 1402,1410 ****
  430. --- 1660,1688 ----
  431.           if (wreq.wi_type == WI_RID_DEFLT_CRYPT_KEYS && suser(p))
  432.               break;
  433.           if (wreq.wi_type == WI_RID_IFACE_STATS) {
  434. +             /* call update routine to make sure data
  435. +              * is as up to date as possible
  436. +             */
  437. +             wi_update_stats(sc);
  438.               bcopy((char *)&sc->wi_stats, (char *)&wreq.wi_val,
  439.                   sizeof(sc->wi_stats));
  440.               wreq.wi_len = (sizeof(sc->wi_stats) / 2) + 1;
  441. +         /* copyout AP info
  442. +         */
  443. +         } else if (wreq.wi_type == WI_RID_READ_APS) {
  444. +             if (sc->wi_scanning)
  445. +             {
  446. +                 error = EINVAL;
  447. +                 break;
  448. +             }
  449. +             else
  450. +             {
  451. +                 len = sc->wi_naps*sizeof(struct wi_apinfo);
  452. +                 len = len>WI_MAX_DATALEN? WI_MAX_DATALEN:len;
  453. +                 len = len/sizeof(struct wi_apinfo);     
  454. +                 bcopy((char *)&len, (char *)&wreq.wi_val, sizeof(len));
  455. +                 bcopy((char *)&sc->wi_aps, (char *)&wreq.wi_val+sizeof(len), len*sizeof(struct wi_apinfo));
  456. +             }
  457.           } else if (wreq.wi_type == WI_RID_DEFLT_CRYPT_KEYS) {
  458.               bcopy((char *)&sc->wi_keys, (char *)&wreq,
  459.                   sizeof(struct wi_ltv_keys));
  460. ***************
  461. *** 1444,1449 ****
  462. --- 1722,1762 ----
  463.           } else if (wreq.wi_type == WI_RID_MGMT_XMIT) {
  464.               error = wi_mgmt_xmit(sc, (caddr_t)&wreq.wi_val,
  465.                   wreq.wi_len);
  466. +         } else if (wreq.wi_type == WI_RID_SCAN_APS) {
  467. +             if (wreq.wi_len != 4)
  468. +             {
  469. +                 error = EINVAL;
  470. +                 break;
  471. +             }
  472. +             if (!sc->wi_scanning)
  473. +             {
  474. +                 if (sc->wi_prism2) {
  475. +                     wreq.wi_type = WI_RID_SCAN_REQUEST;
  476. +                     error = wi_write_record(sc, (struct wi_ltv_gen *)&wreq);
  477. +                 }
  478. +                 if(!error)
  479. +                 {
  480. +                     sc->wi_scanning = 1;
  481. +                     sc->wi_scan_ch = timeout(wi_wait_scan, sc, hz*1);
  482. +                 }
  483. +             }
  484. +         } else if (wreq.wi_type == WI_RID_MONITOR_MODE) {
  485. +             sc->wi_monitor = wreq.wi_val[0];
  486. +             wi_init(sc);
  487. +             switch(sc->wi_monitor&WI_MONITOR_HTYPE)
  488. +             {
  489. +                 case WI_MONITOR_WAVELAN:
  490. +                     bpfattach(ifp,DLT_WAVELAN_HEADER,sizeof(struct wi_frame));
  491. +                     break;
  492. +                 case WI_MONITOR_80211:
  493. +                     bpfattach(ifp,DLT_IEEE802_11,sizeof(struct wi_80211_hdr));
  494. +                     break;
  495. +                 case WI_MONITOR_ETHER:
  496. +                 case WI_MONITOR_OFF:
  497. +                 default:
  498. +                     bpfattach(ifp,DLT_EN10MB,sizeof(struct wi_80211_hdr));
  499. +                     break;
  500. +             }
  501.           } else {
  502.               error = wi_write_record(sc, (struct wi_ltv_gen *)&wreq);
  503.               if (!error)
  504. ***************
  505. *** 1742,1747 ****
  506. --- 2055,2076 ----
  507.       /* Enable desired port */
  508.       wi_cmd(sc, WI_CMD_ENABLE|sc->wi_portnum, 0);
  509.   
  510. +     /* Turn monitoring on/off */
  511. +     if(sc->wi_monitor)
  512. +     {
  513. +         if(wi_cmd(sc,WI_CMD_TEST|WI_TEST_MONITOR,0)) sc->wi_monitor=0;
  514. +     } 
  515. +     else
  516. +     {
  517. +         wi_cmd(sc,WI_CMD_TEST|WI_TEST_STOP,0);
  518. +     }
  519. +     /*  scanning variable is modal, therefore reinit to OFF, in
  520. +     *  case it was on.
  521. +     */
  522. +     sc->wi_scanning=0;
  523. +     sc->wi_naps=0;
  524.       if (wi_alloc_nicmem(sc, ETHER_MAX_LEN + sizeof(struct wi_frame) + 8, &id))
  525.           device_printf(sc->dev, "tx buffer allocation failed\n");
  526.       sc->wi_tx_data_id = id;
  527. ***************
  528. *** 1913,1918 ****
  529. --- 2242,2248 ----
  530.       }
  531.   
  532.       untimeout(wi_inquire, sc, sc->wi_stat_ch);
  533. +     untimeout(wi_wait_scan, sc, sc->wi_scan_ch);
  534.   
  535.       ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE);
  536.   
  537. ***************
  538. *** 1998,2003 ****
  539. --- 2328,2360 ----
  540.   
  541.       return;
  542.   }
  543. + /* borrowed from linux wvlan driver.
  544. +  * get version, firmware info.  There is more info
  545. +  * but don't know what it means.
  546. +  * data[1] is vendor, 2 & 3 are firmware # in major/minor order.
  547. +  * lucent is vendor 1, 2 and 6 are prism apparently.
  548. + */      
  549. + static void wi_get_firmware( struct wi_softc *sc, u_int16_t *v,
  550. +         u_int16_t *maj, u_int16_t *min)
  551. + {
  552. +         struct wi_ltv_staid     staid;
  553. +         int rc;
  554. +         staid.wi_len = 32;
  555. +         staid.wi_type = WI_RID_STAID;
  556. +         rc = wi_read_record(sc, (struct wi_ltv_gen *)&staid);
  557. +         /*
  558. +         if (rc < 0) {
  559. +                 printf("rc %d\n", rc);
  560. +         }
  561. +         */
  562. +         *v = staid.wi_data[1];  /* hardware type */
  563. +         *maj = staid.wi_data[2];  /* firmware major */
  564. +         *min =  staid.wi_data[3];  /* firmware minor */
  565. + }
  566.   
  567.   #ifdef WICACHE
  568.   /* wavelan signal strength cache code.
  569.