xref: /original-bsd/sys/i386/isa/if_ne.c (revision 95a66346)
1 #include "ne.h"
2 #if NNE > 0
3 /*
4  * NE2000 Ethernet driver
5  * Copyright (C) 1990 W. Jolitz
6  * @(#)if_ne.c	1.6 (Berkeley) 01/08/91
7  *
8  * Parts inspired from Tim Tucker's if_wd driver for the wd8003,
9  * insight on the ne2000 gained from Robert Clements PC/FTP driver.
10  */
11 
12 #include "param.h"
13 #include "systm.h"
14 #include "mbuf.h"
15 #include "buf.h"
16 #include "protosw.h"
17 #include "socket.h"
18 #include "ioctl.h"
19 #include "errno.h"
20 #include "syslog.h"
21 
22 #include "../net/if.h"
23 #include "../net/netisr.h"
24 #include "../net/route.h"
25 
26 #ifdef INET
27 #include "../netinet/in.h"
28 #include "../netinet/in_systm.h"
29 #include "../netinet/in_var.h"
30 #include "../netinet/ip.h"
31 #include "../netinet/if_ether.h"
32 #endif
33 
34 #ifdef NS
35 #include "../netns/ns.h"
36 #include "../netns/ns_if.h"
37 #endif
38 
39 #include "machine/isa/isa_device.h"
40 #include "if_nereg.h"
41 #include "icu.h"
42 
43 int	neprobe(), neattach(), neintr();
44 int	neinit(), neoutput(), neioctl();
45 
46 #include "dbg.h"
47 struct	isa_driver nedriver = {
48 	neprobe, neattach, "ne",
49 };
50 
51 struct	mbuf *neget();
52 
53 /*
54  * Ethernet software status per interface.
55  *
56  * Each interface is referenced by a network interface structure,
57  * ns_if, which the routing code uses to locate the interface.
58  * This structure contains the output queue for the interface, its address, ...
59  */
60 struct	ne_softc {
61 	struct	arpcom ns_ac;		/* Ethernet common part */
62 #define	ns_if	ns_ac.ac_if		/* network-visible interface */
63 #define	ns_addr	ns_ac.ac_enaddr		/* hardware Ethernet address */
64 	int	ns_flags;
65 #define	DSF_LOCK	1		/* block re-entering enstart */
66 	int	ns_oactive ;
67 	int	ns_mask ;
68 	int	ns_ba;			/* byte addr in buffer ram of inc pkt */
69 	int	ns_cur;			/* current page being filled */
70 	struct	prhdr	ns_ph;		/* hardware header of incoming packet*/
71 	struct	ether_header ns_eh;	/* header of incoming packet */
72 	u_char	ns_pb[2048 /*ETHERMTU+sizeof(long)*/];
73 } ne_softc[NNE] ;
74 #define	ENBUFSIZE	(sizeof(struct ether_header) + ETHERMTU + 2 + 64)
75 
76 int nec;
77 
78 u_short boarddata[16];
79 
80 neprobe(dvp)
81 	struct isa_device *dvp;
82 {
83 	int val,i,s;
84 	register struct ne_softc *ns = &ne_softc[0];
85 
86 #ifdef lint
87 	neintr(0);
88 #endif
89 
90 	nec = dvp->id_iobase;
91 	s = splimp();
92 
93 	/* reset the bastard */
94 	val = inb(nec+ne_reset);
95 	DELAY(2000000);
96 	outb(nec+ne_reset,val);
97 
98 	outb(nec+ds_cmd, DSCM_STOP|DSCM_NODMA);
99 
100 	i = 1000000;
101 	while ((inb(nec+ds0_isr)&DSIS_RESET) == 0 && i-- > 0) nulldev();
102 	if (i < 0) return (0);
103 
104 	outb(nec+ds0_isr, 0xff);
105 
106 	/* Word Transfers, Burst Mode Select, Fifo at 8 bytes */
107 	outb(nec+ds0_dcr, DSDC_WTS|DSDC_BMS|DSDC_FT1);
108 
109 	outb(nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_STOP);
110 	DELAY(10000);
111 
112 	/* check cmd reg and fail if not right */
113 	if ((i=inb(nec+ds_cmd)) != (DSCM_NODMA|DSCM_PG0|DSCM_STOP))
114 		return(0);
115 
116 	outb(nec+ds0_tcr, 0);
117 	outb(nec+ds0_rcr, DSRC_MON);
118 	outb(nec+ds0_pstart, RBUF/DS_PGSIZE);
119 	outb(nec+ds0_pstop, RBUFEND/DS_PGSIZE);
120 	outb(nec+ds0_bnry, RBUFEND/DS_PGSIZE);
121 	outb(nec+ds0_imr, 0);
122 	outb(nec+ds0_isr, 0);
123 	outb(nec+ds_cmd, DSCM_NODMA|DSCM_PG1|DSCM_STOP);
124 	outb(nec+ds1_curr, RBUF/DS_PGSIZE);
125 	outb(nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_STOP);
126 	fetchrom (boarddata, 0, sizeof(boarddata));
127 #ifdef NEDEBUG
128 /*{ int i,rom;
129 	rom=1;
130 printf("ne ram ");
131 	for (i = 0; i < 0xfff0; i+=4) {
132 		int pat;
133 		pat = 0xa55a+i*37;
134 		putram(&pat,i,4);
135 		fetchram(&pat,i,4);
136 		if (pat == 0xa55a+i*37) {
137 			if (rom) { rom=0; printf(" %x", i); }
138 		} else {
139 			if (!rom) { rom=1; printf("..%x ", i); }
140 		}
141 		pat=0;
142 		putram(&pat,i,4);
143 	}
144 printf("\n");
145 }*/
146 #endif
147 /* checksum data? */
148 	/* extract board address */
149 	for(i=0; i < 6; i++)  ns->ns_addr[i] = boarddata[i];
150 	splx(s);
151 	return (1);
152 }
153 
154 fetchrom (up, ad, len) u_short *up; {
155 	u_char cmd;
156 
157 	cmd = inb(nec+ds_cmd);
158 	outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_STOP);
159 	outb (nec+ds0_isr, DSIS_RDC);
160 	outb (nec+ds0_rbcr0, len&0xff);
161 	outb (nec+ds0_rbcr1, (len>>8)&0xff);
162 	outb (nec+ds0_rsar0, ad&0xff);
163 	outb (nec+ds0_rsar1, (ad>>8)&0xff);
164 	outb (nec+ds_cmd, DSCM_RREAD|DSCM_PG0|DSCM_START);
165 	insw (nec+ne_data, up, len/2);
166 	pausestr ("x",1);
167 	while ((inb (nec+ds0_isr) & DSIS_RDC) == 0) pausestr("fetchrom",0);
168 	outb (nec+ds0_isr, DSIS_RDC);
169 	outb (nec+ds_cmd, cmd);
170 }
171 
172 static recur;
173 fetchram (up, ad, len) caddr_t up; {
174 	u_char cmd;
175 
176 	recur++;
177 	cmd = inb(nec+ds_cmd);
178 	outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START);
179 	outb (nec+ds0_isr, DSIS_RDC);
180 	outb (nec+ds0_rbcr0, len&0xff);
181 	outb (nec+ds0_rbcr1, (len>>8)&0xff);
182 	outb (nec+ds0_rsar0, ad&0xff);
183 	outb (nec+ds0_rsar1, (ad>>8)&0xff);
184 	outb (nec+ds_cmd, DSCM_RREAD|DSCM_PG0|DSCM_START);
185 	insw (nec+ne_data, up, len/2);
186 	pausestr ("x",1);
187 	while ((inb (nec+ds0_isr) & DSIS_RDC) == 0) pausestr("fetchram",0);
188 	outb (nec+ds0_isr, DSIS_RDC);
189 	outb (nec+ds_cmd, cmd);
190 	recur--;
191 }
192 
193 putram (up, ad, len) caddr_t up; {
194 	u_char cmd;
195 
196 	recur++;
197 	cmd = inb(nec+ds_cmd);
198 	outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START);
199 	outb (nec+ds0_isr, DSIS_RDC);
200 	if(len&1) len++;
201 	outb (nec+ds0_rbcr0, len&0xff);
202 	outb (nec+ds0_rbcr1, (len>>8)&0xff);
203 	outb (nec+ds0_rsar0, ad&0xff);
204 	outb (nec+ds0_rsar1, (ad>>8)&0xff);
205 	outb (nec+ds_cmd, DSCM_RWRITE|DSCM_PG0|DSCM_START);
206 	outsw (nec+ne_data, up, len/2);
207 	pausestr ("x",1);
208 	while ((inb (nec+ds0_isr) & DSIS_RDC) == 0)
209 		if(pausestr("putram",0)<0) break;
210 	outb (nec+ds0_isr, DSIS_RDC);
211 	outb (nec+ds_cmd, cmd);
212 	recur--;
213 }
214 
215 /*
216  * Reset of interface.
217  */
218 nereset(unit, uban)
219 	int unit, uban;
220 {
221 	if (unit >= NNE)
222 		return;
223 	printf("ne%d: reset\n", unit);
224 	ne_softc[unit].ns_flags &= ~DSF_LOCK;
225 	neinit(unit);
226 }
227 
228 /*
229  * Interface exists: make available by filling in network interface
230  * record.  System will initialize the interface when it is ready
231  * to accept packets.  We get the ethernet address here.
232  */
233 neattach(dvp)
234 	struct isa_device *dvp;
235 {
236 	int unit = dvp->id_unit;
237 	register struct ne_softc *ns = &ne_softc[unit];
238 	register struct ifnet *ifp = &ns->ns_if;
239 
240 	ifp->if_unit = unit;
241 	ifp->if_name = nedriver.name ;
242 	ifp->if_mtu = ETHERMTU;
243 	printf (" ethernet address %s", ether_sprintf(ns->ns_addr)) ;
244 	ifp->if_flags = IFF_BROADCAST|IFF_NOTRAILERS;
245 	ifp->if_init = neinit;
246 	ifp->if_output = neoutput;
247 	ifp->if_ioctl = neioctl;
248 	ifp->if_reset = nereset;
249 	ifp->if_watchdog = 0;
250 	if_attach(ifp);
251 }
252 
253 /*
254  * Initialization of interface; set up initialization block
255  * and transmit/receive descriptor rings.
256  */
257 neinit(unit)
258 	int unit;
259 {
260 	register struct ne_softc *ns = &ne_softc[unit];
261 	struct ifnet *ifp = &ns->ns_if;
262 	int s;
263 	register i; char *cp;
264 
265  	if (ifp->if_addrlist == (struct ifaddr *)0) return;
266 	if (ifp->if_flags & IFF_RUNNING) return;
267 
268 	s = splimp();
269 
270 	/* set physical address on ethernet */
271 	outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG1|DSCM_STOP);
272 	for (i=0 ; i < 6 ; i++) outb(nec+ds1_par0+i,ns->ns_addr[i]);
273 
274 	/* clr logical address hash filter for now */
275 	for (i=0 ; i < 8 ; i++) outb(nec+ds1_mar0+i,0xff);
276 
277 	/* init regs */
278 	outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_STOP);
279 	outb (nec+ds0_rbcr0, 0);
280 	outb (nec+ds0_rbcr1, 0);
281 	outb (nec+ds0_imr, 0);
282 	outb (nec+ds0_isr, 0xff);
283 	/* Word Transfers, Burst Mode Select, Fifo at 8 bytes */
284 	outb(nec+ds0_dcr, DSDC_WTS|DSDC_BMS|DSDC_FT1);
285 	outb(nec+ds0_tcr, 0);
286 	outb (nec+ds0_rcr, DSRC_MON);
287 	outb (nec+ds0_tpsr, 0);
288 	outb(nec+ds0_pstart, RBUF/DS_PGSIZE);
289 	outb(nec+ds0_pstop, RBUFEND/DS_PGSIZE);
290 	outb(nec+ds0_bnry, RBUF/DS_PGSIZE);
291 	outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG1|DSCM_STOP);
292 	outb(nec+ds1_curr, RBUF/DS_PGSIZE);
293 	ns->ns_cur = RBUF/DS_PGSIZE;
294 	outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START);
295 	outb (nec+ds0_rcr, DSRC_AB);
296 	outb(nec+ds0_dcr, DSDC_WTS|DSDC_BMS|DSDC_FT1);
297 	outb (nec+ds0_imr, 0xff);
298 
299 	ns->ns_if.if_flags |= IFF_RUNNING;
300 	ns->ns_oactive = 0; ns->ns_mask = ~0;
301 	if (ns->ns_if.if_snd.ifq_head) nestart(ns);
302 	splx(s);
303 }
304 
305 /*
306  * Setup output on interface.
307  * Get another datagram to send off of the interface queue,
308  * and map it to the interface before starting the output.
309  * called only at splimp or interrupt level.
310  */
311 nestart(ns)
312 	register struct ne_softc *ns;
313 {
314 	struct mbuf *m0, *m;
315 	int buffer;
316 	int len = 0, i;
317 
318 	/*
319 	 * The DS8390 has only one transmit buffer, if it is busy we
320 	 * must wait until the transmit interrupt completes.
321 	 */
322 	outb(nec+ds_cmd,DSCM_NODMA|DSCM_START);
323 
324 	if (ns->ns_flags & DSF_LOCK)
325 		return;
326 
327 	if (inb(nec+ds_cmd) & DSCM_TRANS)
328 		return;
329 
330 	if ((ns->ns_if.if_flags & IFF_RUNNING) == 0)
331 		return;
332 
333 	IF_DEQUEUE(&ns->ns_if.if_snd, m);
334 
335 	if (m == 0)
336 		return;
337 
338 	/*
339 	 * Copy the mbuf chain into the transmit buffer
340 	 */
341 
342 	ns->ns_flags |= DSF_LOCK;	/* prevent entering nestart */
343 	buffer = TBUF; len = i = 0;
344 	for (m0 = m; m != 0; m = m->m_next) {
345 /*int j;*/
346 		putram(mtod(m, caddr_t), buffer, m->m_len);
347 		buffer += m->m_len;
348 		len += m->m_len;
349 /*for(j=0; i < len;i++,j++) puthex(mtod(m,u_char *)[j]);
350 printf("|"); */
351 	}
352 
353 	/*
354 	 * If this was a broadcast packet loop it
355 	 * back because the hardware can't hear its own
356 	 * transmits.
357 	 */
358 	/*if (bcmp((caddr_t)(mtod(m0, struct ether_header *)->ether_dhost),
359 	   (caddr_t)etherbroadcastaddr,
360 	   sizeof(etherbroadcastaddr)) == 0) {
361 		neread(ns, m0);
362 	} else {
363 */
364 		m_freem(m0);
365 	/*}*/
366 
367 	/*
368 	 * Init transmit length registers, and set transmit start flag.
369 	 */
370 
371 #ifdef NEDEBUGx
372 if(len < 0 || len > 1536)
373 pg("T Bogus Length %d\n", len);
374 dprintf(DEXPAND,"snd %d ", len);
375 #endif
376 	if (len < 60) len = 60;
377 	outb(nec+ds0_tbcr0,len&0xff);
378 	outb(nec+ds0_tbcr1,(len>>8)&0xff);
379 	outb(nec+ds0_tpsr, TBUF/DS_PGSIZE);
380 	outb(nec+ds_cmd, DSCM_TRANS|DSCM_NODMA|DSCM_START);
381 }
382 
383 #define succ(n) (((n)+1 >= RBUFEND/DS_PGSIZE) ? RBUF/DS_PGSIZE : (n)+1)
384 #define pred(n) (((n)-1 < RBUF/DS_PGSIZE) ? RBUFEND/DS_PGSIZE-1 : (n)-1)
385 /*
386  * Controller interrupt.
387  */
388 neintr(vec, ppl)
389 	int vec;
390 {
391 	register struct ne_softc *ns = &ne_softc[0];
392 	u_char cmd,isr;
393 static cnt;
394 
395 	/* save cmd, clear interrupt */
396 	cmd = inb (nec+ds_cmd);
397 loop:
398 	isr = inb (nec+ds0_isr);
399 #ifdef NEDEBUGx
400 dprintf(DEXPAND,"|ppl %x isr %x ", ppl, isr);
401 #endif
402 
403 	outb(nec+ds_cmd,DSCM_NODMA|DSCM_START);
404 	outb(nec+ds0_isr, isr);
405 
406 
407 	if (isr & (DSIS_RXE|DSIS_TXE|DSIS_ROVRN))
408 		log(LOG_ERR, "ne%d: error: isr %x\n", ns-ne_softc, isr/*, DSIS_BITS*/);
409 
410 #ifdef notdef
411 	/* receiver ovverun? */
412 	if (isr & DSIS_ROVRN) {
413 		u_char pend,lastfree;
414 
415 		outb(nec+ds_cmd, DSCM_STOP|DSCM_NODMA);
416 		outb(nec+ds_cmd, DSCM_STOP|DSCM_NODMA|DSCM_PG1);
417 		pend = inb(nec+ds1_curr);
418 		outb(nec+ds_cmd, DSCM_STOP|DSCM_NODMA|DSCM_PG0);
419 		lastfree = inb(nec+ds0_bnry);
420 #ifdef NEDEBUG
421 printf("Cur %x pend %x lastfree %x ", ns->ns_cur, pend, lastfree);
422 #endif
423 		/* have we wrapped */
424 		if (lastfree >= RBUFEND/DS_PGSIZE)
425 			lastfree = RBUF/DS_PGSIZE;
426 		/* something in the buffer? */
427 		if (pend != succ(lastfree)) {
428 			u_char nxt;
429 
430 			fetchram(&ns->ns_ph,ns->ns_cur*DS_PGSIZE, sizeof(ns->ns_ph));
431 			ns->ns_ba = ns->ns_cur*DS_PGSIZE+sizeof(ns->ns_ph);
432 
433 			if (ns->ns_ph.pr_status & DSRS_RPC)
434 				nerecv (ns);
435 
436 			nxt = ns->ns_ph.pr_nxtpg ;
437 #ifdef NEDEBUG
438 printf("nxt %x ", nxt);
439 #endif
440 			/* sanity check */
441 			if ( nxt >= RBUF/DS_PGSIZE
442 			&& nxt <= RBUFEND/DS_PGSIZE && nxt <= pend)
443 				ns->ns_cur = nxt;
444 			else	ns->ns_cur = nxt = pend;
445 			lastfree = pred(nxt);
446 			outb(nec+ds0_bnry, lastfree);
447 		} else ns->ns_cur = pend;
448 
449 		outb(nec+ds0_rbcr0,0);
450 		outb(nec+ds0_rbcr1,0);
451 		outb(nec+ds0_tcr,DSTC_LB0);
452 		outb(nec+ds0_rcr, DSRC_MON);
453 		outb(nec+ds_cmd, DSCM_START|DSCM_NODMA);
454 		outb (nec+ds0_rcr, DSRC_AB);
455 		outb(nec+ds0_tcr,0);
456 	}
457 #endif
458 
459 	/* receiver error */
460 	if (isr & DSIS_RXE) {
461 		/* need to read these registers to clear status */
462 		(void) inb(nec+ ds0_rsr);
463 		(void) inb(nec+ 0xD);
464 		(void) inb(nec + 0xE);
465 		(void) inb(nec + 0xF);
466 		ns->ns_if.if_ierrors++;
467 	}
468 
469 	if (isr & (DSIS_RX|DSIS_RXE|DSIS_ROVRN)) {
470 		u_char pend,lastfree;
471 
472 		outb(nec+ds_cmd, DSCM_START|DSCM_NODMA|DSCM_PG1);
473 		pend = inb(nec+ds1_curr);
474 		outb(nec+ds_cmd, DSCM_START|DSCM_NODMA|DSCM_PG0);
475 		lastfree = inb(nec+ds0_bnry);
476 #ifdef NEDEBUG
477 dprintf(DEXPAND,"cur %x pnd %x lfr %x ", ns->ns_cur, pend, lastfree);
478 #endif
479 		/* have we wrapped */
480 		if (lastfree >= RBUFEND/DS_PGSIZE)
481 			lastfree = RBUF/DS_PGSIZE;
482 		if (pend < lastfree && ns->ns_cur < pend)
483 			lastfree = ns->ns_cur;
484 		else	if (ns->ns_cur > lastfree)
485 			lastfree = ns->ns_cur;
486 
487 		/* something in the buffer? */
488 		while (pend != lastfree) {
489 			u_char nxt;
490 
491 			fetchram(&ns->ns_ph,lastfree*DS_PGSIZE,
492 				sizeof(ns->ns_ph));
493 			ns->ns_ba = lastfree*DS_PGSIZE+sizeof(ns->ns_ph);
494 
495 			/* paranoia */
496 			if (ns->ns_ph.pr_status == DSRS_RPC ||
497 				ns->ns_ph.pr_status == 0x21)
498 				nerecv (ns);
499 #ifdef NEDEBUG
500 			else  {
501 printf("cur %x pnd %x lfr %x ", ns->ns_cur, pend, lastfree);
502 printf("nxt %x len %x ", ns->ns_ph.pr_nxtpg, (ns->ns_ph.pr_sz1<<8)+
503 	ns->ns_ph.pr_sz0);
504 pg("Bogus Sts %x ", ns->ns_ph.pr_status);
505 			}
506 #endif
507 
508 			nxt = ns->ns_ph.pr_nxtpg ;
509 #ifdef NEDEBUG
510 dprintf(DEXPAND,"nxt %x ", nxt);
511 #endif
512 			/* sanity check */
513 			if ( nxt >= RBUF/DS_PGSIZE
514 			&& nxt <= RBUFEND/DS_PGSIZE && nxt <= pend)
515 				ns->ns_cur = nxt;
516 			else	ns->ns_cur = nxt = pend;
517 			lastfree = nxt;
518 			outb(nec+ds0_bnry, pred(nxt));
519 			outb(nec+ds_cmd, DSCM_START|DSCM_NODMA|DSCM_PG1);
520 			pend = inb(nec+ds1_curr);
521 			outb(nec+ds_cmd, DSCM_START|DSCM_NODMA|DSCM_PG0);
522 		} /*else ns->ns_cur = pend;*/
523 #ifdef NEDEBUG
524 dprintf(DEXPAND,"cur %x pnd %x lfR %x ", ns->ns_cur, pend, lastfree);
525 #endif
526 		outb(nec+ds_cmd, DSCM_START|DSCM_NODMA);
527 	}
528 	if (isr & DSIS_TXE) {
529 		ns->ns_flags &= ~DSF_LOCK;
530 #ifdef NEDEBUG
531 dprintf(DEXPAND," clsn");
532 #endif
533 		/* need to read these registers to clear status */
534 		ns->ns_if.if_collisions += inb(nec+ds0_tbcr0);
535 		ns->ns_if.if_oerrors++;
536 	}
537 	if (isr & DSIS_TX) {
538 #ifdef NEDEBUGx
539 dprintf(DEXPAND,"tx ");
540 #endif
541 		ns->ns_flags &= ~DSF_LOCK;
542 		++ns->ns_if.if_opackets;
543 		ns->ns_if.if_collisions += inb(nec+ds0_tbcr0);
544 	}
545 
546 	/* receiver ovverun? */
547 	if (isr & DSIS_ROVRN) {
548 		outb(nec+ds0_rbcr0, 0);
549 		outb(nec+ds0_rbcr1, 0);
550 		outb(nec+ds0_tcr, DSTC_LB0);
551 		outb(nec+ds0_rcr, DSRC_MON);
552 		outb(nec+ds_cmd, DSCM_START|DSCM_NODMA);
553 		outb(nec+ds0_rcr, DSRC_AB);
554 		outb(nec+ds0_tcr, 0);
555 	}
556 
557 	outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START);
558 	nestart(ns);
559 	outb (nec+ds_cmd, cmd);
560 	outb (nec+ds0_imr, 0xff);
561 	isr = inb (nec+ds0_isr);
562 	if(isr) goto loop;
563 
564 #ifdef NEDEBUG
565 	if(++cnt % 10 == 0) dprintf(DEXPAND,"\n");
566 #endif
567 }
568 
569 /*
570  * Ethernet interface receiver interface.
571  * If input error just drop packet.
572  * Otherwise examine packet to determine type.  If can't determine length
573  * from type, then have to drop packet.  Othewise decapsulate
574  * packet based on type and pass to type specific higher-level
575  * input routine.
576  */
577 nerecv(ns)
578 	register struct ne_softc *ns;
579 {
580 	int len,i;
581 
582 	ns->ns_if.if_ipackets++;
583 	len = ns->ns_ph.pr_sz0 + (ns->ns_ph.pr_sz1<<8);
584 if(len < 60 || len > 1536) {
585 #ifdef NEDEBUG
586 pg(DEXPAND,"R Bogus Length %d", len);
587 #endif
588 return;
589 }
590 	fetchram(ns->ns_pb,ns->ns_ba,min(len,DS_PGSIZE-sizeof(ns->ns_ph)));
591 #ifdef NEDEBUG
592 if (!bcmp((caddr_t)ns->ns_pb, (caddr_t)ns->ns_addr, 6)
593 && !bcmp((caddr_t)ns->ns_pb, (caddr_t)etherbroadcastaddr, 6)) {
594 printf("G%x ", ns->ns_cur);
595 return;
596 }/* else
597 printf("P%x ", ns->ns_cur);*/
598 #endif
599 	if(len > DS_PGSIZE-sizeof(ns->ns_ph)) {
600 		int l = len - (DS_PGSIZE-sizeof(ns->ns_ph)), b ;
601 		u_char *p = ns->ns_pb + (DS_PGSIZE-sizeof(ns->ns_ph));
602 
603 #ifdef NEDEBUG
604 dprintf(DEXPAND,"len %d(%d|", len, p - ns->ns_pb);
605 #endif
606 		if(++ns->ns_cur > 0x7f) ns->ns_cur = 0x46;
607 		b = ns->ns_cur*DS_PGSIZE;
608 
609 		while (l >= DS_PGSIZE) {
610 			fetchram(p,b,DS_PGSIZE);
611 			p += DS_PGSIZE; l -= DS_PGSIZE;
612 		if(++ns->ns_cur > 0x7f) ns->ns_cur = 0x46;
613 		b = ns->ns_cur*DS_PGSIZE;
614 #ifdef NEDEBUG
615 dprintf(DEXPAND,"%d|", p - ns->ns_pb);
616 #endif
617 		}
618 #ifdef NEDEBUG
619 dprintf(DEXPAND,"%d) ", l);
620 #endif
621 		if (l > 0)
622 			fetchram(p,b,l);
623 	}
624 	len -=
625 		sizeof(struct ether_header)
626 		+ sizeof(long);	/* don't forget checksum! */
627 
628 
629 	neread(ns,(caddr_t)(ns->ns_pb), len);
630 }
631 
632 pausestr(s,n) char *s; {
633 static downcnt;
634 
635 	if(n) { downcnt = 0xffff; return(0); }
636 	if(--downcnt > 0) return(0);
637 #ifdef NEDEBUG
638 	pg(" <%s> recur %d sts %x ", s, recur, inb (nec+ds0_isr));
639 #endif
640 	return(-1);
641 }
642 
643 
644 /*
645  * Pass a packet to the higher levels.
646  * We deal with the trailer protocol here.
647  */
648 neread(ns, buf, len)
649 	register struct ne_softc *ns;
650 	char *buf;
651 	int len;
652 {
653 	register struct ether_header *eh;
654     	struct mbuf *m;
655 	int off, resid;
656 	register struct ifqueue *inq;
657 
658 	/*
659 	 * Deal with trailer protocol: if type is trailer type
660 	 * get true type from first 16-bit word past data.
661 	 * Remember that type was trailer by setting off.
662 	 */
663 	eh = (struct ether_header *)buf;
664 	eh->ether_type = ntohs((u_short)eh->ether_type);
665 #define	nedataaddr(eh, off, type)	((type)(((caddr_t)((eh)+1)+(off))))
666 	if (eh->ether_type >= ETHERTYPE_TRAIL &&
667 	    eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
668 		off = (eh->ether_type - ETHERTYPE_TRAIL) * 512;
669 		if (off >= ETHERMTU) return;		/* sanity */
670 		eh->ether_type = ntohs(*nedataaddr(eh, off, u_short *));
671 		resid = ntohs(*(nedataaddr(eh, off+2, u_short *)));
672 		if (off + resid > len) return;		/* sanity */
673 		len = off + resid;
674 	} else	off = 0;
675 
676 	if (len == 0) return;
677 
678 	/*
679 	 * Pull packet off interface.  Off is nonzero if packet
680 	 * has trailing header; neget will then force this header
681 	 * information to be at the front, but we still have to drop
682 	 * the type and length which are at the front of any trailer data.
683 	 */
684 	m = neget(buf, len, off, &ns->ns_if);
685 	if (m == 0) return;
686 
687 	if (off) {
688 		struct ifnet *ifp;
689 
690 		ifp = *(mtod(m, struct ifnet **));
691 		m->m_off += 2 * sizeof (u_short);
692 		m->m_len -= 2 * sizeof (u_short);
693 		*(mtod(m, struct ifnet **)) = ifp;
694 	}
695 	switch (eh->ether_type) {
696 #ifdef INET
697 	case ETHERTYPE_IP:
698 		/*if (ns->ns_ac.ac_ipaddr == 0) goto raw;*/
699 		schednetisr(NETISR_IP);
700 		inq = &ipintrq;
701 		break;
702 
703 	case ETHERTYPE_ARP:
704 		arpinput(&ns->ns_ac, m);
705 		return;
706 #endif
707 #ifdef NS
708 	case ETHERTYPE_NS:
709 		schednetisr(NETISR_NS);
710 		inq = &nsintrq;
711 		break;
712 
713 #endif
714 	default:
715 		m_freem(m);
716 		return;
717 	}
718 
719 	if (IF_QFULL(inq)) {
720 		IF_DROP(inq);
721 		m_freem(m);
722 		return;
723 	}
724 	IF_ENQUEUE(inq, m);
725 }
726 
727 /*
728  * Ethernet output routine.
729  * Encapsulate a packet of type family for the local net.
730  * Use trailer local net encapsulation if enough data in first
731  * packet leaves a multiple of 512 bytes of data in remainder.
732  */
733 neoutput(ifp, m0, dst)
734 	struct ifnet *ifp;
735 	struct mbuf *m0;
736 	struct sockaddr *dst;
737 {
738 	int type, s, error;
739 	u_char edst[6];
740 	struct in_addr idst;
741 	register struct ne_softc *ns = &ne_softc[ifp->if_unit];
742 	register struct mbuf *m = m0;
743 	register struct ether_header *eh;
744 	register int off;
745 	extern struct ifnet loif;
746         struct mbuf *mcopy = (struct mbuf *)0;
747 	int usetrailers;
748 
749 	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
750 		error = ENETDOWN;
751 		goto bad;
752 	}
753 
754 	switch (dst->sa_family) {
755 #ifdef INET
756 	case AF_INET:
757 		idst = ((struct sockaddr_in *)dst)->sin_addr;
758 		if (!arpresolve(&ns->ns_ac, m, &idst, edst, &usetrailers))
759 			return (0);	/* if not yet resolved */
760 		if (!bcmp((caddr_t)edst, (caddr_t)etherbroadcastaddr,
761 		    sizeof(edst)))
762                         mcopy = m_copy(m, 0, (int)M_COPYALL);
763 		off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
764 
765 
766 		/* need per host negotiation */
767 		if (usetrailers && off > 0 && (off & 0x1ff) == 0 &&
768 		    m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
769 			type = ETHERTYPE_TRAIL + (off>>9);
770 			m->m_off -= 2 * sizeof (u_short);
771 			m->m_len += 2 * sizeof (u_short);
772 			*mtod(m, u_short *) = ntohs((u_short)ETHERTYPE_IP);
773 			*(mtod(m, u_short *) + 1) = ntohs((u_short)m->m_len);
774 			goto gottrailertype;
775 		}
776 		type = ETHERTYPE_IP;
777 		off = 0;
778 		goto gottype;
779 #endif
780 #ifdef NS
781 	case AF_NS:
782  		bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host),
783 		    (caddr_t)edst, sizeof (edst));
784 
785 		if (!bcmp((caddr_t)edst, (caddr_t)&ns_broadhost,
786 			sizeof(edst))) {
787 
788 				mcopy = m_copy(m, 0, (int)M_COPYALL);
789 		} else if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost,
790 			sizeof(edst))) {
791 
792 				return(looutput(&loif, m, dst));
793 		}
794 		type = ETHERTYPE_NS;
795 		off = 0;
796 		goto gottype;
797 #endif
798 
799 	case AF_UNSPEC:
800 		eh = (struct ether_header *)dst->sa_data;
801 		bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst));
802 		type = eh->ether_type;
803 		goto gottype;
804 
805 	default:
806 		printf("ne%d: can't handle af%d\n", ifp->if_unit,
807 			dst->sa_family);
808 		error = EAFNOSUPPORT;
809 		goto bad;
810 	}
811 
812 gottrailertype:
813 	/*
814 	 * Packet to be sent as trailer: move first packet
815 	 * (control information) to end of chain.
816 	 */
817 	while (m->m_next)
818 		m = m->m_next;
819 	m->m_next = m0;
820 	m = m0->m_next;
821 	m0->m_next = 0;
822 	m0 = m;
823 
824 gottype:
825 	/*
826 	 * Add local net header.  If no space in first mbuf,
827 	 * allocate another.
828 	 */
829 	if (m->m_off > MMAXOFF ||
830 	    MMINOFF + sizeof (struct ether_header) > m->m_off) {
831 		m = m_get(M_DONTWAIT, MT_HEADER);
832 		if (m == 0) {
833 			error = ENOBUFS;
834 			goto bad;
835 		}
836 		m->m_next = m0;
837 		m->m_off = MMINOFF;
838 		m->m_len = sizeof (struct ether_header);
839 	} else {
840 		m->m_off -= sizeof (struct ether_header);
841 		m->m_len += sizeof (struct ether_header);
842 	}
843 	eh = mtod(m, struct ether_header *);
844 	bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst));
845 	bcopy((caddr_t)ns->ns_addr, (caddr_t)eh->ether_shost,
846 		sizeof (eh->ether_shost));
847 	eh->ether_type = htons((u_short)type);
848 
849 	/*
850 	 * Queue message on interface, and start output if interface
851 	 * not yet active.
852 	 */
853 	s = splimp();
854 	if (IF_QFULL(&ifp->if_snd)) {
855 		IF_DROP(&ifp->if_snd);
856 		splx(s);
857 		m_freem(m);
858 		return (ENOBUFS);
859 	}
860 	IF_ENQUEUE(&ifp->if_snd, m);
861 	nestart(ns);
862 	splx(s);
863         return (mcopy ? looutput(&loif, mcopy, dst) : 0);
864 
865 bad:
866 	m_freem(m0);
867 	if (mcopy)
868 		m_freem(mcopy);
869 	return (error);
870 }
871 
872 /*
873  * Supporting routines
874  */
875 
876 /*
877  * Pull read data off a interface.
878  * Len is length of data, with local net header stripped.
879  * Off is non-zero if a trailer protocol was used, and
880  * gives the offset of the trailer information.
881  * We copy the trailer information and then all the normal
882  * data into mbufs.  When full cluster sized units are present
883  * we copy into clusters.
884  */
885 struct mbuf *
886 neget(buf, totlen, off0, ifp)
887 	caddr_t buf;
888 	int totlen, off0;
889 	struct ifnet *ifp;
890 {
891 	struct mbuf *top, **mp, *m, *p;
892 	int off = off0, len;
893 	register caddr_t cp = buf;
894 
895 	cp = buf + sizeof(struct ether_header);
896 	top = 0;
897 	mp = &top;
898 	while (totlen > 0) {
899 		u_char *mcp;
900 
901 		MGET(m, M_DONTWAIT, MT_DATA);
902 		if (m == 0)
903 			goto bad;
904 		if (off) {
905 			len = totlen - off;
906 			cp = buf + off + sizeof (struct ether_header);
907 		} else
908 			len = totlen;
909 		if (ifp)
910 			len += sizeof(ifp);
911 		if (len >= NBPG) {
912 			MCLGET(m);
913 			if (m->m_len == CLBYTES)
914 				m->m_len = len = MIN(len, CLBYTES);
915 			else
916 				m->m_len = len = MIN(MLEN, len);
917 		} else {
918 			m->m_len = len = MIN(MLEN, len);
919 			m->m_off = MMINOFF;
920 		}
921 		mcp = mtod(m, u_char *);
922 		if (ifp) {
923 			/*
924 			 * Prepend interface pointer to first mbuf.
925 			 */
926 			*(mtod(m, struct ifnet **)) = ifp;
927 			mcp += sizeof(ifp);
928 			len -= sizeof(ifp);
929 			ifp = (struct ifnet *)0;
930 		}
931 		bcopy(cp, mcp, len);
932 		cp += len ; mcp += len ;
933 		*mp = m;
934 		mp = &m->m_next;
935 		if (off == 0) {
936 			totlen -= len;
937 			continue;
938 		}
939 		off += len;
940 		if (off == totlen) {
941 			cp = buf + sizeof (struct ether_header);
942 			off = 0;
943 			totlen = off0;
944 		}
945 	}
946 	return (top);
947 bad:
948 	m_freem(top);
949 	return (0);
950 }
951 
952 /*
953  * Map a chain of mbufs onto a network interface
954  * in preparation for an i/o operation.
955  * The argument chain of mbufs includes the local network
956  * header which is copied to be in the mapped, aligned
957  * i/o space.
958  */
959 neput(cp, m)
960 	register caddr_t cp;
961 	register struct mbuf *m;
962 {
963 	register struct mbuf *mp;
964 	register int i;
965 	int x, cc = 0, t;
966 	caddr_t dp;
967 
968 	while (m) {
969 		dp = mtod(m, char *);
970 		bcopy(mtod(m, caddr_t), cp, (unsigned)m->m_len);
971 		cp += m->m_len;
972 		cc += m->m_len;
973 		MFREE(m, mp);
974 		m = mp;
975 	}
976 	return (max(cc, ETHERMIN + sizeof(struct ether_header)));
977 }
978 
979 /*
980  * Process an ioctl request.
981  */
982 neioctl(ifp, cmd, data)
983 	register struct ifnet *ifp;
984 	int cmd;
985 	caddr_t data;
986 {
987 	register struct ifaddr *ifa = (struct ifaddr *)data;
988 	struct ne_softc *ns = &ne_softc[ifp->if_unit];
989 	struct ifreq *ifr = (struct ifreq *)data;
990 	int s = splimp(), error = 0;
991 
992 
993 	switch (cmd) {
994 
995 	case SIOCSIFADDR:
996 		ifp->if_flags |= IFF_UP;
997 
998 		switch (ifa->ifa_addr.sa_family) {
999 #ifdef INET
1000 		case AF_INET:
1001 			neinit(ifp->if_unit);	/* before arpwhohas */
1002 			((struct arpcom *)ifp)->ac_ipaddr =
1003 				IA_SIN(ifa)->sin_addr;
1004 			arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
1005 			break;
1006 #endif
1007 #ifdef NS
1008 		case AF_NS:
1009 		    {
1010 			register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
1011 
1012 			if (ns_nullhost(*ina))
1013 				ina->x_host = *(union ns_host *)(ns->ns_addr);
1014 			else {
1015 				/*
1016 				 * The manual says we can't change the address
1017 				 * while the receiver is armed,
1018 				 * so reset everything
1019 				 */
1020 				ifp->if_flags &= ~IFF_RUNNING;
1021 				bcopy((caddr_t)ina->x_host.c_host,
1022 				    (caddr_t)ns->ns_addr, sizeof(ns->ns_addr));
1023 			}
1024 			neinit(ifp->if_unit); /* does ne_setaddr() */
1025 			break;
1026 		    }
1027 #endif
1028 		default:
1029 			neinit(ifp->if_unit);
1030 			break;
1031 		}
1032 		break;
1033 
1034 	case SIOCSIFFLAGS:
1035 		if ((ifp->if_flags & IFF_UP) == 0 &&
1036 		    ifp->if_flags & IFF_RUNNING) {
1037 			ifp->if_flags &= ~IFF_RUNNING;
1038 			outb(nec+ds_cmd,DSCM_STOP|DSCM_NODMA);
1039 		} else if (ifp->if_flags & IFF_UP &&
1040 		    (ifp->if_flags & IFF_RUNNING) == 0)
1041 			neinit(ifp->if_unit);
1042 		break;
1043 
1044 #ifdef notdef
1045 	case SIOCGHWADDR:
1046 		bcopy((caddr_t)ns->ns_addr, (caddr_t) &ifr->ifr_data,
1047 			sizeof(ns->ns_addr));
1048 		break;
1049 #endif
1050 
1051 	default:
1052 		error = EINVAL;
1053 	}
1054 	splx(s);
1055 	return (error);
1056 }
1057 
1058 nesetaddr(ifp, sin)
1059 	register struct ifnet *ifp;
1060 	register struct sockaddr_in *sin;
1061 {
1062 #ifdef notdef
1063 	ifp->if_addr = *(struct sockaddr *)sin;
1064 	ifp->if_net = in_netof(sin->sin_addr);
1065 	ifp->if_host[0] = in_lnaof(sin->sin_addr);
1066 	if (nepaddr[ifp->if_unit][0] == '3')
1067 		nepaddr[ifp->if_unit][0] = ifp->if_host[0] << 1;
1068 	sin = (struct sockaddr_in *)&ifp->if_broadaddr;
1069 	sin->sin_family = AF_INET;
1070 	sin->sin_addr = in_makeaddr(ifp->if_net, INADDR_ANY);
1071 	ifp->if_flags |= IFF_BROADCAST;
1072 #endif
1073 }
1074 #endif
1075