xref: /csrg-svn/sys/i386/isa/if_ne.c (revision 49699)
1 #include "ne.h"
2 #if NNE > 0
3 /*-
4  * NE2000 Ethernet driver
5  * Copyright (C) 1990,91 W. Jolitz
6  * Copyright (c) 1990 The Regents of the University of California.
7  * All rights reserved.
8  *
9  * %sccs.include.redist.c%
10  *
11  *	@(#)if_ne.c	7.2 (Berkeley) 05/12/91
12  *
13  * Parts inspired from Tim Tucker's if_wd driver for the wd8003,
14  * insight on the ne2000 gained from Robert Clements PC/FTP driver.
15  */
16 
17 #include "param.h"
18 #include "systm.h"
19 #include "mbuf.h"
20 #include "buf.h"
21 #include "protosw.h"
22 #include "socket.h"
23 #include "ioctl.h"
24 #include "errno.h"
25 #include "syslog.h"
26 
27 #include "net/if.h"
28 #include "net/netisr.h"
29 #include "net/route.h"
30 
31 #ifdef INET
32 #include "netinet/in.h"
33 #include "netinet/in_systm.h"
34 #include "netinet/in_var.h"
35 #include "netinet/ip.h"
36 #include "netinet/if_ether.h"
37 #endif
38 
39 #ifdef NS
40 #include "netns/ns.h"
41 #include "netns/ns_if.h"
42 #endif
43 
44 #include "i386/isa/isa_device.h"
45 #include "i386/isa/if_nereg.h"
46 #include "i386/isa/icu.h"
47 
48 int	neprobe(), neattach(), neintr();
49 int	nestart(),neinit(), ether_output(), neioctl();
50 
51 struct	isa_driver nedriver = {
52 	neprobe, neattach, "ne",
53 };
54 
55 struct	mbuf *neget();
56 
57 /*
58  * Ethernet software status per interface.
59  *
60  * Each interface is referenced by a network interface structure,
61  * ns_if, which the routing code uses to locate the interface.
62  * This structure contains the output queue for the interface, its address, ...
63  */
64 struct	ne_softc {
65 	struct	arpcom ns_ac;		/* Ethernet common part */
66 #define	ns_if	ns_ac.ac_if		/* network-visible interface */
67 #define	ns_addr	ns_ac.ac_enaddr		/* hardware Ethernet address */
68 	int	ns_flags;
69 #define	DSF_LOCK	1		/* block re-entering enstart */
70 	int	ns_oactive ;
71 	int	ns_mask ;
72 	int	ns_ba;			/* byte addr in buffer ram of inc pkt */
73 	int	ns_cur;			/* current page being filled */
74 	struct	prhdr	ns_ph;		/* hardware header of incoming packet*/
75 	struct	ether_header ns_eh;	/* header of incoming packet */
76 	u_char	ns_pb[2048 /*ETHERMTU+sizeof(long)*/];
77 } ne_softc[NNE] ;
78 #define	ENBUFSIZE	(sizeof(struct ether_header) + ETHERMTU + 2 + ETHER_MIN_LEN)
79 
80 int nec;
81 
82 u_short boarddata[16];
83 
84 neprobe(dvp)
85 	struct isa_device *dvp;
86 {
87 	int val,i,s;
88 	register struct ne_softc *ns = &ne_softc[0];
89 
90 #ifdef lint
91 	neintr(0);
92 #endif
93 
94 	nec = dvp->id_iobase;
95 	s = splimp();
96 
97 	/* Reset the bastard */
98 	val = inb(nec+ne_reset);
99 	DELAY(2000000);
100 	outb(nec+ne_reset,val);
101 
102 	outb(nec+ds_cmd, DSCM_STOP|DSCM_NODMA);
103 
104 	i = 1000000;
105 	while ((inb(nec+ds0_isr)&DSIS_RESET) == 0 && i-- > 0);
106 	if (i < 0) return (0);
107 
108 	outb(nec+ds0_isr, 0xff);
109 
110 	/* Word Transfers, Burst Mode Select, Fifo at 8 bytes */
111 	outb(nec+ds0_dcr, DSDC_WTS|DSDC_BMS|DSDC_FT1);
112 
113 	outb(nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_STOP);
114 	DELAY(10000);
115 
116 	/* Check cmd reg and fail if not right */
117 	if ((i=inb(nec+ds_cmd)) != (DSCM_NODMA|DSCM_PG0|DSCM_STOP))
118 		return(0);
119 
120 	outb(nec+ds0_tcr, 0);
121 	outb(nec+ds0_rcr, DSRC_MON);
122 	outb(nec+ds0_pstart, RBUF/DS_PGSIZE);
123 	outb(nec+ds0_pstop, RBUFEND/DS_PGSIZE);
124 	outb(nec+ds0_bnry, RBUFEND/DS_PGSIZE);
125 	outb(nec+ds0_imr, 0);
126 	outb(nec+ds0_isr, 0);
127 	outb(nec+ds_cmd, DSCM_NODMA|DSCM_PG1|DSCM_STOP);
128 	outb(nec+ds1_curr, RBUF/DS_PGSIZE);
129 	outb(nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_STOP);
130 
131 #ifdef NEDEBUG
132 #define	PAT(n)	(0xa55a + 37*(n))
133 #define	RCON	37
134 	{	int i, rom, pat;
135 
136 		rom=1;
137 		printf("ne ram ");
138 
139 		for (i = 0; i < 0xfff0; i+=4) {
140 			pat = PAT(i);
141 			neput(&pat,i,4);
142 			nefetch(&pat,i,4);
143 			if (pat == PAT(i)) {
144 				if (rom) {
145 					rom=0;
146 					printf(" %x", i);
147 				}
148 			} else {
149 				if (!rom) {
150 					rom=1;
151 					printf("..%x ", i);
152 				}
153 			}
154 			pat=0;
155 			neput(&pat,i,4);
156 		}
157 		printf("\n");
158 	}
159 #endif
160 
161 	/* Extract board address */
162 	nefetch ((caddr_t)boarddata, 0, sizeof(boarddata));
163 	for(i=0; i < 6; i++)  ns->ns_addr[i] = boarddata[i];
164 	splx(s);
165 	return (1);
166 }
167 
168 /*
169  * Fetch from onboard ROM/RAM
170  */
171 nefetch (up, ad, len) caddr_t up; {
172 	u_char cmd;
173 
174 	cmd = inb(nec+ds_cmd);
175 	outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START);
176 
177 	/* Setup remote dma */
178 	outb (nec+ds0_isr, DSIS_RDC);
179 	outb (nec+ds0_rbcr0, len);
180 	outb (nec+ds0_rbcr1, len>>8);
181 	outb (nec+ds0_rsar0, ad);
182 	outb (nec+ds0_rsar1, ad>>8);
183 
184 	/* Execute & extract from card */
185 	outb (nec+ds_cmd, DSCM_RREAD|DSCM_PG0|DSCM_START);
186 	insw (nec+ne_data, up, len/2);
187 
188 	/* Wait till done, then shutdown feature */
189 	while ((inb (nec+ds0_isr) & DSIS_RDC) == 0) ;
190 	outb (nec+ds0_isr, DSIS_RDC);
191 	outb (nec+ds_cmd, cmd);
192 }
193 
194 /*
195  * Put to onboard RAM
196  */
197 neput (up, ad, len) caddr_t up; {
198 	u_char cmd;
199 
200 	cmd = inb(nec+ds_cmd);
201 	outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START);
202 
203 	/* Setup for remote dma */
204 	outb (nec+ds0_isr, DSIS_RDC);
205 	if(len&1) len++;		/* roundup to words */
206 	outb (nec+ds0_rbcr0, len);
207 	outb (nec+ds0_rbcr1, len>>8);
208 	outb (nec+ds0_rsar0, ad);
209 	outb (nec+ds0_rsar1, ad>>8);
210 
211 	/* Execute & stuff to card */
212 	outb (nec+ds_cmd, DSCM_RWRITE|DSCM_PG0|DSCM_START);
213 	outsw (nec+ne_data, up, len/2);
214 
215 	/* Wait till done, then shutdown feature */
216 	while ((inb (nec+ds0_isr) & DSIS_RDC) == 0) ;
217 	outb (nec+ds0_isr, DSIS_RDC);
218 	outb (nec+ds_cmd, cmd);
219 }
220 
221 /*
222  * Reset of interface.
223  */
224 nereset(unit, uban)
225 	int unit, uban;
226 {
227 	if (unit >= NNE)
228 		return;
229 	printf("ne%d: reset\n", unit);
230 	ne_softc[unit].ns_flags &= ~DSF_LOCK;
231 	neinit(unit);
232 }
233 
234 /*
235  * Interface exists: make available by filling in network interface
236  * record.  System will initialize the interface when it is ready
237  * to accept packets.  We get the ethernet address here.
238  */
239 neattach(dvp)
240 	struct isa_device *dvp;
241 {
242 	int unit = dvp->id_unit;
243 	register struct ne_softc *ns = &ne_softc[unit];
244 	register struct ifnet *ifp = &ns->ns_if;
245 
246 	ifp->if_unit = unit;
247 	ifp->if_name = nedriver.name ;
248 	ifp->if_mtu = ETHERMTU;
249 	printf (" ethernet address %s", ether_sprintf(ns->ns_addr)) ;
250 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
251 	ifp->if_init = neinit;
252 	ifp->if_output = ether_output;
253 	ifp->if_start = nestart;
254 	ifp->if_ioctl = neioctl;
255 	ifp->if_reset = nereset;
256 	ifp->if_watchdog = 0;
257 	if_attach(ifp);
258 }
259 
260 /*
261  * Initialization of interface; set up initialization block
262  * and transmit/receive descriptor rings.
263  */
264 neinit(unit)
265 	int unit;
266 {
267 	register struct ne_softc *ns = &ne_softc[unit];
268 	struct ifnet *ifp = &ns->ns_if;
269 	int s;
270 	register i; char *cp;
271 
272  	if (ifp->if_addrlist == (struct ifaddr *)0) return;
273 	if (ifp->if_flags & IFF_RUNNING) return;
274 
275 	s = splimp();
276 
277 	/* set physical address on ethernet */
278 	outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG1|DSCM_STOP);
279 	for (i=0 ; i < 6 ; i++) outb(nec+ds1_par0+i,ns->ns_addr[i]);
280 
281 	/* clr logical address hash filter for now */
282 	for (i=0 ; i < 8 ; i++) outb(nec+ds1_mar0+i,0xff);
283 
284 	/* init regs */
285 	outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_STOP);
286 	outb (nec+ds0_rbcr0, 0);
287 	outb (nec+ds0_rbcr1, 0);
288 	outb (nec+ds0_imr, 0);
289 	outb (nec+ds0_isr, 0xff);
290 
291 	/* Word Transfers, Burst Mode Select, Fifo at 8 bytes */
292 	outb(nec+ds0_dcr, DSDC_WTS|DSDC_BMS|DSDC_FT1);
293 	outb(nec+ds0_tcr, 0);
294 	outb (nec+ds0_rcr, DSRC_MON);
295 	outb (nec+ds0_tpsr, 0);
296 	outb(nec+ds0_pstart, RBUF/DS_PGSIZE);
297 	outb(nec+ds0_pstop, RBUFEND/DS_PGSIZE);
298 	outb(nec+ds0_bnry, RBUF/DS_PGSIZE);
299 	outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG1|DSCM_STOP);
300 	outb(nec+ds1_curr, RBUF/DS_PGSIZE);
301 	ns->ns_cur = RBUF/DS_PGSIZE;
302 	outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START);
303 	outb (nec+ds0_rcr, DSRC_AB);
304 	outb(nec+ds0_dcr, DSDC_WTS|DSDC_BMS|DSDC_FT1);
305 	outb (nec+ds0_imr, 0xff);
306 
307 	ns->ns_if.if_flags |= IFF_RUNNING;
308 	ns->ns_oactive = 0; ns->ns_mask = ~0;
309 	nestart(ifp);
310 	splx(s);
311 }
312 
313 /*
314  * Setup output on interface.
315  * Get another datagram to send off of the interface queue,
316  * and map it to the interface before starting the output.
317  * called only at splimp or interrupt level.
318  */
319 nestart(ifp)
320 	struct ifnet *ifp;
321 {
322 	register struct ne_softc *ns = &ne_softc[ifp->if_unit];
323 	struct mbuf *m0, *m;
324 	int buffer;
325 	int len = 0, i, total,t;
326 
327 	/*
328 	 * The DS8390 has only one transmit buffer, if it is busy we
329 	 * must wait until the transmit interrupt completes.
330 	 */
331 	outb(nec+ds_cmd,DSCM_NODMA|DSCM_START);
332 
333 	if (ns->ns_flags & DSF_LOCK)
334 		return;
335 
336 	if (inb(nec+ds_cmd) & DSCM_TRANS)
337 		return;
338 
339 	if ((ns->ns_if.if_flags & IFF_RUNNING) == 0)
340 		return;
341 
342 	IF_DEQUEUE(&ns->ns_if.if_snd, m);
343 
344 	if (m == 0)
345 		return;
346 
347 	/*
348 	 * Copy the mbuf chain into the transmit buffer
349 	 */
350 
351 	ns->ns_flags |= DSF_LOCK;	/* prevent entering nestart */
352 	buffer = TBUF; len = i = 0;
353 	t = 0;
354 	for (m0 = m; m != 0; m = m->m_next)
355 		t += m->m_len;
356 
357 	m = m0;
358 	total = t;
359 	for (m0 = m; m != 0; ) {
360 
361 		if (m->m_len&1 && t > m->m_len) {
362 			neput(mtod(m, caddr_t), buffer, m->m_len - 1);
363 			t -= m->m_len - 1;
364 			buffer += m->m_len - 1;
365 			m->m_data += m->m_len - 1;
366 			m->m_len = 1;
367 			m = m_pullup(m, 2);
368 		} else {
369 			neput(mtod(m, caddr_t), buffer, m->m_len);
370 			buffer += m->m_len;
371 			t -= m->m_len;
372 			MFREE(m, m0);
373 			m = m0;
374 		}
375 	}
376 
377 	/*
378 	 * Init transmit length registers, and set transmit start flag.
379 	 */
380 
381 	len = total;
382 	if (len < ETHER_MIN_LEN) len = ETHER_MIN_LEN;
383 	outb(nec+ds0_tbcr0,len&0xff);
384 	outb(nec+ds0_tbcr1,(len>>8)&0xff);
385 	outb(nec+ds0_tpsr, TBUF/DS_PGSIZE);
386 	outb(nec+ds_cmd, DSCM_TRANS|DSCM_NODMA|DSCM_START);
387 }
388 
389 /* buffer successor/predecessor in ring? */
390 #define succ(n) (((n)+1 >= RBUFEND/DS_PGSIZE) ? RBUF/DS_PGSIZE : (n)+1)
391 #define pred(n) (((n)-1 < RBUF/DS_PGSIZE) ? RBUFEND/DS_PGSIZE-1 : (n)-1)
392 
393 /*
394  * Controller interrupt.
395  */
396 neintr(unit)
397 {
398 	register struct ne_softc *ns = &ne_softc[unit];
399 	u_char cmd,isr;
400 
401 	/* Save cmd, clear interrupt */
402 	cmd = inb (nec+ds_cmd);
403 loop:
404 	isr = inb (nec+ds0_isr);
405 	outb(nec+ds_cmd,DSCM_NODMA|DSCM_START);
406 	outb(nec+ds0_isr, isr);
407 
408 	/* Receiver error */
409 	if (isr & DSIS_RXE) {
410 		/* need to read these registers to clear status */
411 		(void) inb(nec+ ds0_rsr);
412 		(void) inb(nec+ 0xD);
413 		(void) inb(nec + 0xE);
414 		(void) inb(nec + 0xF);
415 		ns->ns_if.if_ierrors++;
416 	}
417 
418 	/* We received something; rummage thru tiny ring buffer */
419 	if (isr & (DSIS_RX|DSIS_RXE|DSIS_ROVRN)) {
420 		u_char pend,lastfree;
421 
422 		outb(nec+ds_cmd, DSCM_START|DSCM_NODMA|DSCM_PG1);
423 		pend = inb(nec+ds1_curr);
424 		outb(nec+ds_cmd, DSCM_START|DSCM_NODMA|DSCM_PG0);
425 		lastfree = inb(nec+ds0_bnry);
426 
427 		/* Have we wrapped? */
428 		if (lastfree >= RBUFEND/DS_PGSIZE)
429 			lastfree = RBUF/DS_PGSIZE;
430 		if (pend < lastfree && ns->ns_cur < pend)
431 			lastfree = ns->ns_cur;
432 		else	if (ns->ns_cur > lastfree)
433 			lastfree = ns->ns_cur;
434 
435 		/* Something in the buffer? */
436 		while (pend != lastfree) {
437 			u_char nxt;
438 
439 			/* Extract header from microcephalic board */
440 			nefetch(&ns->ns_ph,lastfree*DS_PGSIZE,
441 				sizeof(ns->ns_ph));
442 			ns->ns_ba = lastfree*DS_PGSIZE+sizeof(ns->ns_ph);
443 
444 			/* Incipient paranoia */
445 			if (ns->ns_ph.pr_status == DSRS_RPC ||
446 				/* for dequna's */
447 				ns->ns_ph.pr_status == 0x21)
448 				nerecv (ns);
449 #ifdef NEDEBUG
450 			else  {
451 				printf("cur %x pnd %x lfr %x ",
452 					ns->ns_cur, pend, lastfree);
453 				printf("nxt %x len %x ", ns->ns_ph.pr_nxtpg,
454 					(ns->ns_ph.pr_sz1<<8)+ ns->ns_ph.pr_sz0);
455 				printf("Bogus Sts %x\n", ns->ns_ph.pr_status);
456 			}
457 #endif
458 
459 			nxt = ns->ns_ph.pr_nxtpg ;
460 
461 			/* Sanity check */
462 			if ( nxt >= RBUF/DS_PGSIZE && nxt <= RBUFEND/DS_PGSIZE
463 				&& nxt <= pend)
464 				ns->ns_cur = nxt;
465 			else	ns->ns_cur = nxt = pend;
466 
467 			/* Set the boundaries */
468 			lastfree = nxt;
469 			outb(nec+ds0_bnry, pred(nxt));
470 			outb(nec+ds_cmd, DSCM_START|DSCM_NODMA|DSCM_PG1);
471 			pend = inb(nec+ds1_curr);
472 			outb(nec+ds_cmd, DSCM_START|DSCM_NODMA|DSCM_PG0);
473 		}
474 		outb(nec+ds_cmd, DSCM_START|DSCM_NODMA);
475 	}
476 
477 	/* Transmit error */
478 	if (isr & DSIS_TXE) {
479 		ns->ns_flags &= ~DSF_LOCK;
480 		/* Need to read these registers to clear status */
481 		ns->ns_if.if_collisions += inb(nec+ds0_tbcr0);
482 		ns->ns_if.if_oerrors++;
483 	}
484 
485 	/* Packet Transmitted */
486 	if (isr & DSIS_TX) {
487 		ns->ns_flags &= ~DSF_LOCK;
488 		++ns->ns_if.if_opackets;
489 		ns->ns_if.if_collisions += inb(nec+ds0_tbcr0);
490 	}
491 
492 	/* Receiver ovverun? */
493 	if (isr & DSIS_ROVRN) {
494 		log(LOG_ERR, "ne%d: error: isr %x\n", ns-ne_softc, isr
495 			/*, DSIS_BITS*/);
496 		outb(nec+ds0_rbcr0, 0);
497 		outb(nec+ds0_rbcr1, 0);
498 		outb(nec+ds0_tcr, DSTC_LB0);
499 		outb(nec+ds0_rcr, DSRC_MON);
500 		outb(nec+ds_cmd, DSCM_START|DSCM_NODMA);
501 		outb(nec+ds0_rcr, DSRC_AB);
502 		outb(nec+ds0_tcr, 0);
503 	}
504 
505 	/* Any more to send? */
506 	outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START);
507 	nestart(&ns->ns_if);
508 	outb (nec+ds_cmd, cmd);
509 	outb (nec+ds0_imr, 0xff);
510 
511 	/* Still more to do? */
512 	isr = inb (nec+ds0_isr);
513 	if(isr) goto loop;
514 }
515 
516 /*
517  * Ethernet interface receiver interface.
518  * If input error just drop packet.
519  * Otherwise examine packet to determine type.  If can't determine length
520  * from type, then have to drop packet.  Othewise decapsulate
521  * packet based on type and pass to type specific higher-level
522  * input routine.
523  */
524 nerecv(ns)
525 	register struct ne_softc *ns;
526 {
527 	int len,i;
528 
529 	ns->ns_if.if_ipackets++;
530 	len = ns->ns_ph.pr_sz0 + (ns->ns_ph.pr_sz1<<8);
531 	if(len < ETHER_MIN_LEN || len > ETHER_MAX_LEN)
532 		return;
533 
534 	/* this need not be so torturous - one/two bcopys at most into mbufs */
535 	nefetch(ns->ns_pb, ns->ns_ba, min(len,DS_PGSIZE-sizeof(ns->ns_ph)));
536 	if (len > DS_PGSIZE-sizeof(ns->ns_ph)) {
537 		int l = len - (DS_PGSIZE-sizeof(ns->ns_ph)), b ;
538 		u_char *p = ns->ns_pb + (DS_PGSIZE-sizeof(ns->ns_ph));
539 
540 		if(++ns->ns_cur > 0x7f) ns->ns_cur = 0x46;
541 		b = ns->ns_cur*DS_PGSIZE;
542 
543 		while (l >= DS_PGSIZE) {
544 			nefetch(p, b, DS_PGSIZE);
545 			p += DS_PGSIZE; l -= DS_PGSIZE;
546 			if(++ns->ns_cur > 0x7f) ns->ns_cur = 0x46;
547 			b = ns->ns_cur*DS_PGSIZE;
548 		}
549 		if (l > 0)
550 			nefetch(p, b, l);
551 	}
552 	/* don't forget checksum! */
553 	len -= sizeof(struct ether_header) + sizeof(long);
554 
555 	neread(ns,(caddr_t)(ns->ns_pb), len);
556 }
557 
558 /*
559  * Pass a packet to the higher levels.
560  * We deal with the trailer protocol here.
561  */
562 neread(ns, buf, len)
563 	register struct ne_softc *ns;
564 	char *buf;
565 	int len;
566 {
567 	register struct ether_header *eh;
568     	struct mbuf *m;
569 	int off, resid;
570 	register struct ifqueue *inq;
571 
572 	/*
573 	 * Deal with trailer protocol: if type is trailer type
574 	 * get true type from first 16-bit word past data.
575 	 * Remember that type was trailer by setting off.
576 	 */
577 	eh = (struct ether_header *)buf;
578 	eh->ether_type = ntohs((u_short)eh->ether_type);
579 #define	nedataaddr(eh, off, type)	((type)(((caddr_t)((eh)+1)+(off))))
580 	if (eh->ether_type >= ETHERTYPE_TRAIL &&
581 	    eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
582 		off = (eh->ether_type - ETHERTYPE_TRAIL) * 512;
583 		if (off >= ETHERMTU) return;		/* sanity */
584 		eh->ether_type = ntohs(*nedataaddr(eh, off, u_short *));
585 		resid = ntohs(*(nedataaddr(eh, off+2, u_short *)));
586 		if (off + resid > len) return;		/* sanity */
587 		len = off + resid;
588 	} else	off = 0;
589 
590 	if (len == 0) return;
591 
592 	/*
593 	 * Pull packet off interface.  Off is nonzero if packet
594 	 * has trailing header; neget will then force this header
595 	 * information to be at the front, but we still have to drop
596 	 * the type and length which are at the front of any trailer data.
597 	 */
598 	m = neget(buf, len, off, &ns->ns_if);
599 	if (m == 0) return;
600 
601 	ether_input(&ns->ns_if, eh, m);
602 }
603 
604 /*
605  * Supporting routines
606  */
607 
608 /*
609  * Pull read data off a interface.
610  * Len is length of data, with local net header stripped.
611  * Off is non-zero if a trailer protocol was used, and
612  * gives the offset of the trailer information.
613  * We copy the trailer information and then all the normal
614  * data into mbufs.  When full cluster sized units are present
615  * we copy into clusters.
616  */
617 struct mbuf *
618 neget(buf, totlen, off0, ifp)
619 	caddr_t buf;
620 	int totlen, off0;
621 	struct ifnet *ifp;
622 {
623 	struct mbuf *top, **mp, *m, *p;
624 	int off = off0, len;
625 	register caddr_t cp = buf;
626 	char *epkt;
627 
628 	buf += sizeof(struct ether_header);
629 	cp = buf;
630 	epkt = cp + totlen;
631 
632 
633 	if (off) {
634 		cp += off + 2 * sizeof(u_short);
635 		totlen -= 2 * sizeof(u_short);
636 	}
637 
638 	MGETHDR(m, M_DONTWAIT, MT_DATA);
639 	if (m == 0)
640 		return (0);
641 	m->m_pkthdr.rcvif = ifp;
642 	m->m_pkthdr.len = totlen;
643 	m->m_len = MHLEN;
644 
645 	top = 0;
646 	mp = &top;
647 	while (totlen > 0) {
648 		if (top) {
649 			MGET(m, M_DONTWAIT, MT_DATA);
650 			if (m == 0) {
651 				m_freem(top);
652 				return (0);
653 			}
654 			m->m_len = MLEN;
655 		}
656 		len = min(totlen, epkt - cp);
657 		if (len >= MINCLSIZE) {
658 			MCLGET(m, M_DONTWAIT);
659 			if (m->m_flags & M_EXT)
660 				m->m_len = len = min(len, MCLBYTES);
661 			else
662 				len = m->m_len;
663 		} else {
664 			/*
665 			 * Place initial small packet/header at end of mbuf.
666 			 */
667 			if (len < m->m_len) {
668 				if (top == 0 && len + max_linkhdr <= m->m_len)
669 					m->m_data += max_linkhdr;
670 				m->m_len = len;
671 			} else
672 				len = m->m_len;
673 		}
674 		bcopy(cp, mtod(m, caddr_t), (unsigned)len);
675 		cp += len;
676 		*mp = m;
677 		mp = &m->m_next;
678 		totlen -= len;
679 		if (cp == epkt)
680 			cp = buf;
681 	}
682 	return (top);
683 }
684 
685 /*
686  * Process an ioctl request.
687  */
688 neioctl(ifp, cmd, data)
689 	register struct ifnet *ifp;
690 	int cmd;
691 	caddr_t data;
692 {
693 	register struct ifaddr *ifa = (struct ifaddr *)data;
694 	struct ne_softc *ns = &ne_softc[ifp->if_unit];
695 	struct ifreq *ifr = (struct ifreq *)data;
696 	int s = splimp(), error = 0;
697 
698 
699 	switch (cmd) {
700 
701 	case SIOCSIFADDR:
702 		ifp->if_flags |= IFF_UP;
703 
704 		switch (ifa->ifa_addr->sa_family) {
705 #ifdef INET
706 		case AF_INET:
707 			neinit(ifp->if_unit);	/* before arpwhohas */
708 			((struct arpcom *)ifp)->ac_ipaddr =
709 				IA_SIN(ifa)->sin_addr;
710 			arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
711 			break;
712 #endif
713 #ifdef NS
714 		case AF_NS:
715 		    {
716 			register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
717 
718 			if (ns_nullhost(*ina))
719 				ina->x_host = *(union ns_host *)(ns->ns_addr);
720 			else {
721 				/*
722 				 * The manual says we can't change the address
723 				 * while the receiver is armed,
724 				 * so reset everything
725 				 */
726 				ifp->if_flags &= ~IFF_RUNNING;
727 				bcopy((caddr_t)ina->x_host.c_host,
728 				    (caddr_t)ns->ns_addr, sizeof(ns->ns_addr));
729 			}
730 			neinit(ifp->if_unit); /* does ne_setaddr() */
731 			break;
732 		    }
733 #endif
734 		default:
735 			neinit(ifp->if_unit);
736 			break;
737 		}
738 		break;
739 
740 	case SIOCSIFFLAGS:
741 		if ((ifp->if_flags & IFF_UP) == 0 &&
742 		    ifp->if_flags & IFF_RUNNING) {
743 			ifp->if_flags &= ~IFF_RUNNING;
744 			outb(nec+ds_cmd,DSCM_STOP|DSCM_NODMA);
745 		} else if (ifp->if_flags & IFF_UP &&
746 		    (ifp->if_flags & IFF_RUNNING) == 0)
747 			neinit(ifp->if_unit);
748 		break;
749 
750 #ifdef notdef
751 	case SIOCGHWADDR:
752 		bcopy((caddr_t)ns->ns_addr, (caddr_t) &ifr->ifr_data,
753 			sizeof(ns->ns_addr));
754 		break;
755 #endif
756 
757 	default:
758 		error = EINVAL;
759 	}
760 	splx(s);
761 	return (error);
762 }
763 #endif
764