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