cleaning pass, removed dead code, updated comments, found boners
[unix-history] / usr / src / sys / i386 / isa / if_ne.c
CommitLineData
93b2b8c5
BJ
1#include "ne.h"
2#if NNE > 0
d0d290ad 3/*-
93b2b8c5 4 * NE2000 Ethernet driver
d0d290ad
WN
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 *
187497c9 11 * @(#)if_ne.c 7.2 (Berkeley) %G%
93b2b8c5
BJ
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
d0d290ad
WN
27#include "net/if.h"
28#include "net/netisr.h"
29#include "net/route.h"
93b2b8c5
BJ
30
31#ifdef INET
d0d290ad
WN
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"
93b2b8c5
BJ
37#endif
38
39#ifdef NS
d0d290ad
WN
40#include "netns/ns.h"
41#include "netns/ns_if.h"
93b2b8c5
BJ
42#endif
43
d0d290ad
WN
44#include "i386/isa/isa_device.h"
45#include "i386/isa/if_nereg.h"
46#include "i386/isa/icu.h"
93b2b8c5
BJ
47
48int neprobe(), neattach(), neintr();
d0d290ad 49int nestart(),neinit(), ether_output(), neioctl();
93b2b8c5 50
c6b0f337 51struct isa_driver nedriver = {
93b2b8c5
BJ
52 neprobe, neattach, "ne",
53};
54
93b2b8c5
BJ
55struct 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 */
64struct 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] ;
187497c9 78#define ENBUFSIZE (sizeof(struct ether_header) + ETHERMTU + 2 + ETHER_MIN_LEN)
93b2b8c5
BJ
79
80int nec;
81
82u_short boarddata[16];
83
84neprobe(dvp)
c6b0f337 85 struct isa_device *dvp;
93b2b8c5
BJ
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
c6b0f337 94 nec = dvp->id_iobase;
93b2b8c5
BJ
95 s = splimp();
96
187497c9 97 /* Reset the bastard */
93b2b8c5
BJ
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);
c6b0f337
BJ
103
104 i = 1000000;
d0d290ad 105 while ((inb(nec+ds0_isr)&DSIS_RESET) == 0 && i-- > 0);
c6b0f337
BJ
106 if (i < 0) return (0);
107
93b2b8c5
BJ
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);
c6b0f337
BJ
114 DELAY(10000);
115
187497c9 116 /* Check cmd reg and fail if not right */
c6b0f337
BJ
117 if ((i=inb(nec+ds_cmd)) != (DSCM_NODMA|DSCM_PG0|DSCM_STOP))
118 return(0);
119
93b2b8c5
BJ
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);
187497c9 130
c6b0f337 131#ifdef NEDEBUG
187497c9
WN
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);
93b2b8c5 156 }
187497c9 157 printf("\n");
93b2b8c5 158 }
c6b0f337 159#endif
187497c9
WN
160
161 /* Extract board address */
162 nefetch ((caddr_t)boarddata, 0, sizeof(boarddata));
93b2b8c5 163 for(i=0; i < 6; i++) ns->ns_addr[i] = boarddata[i];
93b2b8c5
BJ
164 splx(s);
165 return (1);
166}
167
187497c9
WN
168/*
169 * Fetch from onboard ROM/RAM
170 */
171nefetch (up, ad, len) caddr_t up; {
93b2b8c5
BJ
172 u_char cmd;
173
174 cmd = inb(nec+ds_cmd);
175 outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START);
187497c9
WN
176
177 /* Setup remote dma */
93b2b8c5 178 outb (nec+ds0_isr, DSIS_RDC);
187497c9
WN
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 */
93b2b8c5
BJ
185 outb (nec+ds_cmd, DSCM_RREAD|DSCM_PG0|DSCM_START);
186 insw (nec+ne_data, up, len/2);
187497c9
WN
187
188 /* Wait till done, then shutdown feature */
189 while ((inb (nec+ds0_isr) & DSIS_RDC) == 0) ;
93b2b8c5
BJ
190 outb (nec+ds0_isr, DSIS_RDC);
191 outb (nec+ds_cmd, cmd);
192}
193
187497c9
WN
194/*
195 * Put to onboard RAM
196 */
197neput (up, ad, len) caddr_t up; {
93b2b8c5
BJ
198 u_char cmd;
199
200 cmd = inb(nec+ds_cmd);
201 outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START);
187497c9
WN
202
203 /* Setup for remote dma */
93b2b8c5 204 outb (nec+ds0_isr, DSIS_RDC);
187497c9
WN
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 */
93b2b8c5
BJ
212 outb (nec+ds_cmd, DSCM_RWRITE|DSCM_PG0|DSCM_START);
213 outsw (nec+ne_data, up, len/2);
187497c9
WN
214
215 /* Wait till done, then shutdown feature */
216 while ((inb (nec+ds0_isr) & DSIS_RDC) == 0) ;
93b2b8c5
BJ
217 outb (nec+ds0_isr, DSIS_RDC);
218 outb (nec+ds_cmd, cmd);
219}
220
221/*
222 * Reset of interface.
223 */
224nereset(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 */
239neattach(dvp)
c6b0f337 240 struct isa_device *dvp;
93b2b8c5 241{
c6b0f337 242 int unit = dvp->id_unit;
93b2b8c5
BJ
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;
e243739b 249 printf (" ethernet address %s", ether_sprintf(ns->ns_addr)) ;
d0d290ad 250 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
93b2b8c5 251 ifp->if_init = neinit;
d0d290ad
WN
252 ifp->if_output = ether_output;
253 ifp->if_start = nestart;
93b2b8c5
BJ
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 */
264neinit(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);
187497c9 290
93b2b8c5
BJ
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);
c67ce870 298 outb(nec+ds0_bnry, RBUF/DS_PGSIZE);
93b2b8c5
BJ
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;
d0d290ad 309 nestart(ifp);
93b2b8c5
BJ
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 */
d0d290ad
WN
319nestart(ifp)
320 struct ifnet *ifp;
93b2b8c5 321{
d0d290ad 322 register struct ne_softc *ns = &ne_softc[ifp->if_unit];
93b2b8c5
BJ
323 struct mbuf *m0, *m;
324 int buffer;
d0d290ad 325 int len = 0, i, total,t;
93b2b8c5
BJ
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
c6b0f337
BJ
333 if (ns->ns_flags & DSF_LOCK)
334 return;
335
93b2b8c5
BJ
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
c6b0f337 351 ns->ns_flags |= DSF_LOCK; /* prevent entering nestart */
93b2b8c5 352 buffer = TBUF; len = i = 0;
d0d290ad 353 t = 0;
187497c9 354 for (m0 = m; m != 0; m = m->m_next)
d0d290ad 355 t += m->m_len;
d0d290ad
WN
356
357 m = m0;
358 total = t;
d0d290ad
WN
359 for (m0 = m; m != 0; ) {
360
d0d290ad 361 if (m->m_len&1 && t > m->m_len) {
187497c9 362 neput(mtod(m, caddr_t), buffer, m->m_len - 1);
d0d290ad
WN
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);
d0d290ad 368 } else {
187497c9 369 neput(mtod(m, caddr_t), buffer, m->m_len);
d0d290ad
WN
370 buffer += m->m_len;
371 t -= m->m_len;
372 MFREE(m, m0);
373 m = m0;
374 }
93b2b8c5 375 }
93b2b8c5
BJ
376
377 /*
378 * Init transmit length registers, and set transmit start flag.
379 */
380
d0d290ad 381 len = total;
187497c9 382 if (len < ETHER_MIN_LEN) len = ETHER_MIN_LEN;
93b2b8c5
BJ
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
187497c9 389/* buffer successor/predecessor in ring? */
c67ce870
BJ
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)
187497c9 392
93b2b8c5
BJ
393/*
394 * Controller interrupt.
395 */
d0d290ad 396neintr(unit)
93b2b8c5 397{
d0d290ad 398 register struct ne_softc *ns = &ne_softc[unit];
93b2b8c5
BJ
399 u_char cmd,isr;
400
187497c9 401 /* Save cmd, clear interrupt */
93b2b8c5 402 cmd = inb (nec+ds_cmd);
c6b0f337 403loop:
93b2b8c5 404 isr = inb (nec+ds0_isr);
c6b0f337 405 outb(nec+ds_cmd,DSCM_NODMA|DSCM_START);
c67ce870 406 outb(nec+ds0_isr, isr);
93b2b8c5 407
187497c9 408 /* Receiver error */
93b2b8c5
BJ
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
187497c9 418 /* We received something; rummage thru tiny ring buffer */
c67ce870 419 if (isr & (DSIS_RX|DSIS_RXE|DSIS_ROVRN)) {
93b2b8c5
BJ
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);
187497c9
WN
426
427 /* Have we wrapped? */
c67ce870 428 if (lastfree >= RBUFEND/DS_PGSIZE)
93b2b8c5 429 lastfree = RBUF/DS_PGSIZE;
c67ce870
BJ
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
187497c9 435 /* Something in the buffer? */
c67ce870 436 while (pend != lastfree) {
93b2b8c5
BJ
437 u_char nxt;
438
187497c9
WN
439 /* Extract header from microcephalic board */
440 nefetch(&ns->ns_ph,lastfree*DS_PGSIZE,
c67ce870
BJ
441 sizeof(ns->ns_ph));
442 ns->ns_ba = lastfree*DS_PGSIZE+sizeof(ns->ns_ph);
93b2b8c5 443
187497c9 444 /* Incipient paranoia */
c6b0f337 445 if (ns->ns_ph.pr_status == DSRS_RPC ||
187497c9 446 /* for dequna's */
c6b0f337 447 ns->ns_ph.pr_status == 0x21)
93b2b8c5 448 nerecv (ns);
c6b0f337
BJ
449#ifdef NEDEBUG
450 else {
187497c9
WN
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);
c6b0f337
BJ
456 }
457#endif
93b2b8c5
BJ
458
459 nxt = ns->ns_ph.pr_nxtpg ;
187497c9
WN
460
461 /* Sanity check */
462 if ( nxt >= RBUF/DS_PGSIZE && nxt <= RBUFEND/DS_PGSIZE
463 && nxt <= pend)
93b2b8c5
BJ
464 ns->ns_cur = nxt;
465 else ns->ns_cur = nxt = pend;
187497c9
WN
466
467 /* Set the boundaries */
c67ce870
BJ
468 lastfree = nxt;
469 outb(nec+ds0_bnry, pred(nxt));
470 outb(nec+ds_cmd, DSCM_START|DSCM_NODMA|DSCM_PG1);
c6b0f337 471 pend = inb(nec+ds1_curr);
c67ce870 472 outb(nec+ds_cmd, DSCM_START|DSCM_NODMA|DSCM_PG0);
187497c9 473 }
93b2b8c5 474 outb(nec+ds_cmd, DSCM_START|DSCM_NODMA);
93b2b8c5 475 }
187497c9
WN
476
477 /* Transmit error */
93b2b8c5 478 if (isr & DSIS_TXE) {
c67ce870 479 ns->ns_flags &= ~DSF_LOCK;
187497c9 480 /* Need to read these registers to clear status */
93b2b8c5
BJ
481 ns->ns_if.if_collisions += inb(nec+ds0_tbcr0);
482 ns->ns_if.if_oerrors++;
483 }
187497c9
WN
484
485 /* Packet Transmitted */
c6b0f337 486 if (isr & DSIS_TX) {
c67ce870 487 ns->ns_flags &= ~DSF_LOCK;
93b2b8c5 488 ++ns->ns_if.if_opackets;
c67ce870
BJ
489 ns->ns_if.if_collisions += inb(nec+ds0_tbcr0);
490 }
491
187497c9 492 /* Receiver ovverun? */
c67ce870 493 if (isr & DSIS_ROVRN) {
187497c9
WN
494 log(LOG_ERR, "ne%d: error: isr %x\n", ns-ne_softc, isr
495 /*, DSIS_BITS*/);
c67ce870
BJ
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);
93b2b8c5 503 }
c6b0f337 504
187497c9 505 /* Any more to send? */
93b2b8c5 506 outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START);
d0d290ad 507 nestart(&ns->ns_if);
c6b0f337 508 outb (nec+ds_cmd, cmd);
93b2b8c5 509 outb (nec+ds0_imr, 0xff);
187497c9
WN
510
511 /* Still more to do? */
c6b0f337
BJ
512 isr = inb (nec+ds0_isr);
513 if(isr) goto loop;
93b2b8c5
BJ
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 */
524nerecv(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);
187497c9
WN
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)) {
93b2b8c5
BJ
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
93b2b8c5
BJ
540 if(++ns->ns_cur > 0x7f) ns->ns_cur = 0x46;
541 b = ns->ns_cur*DS_PGSIZE;
542
543 while (l >= DS_PGSIZE) {
187497c9 544 nefetch(p, b, DS_PGSIZE);
93b2b8c5 545 p += DS_PGSIZE; l -= DS_PGSIZE;
187497c9
WN
546 if(++ns->ns_cur > 0x7f) ns->ns_cur = 0x46;
547 b = ns->ns_cur*DS_PGSIZE;
93b2b8c5 548 }
93b2b8c5 549 if (l > 0)
187497c9 550 nefetch(p, b, l);
93b2b8c5 551 }
187497c9
WN
552 /* don't forget checksum! */
553 len -= sizeof(struct ether_header) + sizeof(long);
93b2b8c5 554
93b2b8c5
BJ
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 */
562neread(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
d0d290ad 601 ether_input(&ns->ns_if, eh, m);
93b2b8c5
BJ
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 */
617struct mbuf *
618neget(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;
d0d290ad
WN
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;
93b2b8c5 644
93b2b8c5
BJ
645 top = 0;
646 mp = &top;
647 while (totlen > 0) {
d0d290ad
WN
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);
93b2b8c5 661 else
d0d290ad 662 len = m->m_len;
93b2b8c5 663 } else {
93b2b8c5 664 /*
d0d290ad 665 * Place initial small packet/header at end of mbuf.
93b2b8c5 666 */
d0d290ad
WN
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;
93b2b8c5 673 }
d0d290ad
WN
674 bcopy(cp, mtod(m, caddr_t), (unsigned)len);
675 cp += len;
93b2b8c5
BJ
676 *mp = m;
677 mp = &m->m_next;
d0d290ad
WN
678 totlen -= len;
679 if (cp == epkt)
680 cp = buf;
93b2b8c5
BJ
681 }
682 return (top);
93b2b8c5
BJ
683}
684
685/*
686 * Process an ioctl request.
687 */
688neioctl(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
d0d290ad 704 switch (ifa->ifa_addr->sa_family) {
93b2b8c5
BJ
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}
93b2b8c5 763#endif