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