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