xref: /inferno-os/os/ipaq1110/etherwavelan.c (revision 74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a)
1 /*
2 	Lucent Wavelan IEEE 802.11 pcmcia.
3 	There is almost no documentation for the card.
4 	the driver is done using both the FreeBSD, Linux and
5 	original Plan 9 drivers as `documentation'.
6 
7 	Has been used with the card plugged in during all up time.
8 	no cards removals/insertions yet.
9 
10 	For known BUGS see the comments below. Besides,
11 	the driver keeps interrupts disabled for just too
12 	long. When it gets robust, locks should be revisited.
13 
14 	BUGS: check endian, alignment and mem/io issues;
15 	      multicast;
16 	      receive watchdog interrupts.
17 	TODO: automatic power management;
18 	      improve locking.
19  */
20 #include "u.h"
21 #include "../port/lib.h"
22 #include "mem.h"
23 #include "dat.h"
24 #include "fns.h"
25 #include "io.h"
26 #include "../port/error.h"
27 #include "../port/netif.h"
28 #include "etherif.h"
29 
30 #define	print	iprint
31 #define DEBUG	if(1)iprint
32 
33 #define SEEKEYS 1
34 
35 typedef struct Ctlr	Ctlr;
36 typedef struct Wltv	Wltv;
37 typedef struct WFrame	WFrame;
38 typedef struct Stats	Stats;
39 typedef struct WStats	WStats;
40 typedef struct WKey	WKey;
41 
42 struct WStats
43 {
44 	ulong	ntxuframes;		// unicast frames
45 	ulong	ntxmframes;		// multicast frames
46 	ulong	ntxfrags;		// fragments
47 	ulong	ntxubytes;		// unicast bytes
48 	ulong	ntxmbytes;		// multicast bytes
49 	ulong	ntxdeferred;		// deferred transmits
50 	ulong	ntxsretries;		// single retries
51 	ulong	ntxmultiretries;	// multiple retries
52 	ulong	ntxretrylimit;
53 	ulong	ntxdiscards;
54 	ulong	nrxuframes;		// unicast frames
55 	ulong	nrxmframes;		// multicast frames
56 	ulong	nrxfrags;		// fragments
57 	ulong	nrxubytes;		// unicast bytes
58 	ulong	nrxmbytes;		// multicast bytes
59 	ulong	nrxfcserr;
60 	ulong	nrxdropnobuf;
61 	ulong	nrxdropnosa;
62 	ulong	nrxcantdecrypt;
63 	ulong	nrxmsgfrag;
64 	ulong	nrxmsgbadfrag;
65 	ulong	end;
66 };
67 
68 struct WFrame
69 {
70 	ushort	sts;
71 	ushort	rsvd0;
72 	ushort	rsvd1;
73 	ushort	qinfo;
74 	ushort	rsvd2;
75 	ushort	rsvd3;
76 	ushort	txctl;
77 	ushort	framectl;
78 	ushort	id;
79 	uchar	addr1[Eaddrlen];
80 	uchar	addr2[Eaddrlen];
81 	uchar	addr3[Eaddrlen];
82 	ushort	seqctl;
83 	uchar	addr4[Eaddrlen];
84 	ushort	dlen;
85 	uchar	dstaddr[Eaddrlen];
86 	uchar	srcaddr[Eaddrlen];
87 	ushort	len;
88 	ushort	dat[3];
89 	ushort	type;
90 };
91 
92 // Lucent's Length-Type-Value records to talk to the wavelan.
93 // most operational parameters are read/set using this.
94 enum
95 {
96 	WTyp_Stats	= 0xf100,
97 	WTyp_Ptype	= 0xfc00,
98 	WTyp_Mac	= 0xfc01,
99 	WTyp_WantName	= 0xfc02,
100 	WTyp_Chan	= 0xfc03,
101 	WTyp_NetName	= 0xfc04,
102 	WTyp_ApDens	= 0xfc06,
103 	WTyp_MaxLen	= 0xfc07,
104 	WTyp_PM		= 0xfc09,
105 	WTyp_PMWait	= 0xfc0c,
106 	WTyp_NodeName	= 0xfc0e,
107 	WTyp_Crypt	= 0xfc20,
108 	WTyp_XClear	= 0xfc22,
109 	WTyp_Tick	= 0xfce0,
110 	WTyp_RtsThres	= 0xfc83,
111 	WTyp_TxRate	= 0xfc84,
112 		WTx1Mbps	= 0x0,
113 		WTx2Mbps	= 0x1,
114 		WTxAuto		= 0x3,
115 	WTyp_Prom	= 0xfc85,
116 	WTyp_Keys	= 0xfcb0,
117 	WTyp_TxKey	= 0xfcb1,
118 	WTyp_StationID	= 0xfd20,
119 	WTyp_CurName	= 0xfd41,
120 	WTyp_BaseID	= 0xfd42,	// ID of the currently connected-to base station
121 	WTyp_CurTxRate	= 0xfd44,	// Current TX rate
122 	WTyp_HasCrypt	= 0xfd4f,
123 };
124 
125 // Controller
126 enum
127 {
128 	WDfltIRQ	= 3,		// default irq
129 	WDfltIOB	= 0x180,	// default IO base
130 
131 	WIOLen		= 0x40,		// Hermes IO length
132 
133 	WTmOut		= 65536,	// Cmd time out
134 
135 	WPTypePeerToPeer	= 0,
136 	WPTypeManaged	= 1,
137 	WPTypeWDS	= 2,
138 	WPTypeAdHoc	= 3,
139 	WDfltPType	= WPTypeManaged,
140 
141 	WDfltApDens	= 1,
142 	WDfltRtsThres	= 2347,		// == disabled
143 	WDfltTxRate	= WTxAuto,	// 2Mbps
144 
145 	WMaxLen		= 2304,
146 	WNameLen	= 32,
147 
148 	WNKeys		= 4,
149 	WKeyLen		= 14,
150 	WMinKeyLen	= 5,
151 
152 	// Wavelan hermes registers
153 	WR_Cmd		= 0x00,
154 		WCmdIni		= 0x0000,
155 		WCmdEna		= 0x0001,
156 		WCmdDis		= 0x0002,
157 		WCmdTx		= 0x000b,
158 		WCmdMalloc	= 0x000a,
159 		WCmdAskStats	= 0x0011,
160 		WCmdMsk		= 0x003f,
161 		WCmdAccRd	= 0x0021,
162 		WCmdReclaim	= 0x0100,
163 		WCmdAccWr	= 0x0121,
164 		WCmdBusy	= 0x8000,
165 	WR_Parm0	= 0x02,
166 	WR_Parm1	= 0x04,
167 	WR_Parm2	= 0x06,
168 	WR_Sts		= 0x08,
169 	WR_InfoId	= 0x10,
170 	WR_Sel0		= 0x18,
171 	WR_Sel1		= 0x1a,
172 	WR_Off0		= 0x1c,
173 	WR_Off1		= 0x1e,
174 		WBusyOff	= 0x8000,
175 		WErrOff		= 0x4000,
176 		WResSts		= 0x7f00,
177 	WR_RXId		= 0x20,
178 	WR_Alloc	= 0x22,
179 	WR_EvSts	= 0x30,
180 	WR_IntEna	= 0x32,
181 		WCmdEv		= 0x0010,
182 		WRXEv		= 0x0001,
183 		WTXEv		= 0x0002,
184 		WTxErrEv	= 0x0004,
185 		WAllocEv	= 0x0008,
186 		WInfoEv		= 0x0080,
187 		WIDropEv	= 0x2000,
188 		WTickEv		= 0x8000,
189 		WEvs		= WRXEv|WTXEv|WAllocEv|WInfoEv|WIDropEv,
190 
191 	WR_EvAck	= 0x34,
192 	WR_Data0	= 0x36,
193 	WR_Data1	= 0x38,
194 
195 	// Frame stuff
196 
197 	WF_Err		= 0x0003,
198 	WF_1042		= 0x2000,
199 	WF_Tunnel	= 0x4000,
200 	WF_WMP		= 0x6000,
201 
202 	WF_Data		= 0x0008,
203 
204 	WSnapK1		= 0xaa,
205 	WSnapK2		= 0x00,
206 	WSnapCtlr	= 0x03,
207 	WSnap0		= (WSnapK1|(WSnapK1<<8)),
208 	WSnap1		= (WSnapK2|(WSnapCtlr<<8)),
209 	WSnapHdrLen	= 6,
210 
211 	WF_802_11_Off	= 0x44,
212 	WF_802_3_Off	= 0x2e,
213 
214 };
215 
216 #define csr_outs(ctlr,r,arg)	outs((ctlr)->iob+(r),(arg))
217 #define csr_ins(ctlr,r)		ins((ctlr)->iob+(r))
218 #define csr_ack(ctlr,ev)	outs((ctlr)->iob+WR_EvAck,(ev))
219 
220 struct WKey
221 {
222 	ushort	len;
223 	char	dat[WKeyLen];
224 };
225 
226 struct Wltv
227 {
228 	ushort	len;
229 	ushort	type;
230 	union
231 	{
232 		struct {
233 			ushort	val;
234 			ushort	pad;
235 		};
236 		struct {
237 			uchar	addr[8];
238 		};
239 		struct {
240 			ushort	slen;
241 			char	s[WNameLen];
242 		};
243 		struct {
244 			char	name[WNameLen];
245 		};
246 		struct {
247 			WKey	keys[WNKeys];
248 		};
249 	};
250 };
251 
252 // What the driver thinks. Not what the card thinks.
253 struct Stats
254 {
255 	ulong	nints;
256 	ulong	nrx;
257 	ulong	ntx;
258 	ulong	ntxrq;
259 	ulong	nrxerr;
260 	ulong	ntxerr;
261 	ulong	nalloc;			// allocation (reclaim) events
262 	ulong	ninfo;
263 	ulong	nidrop;
264 	ulong	nwatchdogs;		// transmit time outs, actually
265 	int	ticks;
266 	int	tickintr;
267 	int	signal;
268 	int	noise;
269 };
270 
271 struct Ctlr
272 {
273 	Lock;
274 	Rendez	timer;
275 
276 	int	attached;
277 	int	slot;
278 	int	iob;
279 	int	ptype;
280 	int	apdensity;
281 	int	rtsthres;
282 	int	txbusy;
283 	int	txrate;
284 	int	txdid;
285 	int	txmid;
286 	int	txtmout;
287 	int	maxlen;
288 	int	chan;
289 	int	pmena;
290 	int	pmwait;
291 
292 	char	netname[WNameLen];
293 	char	wantname[WNameLen];
294 	char	nodename[WNameLen];
295 	WFrame	txf;
296 	uchar	txbuf[1536];
297 
298 	int	hascrypt;		// card has encryption
299 	int	crypt;			// encryption off/on
300 	int	txkey;			// transmit key
301 	Wltv	keys;			// default keys
302 	int	xclear;			// exclude clear packets off/on
303 
304 	Stats;
305 	WStats;
306 };
307 
308 // w_... routines do not ilock the Ctlr and should
309 // be called locked.
310 
311 static void
w_intdis(Ctlr * ctlr)312 w_intdis(Ctlr* ctlr)
313 {
314 	csr_outs(ctlr, WR_IntEna, 0);
315 	csr_ack(ctlr, 0xffff);
316 }
317 
318 static void
w_intena(Ctlr * ctlr)319 w_intena(Ctlr* ctlr)
320 {
321 	csr_outs(ctlr, WR_IntEna, WEvs);
322 }
323 
324 static int
w_cmd(Ctlr * ctlr,ushort cmd,ushort arg)325 w_cmd(Ctlr *ctlr, ushort cmd, ushort arg)
326 {
327 	int i, rc;
328 
329 	csr_outs(ctlr, WR_Parm0, arg);
330 	csr_outs(ctlr, WR_Cmd, cmd);
331 	for (i = 0; i<WTmOut; i++){
332 		rc = csr_ins(ctlr, WR_EvSts);
333 		if ( rc&WCmdEv ){
334 			rc = csr_ins(ctlr, WR_Sts);
335 			csr_ack(ctlr, WCmdEv);
336 			if ((rc&WCmdMsk) != (cmd&WCmdMsk))
337 				break;
338 			if (rc&WResSts)
339 				break;
340 			return 0;
341 		}
342 	}
343 
344 	return -1;
345 }
346 
347 static int
w_seek(Ctlr * ctlr,ushort id,ushort offset,int chan)348 w_seek(Ctlr* ctlr, ushort id, ushort offset, int chan)
349 {
350 	int i, rc;
351 	static ushort sel[] = { WR_Sel0, WR_Sel1 };
352 	static ushort off[] = { WR_Off0, WR_Off1 };
353 
354 	if (chan != 0 && chan != 1)
355 		panic("wavelan: bad chan\n");
356 	csr_outs(ctlr, sel[chan], id);
357 	csr_outs(ctlr, off[chan], offset);
358 	for (i=0; i<WTmOut; i++){
359 		rc = csr_ins(ctlr, off[chan]);
360 		if ((rc & (WBusyOff|WErrOff)) == 0)
361 			return 0;
362 	}
363 	return -1;
364 }
365 
366 static int
w_inltv(Ctlr * ctlr,Wltv * ltv)367 w_inltv(Ctlr* ctlr, Wltv* ltv)
368 {
369 	int len;
370 	ushort code;
371 
372 	if (w_cmd(ctlr, WCmdAccRd, ltv->type)){
373 		DEBUG("wavelan: access read failed\n");
374 		return -1;
375 	}
376 	if (w_seek(ctlr,ltv->type,0,1)){
377 		DEBUG("wavelan: seek failed\n");
378 		return -1;
379 	}
380 	len = csr_ins(ctlr, WR_Data1);
381 	if (len > ltv->len)
382 		return -1;
383 	ltv->len = len;
384 	if ((code=csr_ins(ctlr, WR_Data1)) != ltv->type){
385 		DEBUG("wavelan: type %x != code %x\n",ltv->type,code);
386 		return -1;
387 	}
388 	if(ltv->len > 0)
389 		inss((ctlr)->iob+(WR_Data1), &ltv->val, ltv->len-1);
390 
391 	return 0;
392 }
393 
394 static void
w_outltv(Ctlr * ctlr,Wltv * ltv)395 w_outltv(Ctlr* ctlr, Wltv* ltv)
396 {
397 	if(w_seek(ctlr,ltv->type, 0, 1))
398 		return;
399 	outss((ctlr)->iob+(WR_Data1), ltv, ltv->len+1);
400 	w_cmd(ctlr, WCmdAccWr, ltv->type);
401 }
402 
403 static void
ltv_outs(Ctlr * ctlr,int type,ushort val)404 ltv_outs(Ctlr* ctlr, int type, ushort val)
405 {
406 	Wltv ltv;
407 
408 	ltv.len = 2;
409 	ltv.type = type;
410 	ltv.val = val;
411 	w_outltv(ctlr, &ltv);
412 }
413 
414 static int
ltv_ins(Ctlr * ctlr,int type)415 ltv_ins(Ctlr* ctlr, int type)
416 {
417 	Wltv ltv;
418 
419 	ltv.len = 2;
420 	ltv.type = type;
421 	ltv.val = 0;
422 	if(w_inltv(ctlr, &ltv))
423 		return -1;
424 	return ltv.val;
425 }
426 
427 static void
ltv_outstr(Ctlr * ctlr,int type,char * val)428 ltv_outstr(Ctlr* ctlr, int type, char* val)
429 {
430 	Wltv ltv;
431 	int len;
432 
433 	len = strlen(val);
434 	if(len > sizeof(ltv.s))
435 		len = sizeof(ltv.s);
436 	memset(&ltv, 0, sizeof(ltv));
437 	ltv.len = (sizeof(ltv.type)+sizeof(ltv.slen)+sizeof(ltv.s))/2;
438 	ltv.type = type;
439 
440 //	This should be ltv.slen = len; according to Axel Belinfante
441 	ltv.slen = len;
442 
443 	strncpy(ltv.s, val, len);
444 	w_outltv(ctlr, &ltv);
445 }
446 
447 static char Unkname[] = "who knows";
448 static char Nilname[] = "card does not tell";
449 
450 static char*
ltv_inname(Ctlr * ctlr,int type)451 ltv_inname(Ctlr* ctlr, int type)
452 {
453 	static Wltv ltv;
454 	int len;
455 
456 	memset(&ltv,0,sizeof(ltv));
457 	ltv.len = WNameLen/2+2;
458 	ltv.type = type;
459 	if (w_inltv(ctlr, &ltv))
460 		return Unkname;
461 	len = ltv.slen;
462 	if(len == 0 || ltv.s[0] == 0)
463 		return Nilname;
464 	if(len >= sizeof ltv.s)
465 		len = sizeof ltv.s - 1;
466 	ltv.s[len] = '\0';
467 	return ltv.s;
468 }
469 
470 static int
w_read(Ctlr * ctlr,int type,int off,void * buf,ulong len)471 w_read(Ctlr* ctlr, int type, int off, void* buf, ulong len)
472 {
473 	if (w_seek(ctlr, type, off, 1)){
474 		DEBUG("wavelan: w_read: seek failed");
475 		return 0;
476 	}
477 	inss((ctlr)->iob+(WR_Data1), buf, len/2);
478 
479 	return len;
480 }
481 
482 static int
w_write(Ctlr * ctlr,int type,int off,void * buf,ulong len)483 w_write(Ctlr* ctlr, int type, int off, void* buf, ulong len)
484 {
485 	int tries;
486 
487 	for (tries=0; tries < WTmOut; tries++){
488 		if (w_seek(ctlr, type, off, 0)){
489 			DEBUG("wavelan: w_write: seek failed\n");
490 			return 0;
491 		}
492 
493 		outss((ctlr)->iob+(WR_Data0), buf, len/2);
494 
495 		csr_outs(ctlr, WR_Data0, 0xdead);
496 		csr_outs(ctlr, WR_Data0, 0xbeef);
497 		if (w_seek(ctlr, type, off + len, 0)){
498 			DEBUG("wavelan: write seek failed\n");
499 			return 0;
500 		}
501 		if (csr_ins(ctlr, WR_Data0) == 0xdead)
502 		if (csr_ins(ctlr, WR_Data0) == 0xbeef)
503 			return len;
504 		DEBUG("wavelan: Hermes bug byte.\n");
505 		return 0;
506 	}
507 	DEBUG("wavelan: tx timeout\n");
508 	return 0;
509 }
510 
511 static int
w_alloc(Ctlr * ctlr,int len)512 w_alloc(Ctlr* ctlr, int len)
513 {
514 	int rc;
515 	int i,j;
516 
517 	if (w_cmd(ctlr, WCmdMalloc, len)==0)
518 		for (i = 0; i<WTmOut; i++)
519 			if (csr_ins(ctlr, WR_EvSts) & WAllocEv){
520 				csr_ack(ctlr, WAllocEv);
521 				rc=csr_ins(ctlr, WR_Alloc);
522 				if (w_seek(ctlr, rc, 0, 0))
523 					return -1;
524 				len = len/2;
525 				for (j=0; j<len; j++)
526 					csr_outs(ctlr, WR_Data0, 0);
527 				return rc;
528 			}
529 	return -1;
530 }
531 
532 static int
w_enable(Ether * ether)533 w_enable(Ether* ether)
534 {
535 	Wltv ltv;
536 	Ctlr* ctlr = (Ctlr*) ether->ctlr;
537 
538 	if (!ctlr)
539 		return -1;
540 
541 	w_intdis(ctlr);
542 	w_cmd(ctlr, WCmdDis, 0);
543 	w_intdis(ctlr);
544 	if(w_cmd(ctlr, WCmdIni, 0))
545 		return -1;
546 	w_intdis(ctlr);
547 
548 	ltv_outs(ctlr, WTyp_Tick, 8);
549 	ltv_outs(ctlr, WTyp_MaxLen, ctlr->maxlen);
550 	ltv_outs(ctlr, WTyp_Ptype, ctlr->ptype);
551 	ltv_outs(ctlr, WTyp_RtsThres, ctlr->rtsthres);
552 	ltv_outs(ctlr, WTyp_TxRate, ctlr->txrate);
553 	ltv_outs(ctlr, WTyp_ApDens, ctlr->apdensity);
554 	ltv_outs(ctlr, WTyp_PMWait, ctlr->pmwait);
555 	ltv_outs(ctlr, WTyp_PM, ctlr->pmena);
556 	if (*ctlr->netname)
557 		ltv_outstr(ctlr, WTyp_NetName, ctlr->netname);
558 	if (*ctlr->wantname)
559 		ltv_outstr(ctlr, WTyp_WantName, ctlr->wantname);
560 	ltv_outs(ctlr, WTyp_Chan, ctlr->chan);
561 	if (*ctlr->nodename)
562 		ltv_outstr(ctlr, WTyp_NodeName, ctlr->nodename);
563 	ltv.len = 4;
564 	ltv.type = WTyp_Mac;
565 	memmove(ltv.addr, ether->ea, Eaddrlen);
566 	w_outltv(ctlr, &ltv);
567 
568 	ltv_outs(ctlr, WTyp_Prom, (ether->prom?1:0));
569 
570 	if (ctlr->hascrypt){
571 		ltv_outs(ctlr, WTyp_Crypt, ctlr->crypt);
572 		ltv_outs(ctlr, WTyp_TxKey, ctlr->txkey);
573 		w_outltv(ctlr, &ctlr->keys);
574 		ltv_outs(ctlr, WTyp_XClear, ctlr->xclear);
575 	}
576 
577 	// BUG: set multicast addresses
578 
579 	if (w_cmd(ctlr, WCmdEna, 0)){
580 		DEBUG("wavelan: Enable failed");
581 		return -1;
582 	}
583 	ctlr->txdid = w_alloc(ctlr, 1518 + sizeof(WFrame) + 8);
584 	ctlr->txmid = w_alloc(ctlr, 1518 + sizeof(WFrame) + 8);
585 	if (ctlr->txdid == -1 || ctlr->txmid == -1)
586 		DEBUG("wavelan: alloc failed");
587 	ctlr->txbusy = 0;
588 	w_intena(ctlr);
589 	return 0;
590 }
591 
592 static void
w_rxdone(Ether * ether)593 w_rxdone(Ether* ether)
594 {
595 	Ctlr* ctlr = (Ctlr*) ether->ctlr;
596 	int len, sp;
597 	WFrame f;
598 	Block* bp=0;
599 	Etherpkt* ep;
600 
601 	sp = csr_ins(ctlr, WR_RXId);
602 	len = w_read(ctlr, sp, 0, &f, sizeof(f));
603 	if (len == 0){
604 		DEBUG("wavelan: read frame error\n");
605 		goto rxerror;
606 	}
607 	if (f.sts&WF_Err){
608 		goto rxerror;
609 	}
610 	switch(f.sts){
611 	case WF_1042:
612 	case WF_Tunnel:
613 	case WF_WMP:
614 		len = f.dlen + WSnapHdrLen;
615 		bp = iallocb(ETHERHDRSIZE + len + 2);
616 		if (!bp)
617 			goto rxerror;
618 		ep = (Etherpkt*) bp->wp;
619 		memmove(ep->d, f.addr1, Eaddrlen);
620 		memmove(ep->s, f.addr2, Eaddrlen);
621 		memmove(ep->type,&f.type,2);
622 		bp->wp += ETHERHDRSIZE;
623 		if (w_read(ctlr, sp, WF_802_11_Off, bp->wp, len+2) == 0){
624 			DEBUG("wavelan: read 802.11 error\n");
625 			goto rxerror;
626 		}
627 		bp->wp = bp->rp+(ETHERHDRSIZE+f.dlen);
628 		break;
629 	default:
630 		len = ETHERHDRSIZE + f.dlen + 2;
631 		bp = iallocb(len);
632 		if (!bp)
633 			goto rxerror;
634 		if (w_read(ctlr, sp, WF_802_3_Off, bp->wp, len) == 0){
635 			DEBUG("wavelan: read 800.3 error\n");
636 			goto rxerror;
637 		}
638 		bp->wp += len;
639 	}
640 
641 	ctlr->nrx++;
642 	etheriq(ether,bp,1);
643 	ctlr->signal = ((ctlr->signal*15)+((f.qinfo>>8) & 0xFF))/16;
644 	ctlr->noise = ((ctlr->noise*15)+(f.qinfo & 0xFF))/16;
645 	return;
646 
647 rxerror:
648 	freeb(bp);
649 	ctlr->nrxerr++;
650 }
651 
652 static void
w_txstart(Ether * ether)653 w_txstart(Ether* ether)
654 {
655 	Etherpkt *pkt;
656 	Ctlr *ctlr;
657 	Block *bp;
658 	int len, off;
659 
660 	if((ctlr = ether->ctlr) == nil || ctlr->attached == 0 || ctlr->txbusy)
661 		return;
662 
663 	if((bp = qget(ether->oq)) == nil)
664 		return;
665 	pkt = (Etherpkt*)bp->rp;
666 
667 	//
668 	// If the packet header type field is > 1500 it is an IP or
669 	// ARP datagram, otherwise it is an 802.3 packet. See RFC1042.
670 	//
671 	memset(&ctlr->txf, 0, sizeof(ctlr->txf));
672 	if(((pkt->type[0]<<8)|pkt->type[1]) > 1500){
673 		ctlr->txf.framectl = WF_Data;
674 		memmove(ctlr->txf.addr1, pkt->d, Eaddrlen);
675 		memmove(ctlr->txf.addr2, pkt->s, Eaddrlen);
676 		memmove(ctlr->txf.dstaddr, pkt->d, Eaddrlen);
677 		memmove(ctlr->txf.srcaddr, pkt->s, Eaddrlen);
678 		memmove(&ctlr->txf.type, pkt->type, 2);
679 		bp->rp += ETHERHDRSIZE;
680 		len = BLEN(bp);
681 		off = WF_802_11_Off;
682 		ctlr->txf.dlen = len+ETHERHDRSIZE-WSnapHdrLen;
683 		hnputs((uchar*)&ctlr->txf.dat[0], WSnap0);
684 		hnputs((uchar*)&ctlr->txf.dat[1], WSnap1);
685 		hnputs((uchar*)&ctlr->txf.len, len+ETHERHDRSIZE-WSnapHdrLen);
686 	}
687 	else{
688 		len = BLEN(bp);
689 		off = WF_802_3_Off;
690 		ctlr->txf.dlen = len;
691 	}
692 	w_write(ctlr, ctlr->txdid, 0, &ctlr->txf, sizeof(ctlr->txf));
693 	w_write(ctlr, ctlr->txdid, off, bp->rp, len+2);
694 
695 	if(w_cmd(ctlr, WCmdReclaim|WCmdTx, ctlr->txdid)){
696 		DEBUG("wavelan: transmit failed\n");
697 		ctlr->ntxerr++;
698 	}
699 	else{
700 		ctlr->txbusy = 1;
701 		ctlr->txtmout = 2;
702 	}
703 	freeb(bp);
704 }
705 
706 static void
w_txdone(Ctlr * ctlr,int sts)707 w_txdone(Ctlr* ctlr, int sts)
708 {
709 	ctlr->txbusy = 0;
710 	ctlr->txtmout = 0;
711 	if (sts & WTxErrEv)
712 		ctlr->ntxerr++;
713 	else
714 		ctlr->ntx++;
715 }
716 
717 static int
w_stats(Ctlr * ctlr)718 w_stats(Ctlr* ctlr)
719 {
720 	int i, rc, sp;
721 	Wltv ltv;
722 	ulong* p = (ulong*)&ctlr->WStats;
723 	ulong* pend = (ulong*)&ctlr->end;
724 
725 	sp = csr_ins(ctlr, WR_InfoId);
726 	ltv.len = ltv.type = 0;
727 	w_read(ctlr, sp, 0, &ltv, 4);
728 	if (ltv.type == WTyp_Stats){
729 		ltv.len--;
730 		for (i = 0; i < ltv.len && p < pend; i++){
731 			rc = csr_ins(ctlr, WR_Data1);
732 			if (rc > 0xf000)
733 				rc = ~rc & 0xffff;
734 			p[i] += rc;
735 		}
736 		return 0;
737 	}
738 	return -1;
739 }
740 
741 static void
w_intr(Ether * ether)742 w_intr(Ether *ether)
743 {
744 	int rc, txid;
745 	Ctlr* ctlr = (Ctlr*) ether->ctlr;
746 
747 	if (ctlr->attached == 0){
748 		csr_ack(ctlr, 0xffff);
749 		csr_outs(ctlr, WR_IntEna, 0);
750 		return;
751 	}
752 
753 	csr_outs(ctlr, WR_IntEna, 0);
754 	rc = csr_ins(ctlr, WR_EvSts);
755 	csr_ack(ctlr, ~WEvs);	// Not interested on them
756 
757 	if (rc & WRXEv){
758 		w_rxdone(ether);
759 		csr_ack(ctlr, WRXEv);
760 	}
761 	if (rc & WTXEv){
762 		w_txdone(ctlr, rc);
763 		csr_ack(ctlr, WTXEv);
764 	}
765 	if (rc & WAllocEv){
766 		ctlr->nalloc++;
767 		txid = csr_ins(ctlr, WR_Alloc);
768 		csr_ack(ctlr, WAllocEv);
769 		if (txid == ctlr->txdid){
770 			if ((rc & WTXEv) == 0)
771 				w_txdone(ctlr, rc);
772 		}
773 	}
774 	if (rc & WInfoEv){
775 		ctlr->ninfo++;
776 		w_stats(ctlr);
777 		csr_ack(ctlr, WInfoEv);
778 	}
779 	if (rc & WTxErrEv){
780 		w_txdone(ctlr, rc);
781 		csr_ack(ctlr, WTxErrEv);
782 	}
783 	if (rc & WIDropEv){
784 		ctlr->nidrop++;
785 		csr_ack(ctlr, WIDropEv);
786 	}
787 
788 	w_intena(ctlr);
789 	w_txstart(ether);
790 }
791 
792 // Watcher to ensure that the card still works properly and
793 // to request WStats updates once a minute.
794 // BUG: it runs much more often, see the comment below.
795 
796 static void
w_timer(void * arg)797 w_timer(void* arg)
798 {
799 	Ether* ether = (Ether*) arg;
800 	Ctlr* ctlr = (Ctlr*)ether->ctlr;
801 
802 	for(;;){
803 		tsleep(&ctlr->timer, return0, 0, 50);
804 		ctlr = (Ctlr*)ether->ctlr;
805 		if (ctlr == 0)
806 			break;
807 		if (ctlr->attached == 0)
808 			continue;
809 		ctlr->ticks++;
810 
811 		ilock(ctlr);
812 
813 		// Seems that the card gets frames BUT does
814 		// not send the interrupt; this is a problem because
815 		// I suspect it runs out of receive buffers and
816 		// stops receiving until a transmit watchdog
817 		// reenables the card.
818 		// The problem is serious because it leads to
819 		// poor rtts.
820 		// This can be seen clearly by commenting out
821 		// the next if and doing a ping: it will stop
822 		// receiving (although the icmp replies are being
823 		// issued from the remote) after a few seconds.
824 		// Of course this `bug' could be because I'm reading
825 		// the card frames in the wrong way; due to the
826 		// lack of documentation I cannot know.
827 
828 //		if (csr_ins(ctlr, WR_EvSts)&WEvs){
829 //			ctlr->tickintr++;
830 //			w_intr(ether);
831 //		}
832 
833 		if ((ctlr->ticks % 10) == 0) {
834 			if (ctlr->txtmout && --ctlr->txtmout == 0){
835 				ctlr->nwatchdogs++;
836 				w_txdone(ctlr, WTxErrEv);
837 				if (w_enable(ether)){
838 					DEBUG("wavelan: wdog enable failed\n");
839 				}
840 				w_txstart(ether);
841 			}
842 			if ((ctlr->ticks % 120) == 0)
843 			if (ctlr->txbusy == 0)
844 				w_cmd(ctlr, WCmdAskStats, WTyp_Stats);
845 		}
846 		iunlock(ctlr);
847 	}
848 	pexit("terminated",0);
849 }
850 
851 static void
multicast(void *,uchar *,int)852 multicast(void*, uchar*, int)
853 {
854 	// BUG: to be added.
855 }
856 
857 static void
attach(Ether * ether)858 attach(Ether* ether)
859 {
860 	Ctlr* ctlr;
861 	char name[64];
862 	int rc;
863 
864 	if (ether->ctlr == 0)
865 		return;
866 
867 	snprint(name, sizeof(name), "#l%dtimer", ether->ctlrno);
868 	ctlr = (Ctlr*) ether->ctlr;
869 	if (ctlr->attached == 0){
870 		ilock(ctlr);
871 		rc = w_enable(ether);
872 		iunlock(ctlr);
873 		if(rc == 0){
874 			ctlr->attached = 1;
875 			kproc(name, w_timer, ether, 0);
876 		} else
877 			print("#l%d: enable failed\n",ether->ctlrno);
878 	}
879 }
880 
881 #define PRINTSTAT(fmt,val)	l += snprint(p+l, READSTR-l, (fmt), (val))
882 #define PRINTSTR(fmt)		l += snprint(p+l, READSTR-l, (fmt))
883 
884 static long
ifstat(Ether * ether,void * a,long n,ulong offset)885 ifstat(Ether* ether, void* a, long n, ulong offset)
886 {
887 	Ctlr *ctlr = (Ctlr*) ether->ctlr;
888 	char *k, *p;
889 	int i, l, txid;
890 
891 	ether->oerrs = ctlr->ntxerr;
892 	ether->crcs = ctlr->nrxfcserr;
893 	ether->frames = 0;
894 	ether->buffs = ctlr->nrxdropnobuf;
895 	ether->overflows = 0;
896 
897 	//
898 	// Offset must be zero or there's a possibility the
899 	// new data won't match the previous read.
900 	//
901 	if(n == 0 || offset != 0)
902 		return 0;
903 
904 	p = malloc(READSTR);
905 	l = 0;
906 
907 	PRINTSTAT("Signal: %d\n", ctlr->signal-149);
908 	PRINTSTAT("Noise: %d\n", ctlr->noise-149);
909 	PRINTSTAT("SNR: %ud\n", ctlr->signal-ctlr->noise);
910 	PRINTSTAT("Interrupts: %lud\n", ctlr->nints);
911 	PRINTSTAT("TxPackets: %lud\n", ctlr->ntx);
912 	PRINTSTAT("RxPackets: %lud\n", ctlr->nrx);
913 	PRINTSTAT("TxErrors: %lud\n", ctlr->ntxerr);
914 	PRINTSTAT("RxErrors: %lud\n", ctlr->nrxerr);
915 	PRINTSTAT("TxRequests: %lud\n", ctlr->ntxrq);
916 	PRINTSTAT("AllocEvs: %lud\n", ctlr->nalloc);
917 	PRINTSTAT("InfoEvs: %lud\n", ctlr->ninfo);
918 	PRINTSTAT("InfoDrop: %lud\n", ctlr->nidrop);
919 	PRINTSTAT("WatchDogs: %lud\n", ctlr->nwatchdogs);
920 	PRINTSTAT("Ticks: %ud\n", ctlr->ticks);
921 	PRINTSTAT("TickIntr: %ud\n", ctlr->tickintr);
922 	k = ((ctlr->attached) ? "attached" : "not attached");
923 	PRINTSTAT("Card %s", k);
924 	k = ((ctlr->txbusy)? ", txbusy" : "");
925 	PRINTSTAT("%s\n", k);
926 
927 	if (ctlr->hascrypt){
928 		PRINTSTR("Keys: ");
929 		for (i = 0; i < WNKeys; i++){
930 			if (ctlr->keys.keys[i].len == 0)
931 				PRINTSTR("none ");
932 			else if (SEEKEYS == 0)
933 				PRINTSTR("set ");
934 			else
935 				PRINTSTAT("%s ", ctlr->keys.keys[i].dat);
936 		}
937 		PRINTSTR("\n");
938 	}
939 
940 	// real card stats
941 	ilock(ctlr);
942 	PRINTSTR("\nCard stats: \n");
943 	PRINTSTAT("Status: %ux\n", csr_ins(ctlr, WR_Sts));
944 	PRINTSTAT("Event status: %ux\n", csr_ins(ctlr, WR_EvSts));
945 	i = ltv_ins(ctlr, WTyp_Ptype);
946 	PRINTSTAT("Port type: %d\n", i);
947 	PRINTSTAT("Transmit rate: %d\n", ltv_ins(ctlr, WTyp_TxRate));
948 	PRINTSTAT("Current Transmit rate: %d\n",
949 		ltv_ins(ctlr, WTyp_CurTxRate));
950 	PRINTSTAT("Channel: %d\n", ltv_ins(ctlr, WTyp_Chan));
951 	PRINTSTAT("AP density: %d\n", ltv_ins(ctlr, WTyp_ApDens));
952 	PRINTSTAT("Promiscuous mode: %d\n", ltv_ins(ctlr, WTyp_Prom));
953 	if(i == 3)
954 		PRINTSTAT("SSID name: %s\n", ltv_inname(ctlr, WTyp_NetName));
955 	else {
956 		Wltv ltv;
957 		PRINTSTAT("Current name: %s\n", ltv_inname(ctlr, WTyp_CurName));
958 		ltv.type = WTyp_BaseID;
959 		ltv.len = 4;
960 		if (w_inltv(ctlr, &ltv))
961 			print("#l%d: unable to read base station mac addr\n", ether->ctlrno);
962 		l += snprint(p+l, READSTR-l, "Base station: %2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n",
963 			ltv.addr[0], ltv.addr[1], ltv.addr[2], ltv.addr[3], ltv.addr[4], ltv.addr[5]);
964 	}
965 	PRINTSTAT("Net name: %s\n", ltv_inname(ctlr, WTyp_WantName));
966 	PRINTSTAT("Node name: %s\n", ltv_inname(ctlr, WTyp_NodeName));
967 	if (ltv_ins(ctlr, WTyp_HasCrypt) == 0)
968 		PRINTSTR("WEP: not supported\n");
969 	else {
970 		if (ltv_ins(ctlr, WTyp_Crypt) == 0)
971 			PRINTSTR("WEP: disabled\n");
972 		else{
973 			PRINTSTR("WEP: enabled\n");
974 			k = ((ctlr->xclear)? "excluded": "included");
975 			PRINTSTAT("Clear packets: %s\n", k);
976 			txid = ltv_ins(ctlr, WTyp_TxKey);
977 			PRINTSTAT("Transmit key id: %d\n", txid);
978 		}
979 	}
980 	iunlock(ctlr);
981 
982 	PRINTSTAT("ntxuframes: %lud\n", ctlr->ntxuframes);
983 	PRINTSTAT("ntxmframes: %lud\n", ctlr->ntxmframes);
984 	PRINTSTAT("ntxfrags: %lud\n", ctlr->ntxfrags);
985 	PRINTSTAT("ntxubytes: %lud\n", ctlr->ntxubytes);
986 	PRINTSTAT("ntxmbytes: %lud\n", ctlr->ntxmbytes);
987 	PRINTSTAT("ntxdeferred: %lud\n", ctlr->ntxdeferred);
988 	PRINTSTAT("ntxsretries: %lud\n", ctlr->ntxsretries);
989 	PRINTSTAT("ntxmultiretries: %lud\n", ctlr->ntxmultiretries);
990 	PRINTSTAT("ntxretrylimit: %lud\n", ctlr->ntxretrylimit);
991 	PRINTSTAT("ntxdiscards: %lud\n", ctlr->ntxdiscards);
992 	PRINTSTAT("nrxuframes: %lud\n", ctlr->nrxuframes);
993 	PRINTSTAT("nrxmframes: %lud\n", ctlr->nrxmframes);
994 	PRINTSTAT("nrxfrags: %lud\n", ctlr->nrxfrags);
995 	PRINTSTAT("nrxubytes: %lud\n", ctlr->nrxubytes);
996 	PRINTSTAT("nrxmbytes: %lud\n", ctlr->nrxmbytes);
997 	PRINTSTAT("nrxfcserr: %lud\n", ctlr->nrxfcserr);
998 	PRINTSTAT("nrxdropnobuf: %lud\n", ctlr->nrxdropnobuf);
999 	PRINTSTAT("nrxdropnosa: %lud\n", ctlr->nrxdropnosa);
1000 	PRINTSTAT("nrxcantdecrypt: %lud\n", ctlr->nrxcantdecrypt);
1001 	PRINTSTAT("nrxmsgfrag: %lud\n", ctlr->nrxmsgfrag);
1002 	PRINTSTAT("nrxmsgbadfrag: %lud\n", ctlr->nrxmsgbadfrag);
1003 	USED(l);
1004 	n = readstr(offset, a, n, p);
1005 	free(p);
1006 	return n;
1007 }
1008 #undef PRINTSTR
1009 #undef PRINTSTAT
1010 
1011 static int
w_option(Ctlr * ctlr,char * buf,long n)1012 w_option(Ctlr* ctlr, char* buf, long n)
1013 {
1014 	char *p;
1015 	int i, r;
1016 	WKey *key;
1017 	Cmdbuf *cb;
1018 
1019 	r = 0;
1020 
1021 	cb = parsecmd(buf, n);
1022 	if(cb->nf < 2)
1023 		r = -1;
1024 	else if(cistrcmp(cb->f[0], "essid") == 0){
1025 		if (cistrcmp(cb->f[1],"default") == 0)
1026 			p = "";
1027 		else
1028 			p = cb->f[1];
1029 		switch(ctlr->ptype){
1030 		case 0:
1031 		case 3:
1032 			memset(ctlr->netname, 0, sizeof(ctlr->netname));
1033 			strncpy(ctlr->netname, p, WNameLen);
1034 			if(ctlr->ptype == 3)
1035 				break;
1036 			/* fall through to set both for peer-to-peer */
1037 		default:
1038 			memset(ctlr->wantname, 0, sizeof(ctlr->wantname));
1039 			strncpy(ctlr->wantname, p, WNameLen);
1040 			break;
1041 		}
1042 	}
1043 	else if(cistrcmp(cb->f[0], "station") == 0){
1044 		memset(ctlr->nodename, 0, sizeof(ctlr->nodename));
1045 		strncpy(ctlr->nodename, cb->f[1], WNameLen);
1046 	}
1047 	else if(cistrcmp(cb->f[0], "channel") == 0){
1048 		if((i = atoi(cb->f[1])) >= 1 && i <= 16)
1049 			ctlr->chan = i;
1050 		else
1051 			r = -1;
1052 	}
1053 	else if(cistrcmp(cb->f[0], "mode") == 0){
1054 		if(cistrcmp(cb->f[1], "managed") == 0)
1055 			ctlr->ptype = WPTypeManaged;
1056 		else if(cistrcmp(cb->f[1], "wds") == 0)
1057 			ctlr->ptype = WPTypeWDS;
1058 		else if(cistrcmp(cb->f[1], "adhoc") == 0)
1059 			ctlr->ptype = WPTypeAdHoc;
1060 		else if(cistrcmp(cb->f[1], "peertopeer") == 0)
1061 			ctlr->ptype = WPTypePeerToPeer;
1062 		else if((i = atoi(cb->f[1])) >= 0 && i <= 3)
1063 			ctlr->ptype = i;
1064 		else
1065 			r = -1;
1066 	}
1067 	else if(cistrcmp(cb->f[0], "crypt") == 0){
1068 		if(cistrcmp(cb->f[1], "off") == 0)
1069 			ctlr->crypt = 0;
1070 		else if(cistrcmp(cb->f[1], "on") == 0 && ctlr->hascrypt)
1071 			ctlr->crypt = 1;
1072 		else
1073 			r = -1;
1074 	}
1075 	else if(cistrcmp(cb->f[0], "clear") == 0){
1076 		if(cistrcmp(cb->f[1], "on") == 0)
1077 			ctlr->xclear = 0;
1078 		else if(cistrcmp(cb->f[1], "off") == 0 && ctlr->hascrypt)
1079 			ctlr->xclear = 1;
1080 		else
1081 			r = -1;
1082 	}
1083 	else if(strncmp(cb->f[0], "key", 3) == 0){
1084 		if((i = atoi(cb->f[0]+3)) >= 1 && i <= WNKeys){
1085 			ctlr->txkey = i-1;
1086 			key = &ctlr->keys.keys[ctlr->txkey];
1087 			key->len = strlen(cb->f[1]);
1088 			if (key->len > WKeyLen)
1089 				key->len = WKeyLen;
1090 			memset(key->dat, 0, sizeof(key->dat));
1091 			memmove(key->dat, cb->f[1], key->len);
1092 		}
1093 		else
1094 			r = -1;
1095 	}
1096 	else if(cistrcmp(cb->f[0], "txkey") == 0){
1097 		if((i = atoi(cb->f[1])) >= 1 && i <= WNKeys)
1098 			ctlr->txkey = i-1;
1099 		else
1100 			r = -1;
1101 	}
1102 	else if(cistrcmp(cb->f[0], "pm") == 0){
1103 		if(cistrcmp(cb->f[1], "off") == 0)
1104 			ctlr->pmena = 0;
1105 		else if(cistrcmp(cb->f[1], "on") == 0){
1106 			ctlr->pmena = 1;
1107 			if(cb->nf == 3){
1108 				i = atoi(cb->f[2]);
1109 				// check range here? what are the units?
1110 				ctlr->pmwait = i;
1111 			}
1112 		}
1113 		else
1114 			r = -1;
1115 	}
1116 	else
1117 		r = -2;
1118 	free(cb);
1119 
1120 	return r;
1121 }
1122 
1123 static long
ctl(Ether * ether,void * buf,long n)1124 ctl(Ether* ether, void* buf, long n)
1125 {
1126 	Ctlr *ctlr;
1127 
1128 	if((ctlr = ether->ctlr) == nil)
1129 		error(Enonexist);
1130 	if(ctlr->attached == 0)
1131 		error(Eshutdown);
1132 
1133 	ilock(ctlr);
1134 	if(w_option(ctlr, buf, n)){
1135 		iunlock(ctlr);
1136 		error(Ebadctl);
1137 	}
1138 	if(ctlr->txbusy)
1139 		w_txdone(ctlr, WTxErrEv);
1140 	w_enable(ether);
1141 	w_txstart(ether);
1142 	iunlock(ctlr);
1143 
1144 	return n;
1145 }
1146 
1147 static void
transmit(Ether * ether)1148 transmit(Ether* ether)
1149 {
1150 	Ctlr* ctlr = ether->ctlr;
1151 
1152 	if (ctlr == 0)
1153 		return;
1154 
1155 	ilock(ctlr);
1156 	ctlr->ntxrq++;
1157 	w_txstart(ether);
1158 	iunlock(ctlr);
1159 }
1160 
1161 static void
promiscuous(void * arg,int on)1162 promiscuous(void* arg, int on)
1163 {
1164 	Ether* ether = (Ether*)arg;
1165 	Ctlr* ctlr = ether->ctlr;
1166 
1167 	if (ctlr == nil)
1168 		error("card not found");
1169 	if (ctlr->attached == 0)
1170 		error("card not attached");
1171 	ilock(ctlr);
1172 	ltv_outs(ctlr, WTyp_Prom, (on?1:0));
1173 	iunlock(ctlr);
1174 }
1175 
1176 static void
interrupt(Ureg *,void * arg)1177 interrupt(Ureg* ,void* arg)
1178 {
1179 	Ether* ether = (Ether*) arg;
1180 	Ctlr* ctlr = (Ctlr*) ether->ctlr;
1181 
1182 	if (ctlr == 0)
1183 		return;
1184 	ilock(ctlr);
1185 	ctlr->nints++;
1186 	w_intr(ether);
1187 	iunlock(ctlr);
1188 }
1189 
1190 static int
reset(Ether * ether)1191 reset(Ether* ether)
1192 {
1193 	int i;
1194 	Wltv ltv;
1195 	Ctlr* ctlr;
1196 	int slot;
1197 	char *p;
1198 
1199 	if ((slot = pcmspecial("WaveLAN/IEEE", ether))<0){
1200 		DEBUG("no wavelan found\n");
1201 		return -1;
1202 	}
1203 
1204 	if((ctlr = malloc(sizeof(Ctlr))) == nil)
1205 		return -1;
1206 
1207 	ilock(ctlr);
1208 
1209 	if (ether->port==0)
1210 		ether->port = WDfltIOB;
1211 	ctlr->iob = ether->port;
1212 	ctlr->slot = slot;
1213 
1214 	if (ioalloc(ether->port,WIOLen,0,"wavelan")<0){
1215 		print("#l%d: port 0x%lx in use\n",
1216 				ether->ctlrno, ether->port);
1217 		goto abort;
1218 	}
1219 	DEBUG("#l%d: port=0x%lx irq=%ld\n",
1220 			ether->ctlrno, ether->port, ether->irq);
1221 
1222 	w_intdis(ctlr);
1223 	if (w_cmd(ctlr,WCmdIni,0)){
1224 		print("#l%d: init failed\n", ether->ctlrno);
1225 		goto abort;
1226 	}
1227 	w_intdis(ctlr);
1228 	ltv_outs(ctlr, WTyp_Tick, 8);
1229 
1230 	ctlr->chan = 0;
1231 	ctlr->ptype = WDfltPType;
1232 	ctlr->txkey = 0;
1233 	ctlr->keys.len = sizeof(WKey)*WNKeys/2 + 1;
1234 	ctlr->keys.type = WTyp_Keys;
1235 	if(ctlr->hascrypt = ltv_ins(ctlr, WTyp_HasCrypt))
1236 		ctlr->crypt = 1;
1237 	*ctlr->netname = *ctlr->wantname = 0;
1238 	strcpy(ctlr->nodename, "Plan 9 STA");
1239 
1240 	for(i = 0; i < ether->nopt; i++){
1241 		//
1242 		// The max. length of an 'opt' is ISAOPTLEN in dat.h.
1243 		// It should be > 16 to give reasonable name lengths.
1244 		//
1245 		if(p = strchr(ether->opt[i], '='))
1246 			*p = ' ';
1247 		w_option(ctlr, ether->opt[i], strlen(ether->opt[i]));
1248 	}
1249 
1250 	ctlr->netname[WNameLen-1] = 0;
1251 	ctlr->wantname[WNameLen-1] = 0;
1252 	ctlr->nodename[WNameLen-1] =0;
1253 
1254 	ltv.type = WTyp_Mac;
1255 	ltv.len	= 4;
1256 	if (w_inltv(ctlr, &ltv)){
1257 		print("#l%d: unable to read mac addr\n",
1258 			ether->ctlrno);
1259 		goto abort;
1260 	}
1261 	memmove(ether->ea, ltv.addr, Eaddrlen);
1262 
1263 	if (ctlr->chan == 0)
1264 		ctlr->chan = ltv_ins(ctlr, WTyp_Chan);
1265 	ctlr->apdensity = WDfltApDens;
1266 	ctlr->rtsthres = WDfltRtsThres;
1267 	ctlr->txrate = WDfltTxRate;
1268 	ctlr->maxlen = WMaxLen;
1269 	ctlr->pmena = 0;
1270 	ctlr->pmwait = 100;
1271 	ctlr->signal = 1;
1272 	ctlr->noise = 1;
1273 
1274 	// link to ether
1275 	ether->ctlr = ctlr;
1276 	ether->mbps = 10;
1277 	ether->attach = attach;
1278 	ether->interrupt = interrupt;
1279 	ether->transmit = transmit;
1280 	ether->ifstat = ifstat;
1281 	ether->ctl = ctl;
1282 	ether->promiscuous = promiscuous;
1283 	ether->multicast = multicast;
1284 	ether->arg = ether;
1285 
1286 //	DEBUG("#l%d: irq %ld port %lx type %s",
1287 //		ether->ctlrno, ether->irq, ether->port,	ether->type);
1288 //	DEBUG(" %2.2uX%2.2uX%2.2uX%2.2uX%2.2uX%2.2uX\n",
1289 //		ether->ea[0], ether->ea[1], ether->ea[2],
1290 //		ether->ea[3], ether->ea[4], ether->ea[5]);
1291 
1292 	iunlock(ctlr);
1293 	return 0;
1294 
1295 abort:
1296 	iunlock(ctlr);
1297 	free(ctlr);
1298 	ether->ctlr = nil;
1299 iprint("wave reset failed\n");
1300 	return -1;
1301 }
1302 
1303 void
etherwavelanlink(void)1304 etherwavelanlink(void)
1305 {
1306 	addethercard("wavelan", reset);
1307 }
1308