various bugs fixed, works on local enet
[unix-history] / usr / src / sys / i386 / isa / if_ne.c
CommitLineData
93b2b8c5
BJ
1#include "ne.h"
2#if NNE > 0
3/*
4 * NE2000 Ethernet driver
5 * Copyright (C) 1990 W. Jolitz
c6b0f337 6 * @(#)if_ne.c 1.2 (Berkeley) %G%
93b2b8c5
BJ
7 *
8 * Parts inspired from Tim Tucker's if_wd driver for the wd8003,
9 * insight on the ne2000 gained from Robert Clements PC/FTP driver.
10 */
11
12#include "param.h"
13#include "systm.h"
14#include "mbuf.h"
15#include "buf.h"
16#include "protosw.h"
17#include "socket.h"
18#include "ioctl.h"
19#include "errno.h"
20#include "syslog.h"
21
22#include "../net/if.h"
23#include "../net/netisr.h"
24#include "../net/route.h"
25
26#ifdef INET
27#include "../netinet/in.h"
28#include "../netinet/in_systm.h"
29#include "../netinet/in_var.h"
30#include "../netinet/ip.h"
31#include "../netinet/if_ether.h"
32#endif
33
34#ifdef NS
35#include "../netns/ns.h"
36#include "../netns/ns_if.h"
37#endif
38
c6b0f337 39#include "machine/isa/device.h"
93b2b8c5
BJ
40#include "if_nereg.h"
41#include "icu.h"
42
43int neprobe(), neattach(), neintr();
44int neinit(), neoutput(), neioctl();
45
c6b0f337
BJ
46#include "dbg.h"
47struct isa_driver nedriver = {
93b2b8c5
BJ
48 neprobe, neattach, "ne",
49};
50
93b2b8c5
BJ
51struct mbuf *neget();
52
53/*
54 * Ethernet software status per interface.
55 *
56 * Each interface is referenced by a network interface structure,
57 * ns_if, which the routing code uses to locate the interface.
58 * This structure contains the output queue for the interface, its address, ...
59 */
60struct ne_softc {
61 struct arpcom ns_ac; /* Ethernet common part */
62#define ns_if ns_ac.ac_if /* network-visible interface */
63#define ns_addr ns_ac.ac_enaddr /* hardware Ethernet address */
64 int ns_flags;
65#define DSF_LOCK 1 /* block re-entering enstart */
66 int ns_oactive ;
67 int ns_mask ;
68 int ns_ba; /* byte addr in buffer ram of inc pkt */
69 int ns_cur; /* current page being filled */
70 struct prhdr ns_ph; /* hardware header of incoming packet*/
71 struct ether_header ns_eh; /* header of incoming packet */
72 u_char ns_pb[2048 /*ETHERMTU+sizeof(long)*/];
73} ne_softc[NNE] ;
74#define ENBUFSIZE (sizeof(struct ether_header) + ETHERMTU + 2 + 64)
75
76int nec;
77
78u_short boarddata[16];
79
80neprobe(dvp)
c6b0f337 81 struct isa_device *dvp;
93b2b8c5
BJ
82{
83 int val,i,s;
84 register struct ne_softc *ns = &ne_softc[0];
85
86#ifdef lint
87 neintr(0);
88#endif
89
c6b0f337 90 nec = dvp->id_iobase;
93b2b8c5
BJ
91 s = splimp();
92
93 /* reset the bastard */
94 val = inb(nec+ne_reset);
95 DELAY(2000000);
96 outb(nec+ne_reset,val);
97
98 outb(nec+ds_cmd, DSCM_STOP|DSCM_NODMA);
c6b0f337
BJ
99
100 i = 1000000;
101 while ((inb(nec+ds0_isr)&DSIS_RESET) == 0 && i-- > 0) nulldev();
102 if (i < 0) return (0);
103
93b2b8c5
BJ
104 outb(nec+ds0_isr, 0xff);
105
106 /* Word Transfers, Burst Mode Select, Fifo at 8 bytes */
107 outb(nec+ds0_dcr, DSDC_WTS|DSDC_BMS|DSDC_FT1);
108
109 outb(nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_STOP);
c6b0f337
BJ
110 DELAY(10000);
111
112 /* check cmd reg and fail if not right */
113 if ((i=inb(nec+ds_cmd)) != (DSCM_NODMA|DSCM_PG0|DSCM_STOP))
114 return(0);
115
93b2b8c5
BJ
116 outb(nec+ds0_tcr, 0);
117 outb(nec+ds0_rcr, DSRC_MON);
118 outb(nec+ds0_pstart, RBUF/DS_PGSIZE);
119 outb(nec+ds0_pstop, RBUFEND/DS_PGSIZE);
120 outb(nec+ds0_bnry, RBUFEND/DS_PGSIZE);
121 outb(nec+ds0_imr, 0);
122 outb(nec+ds0_isr, 0);
123 outb(nec+ds_cmd, DSCM_NODMA|DSCM_PG1|DSCM_STOP);
124 outb(nec+ds1_curr, RBUF/DS_PGSIZE);
125 outb(nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_STOP);
126 fetchrom (boarddata, 0, sizeof(boarddata));
c6b0f337 127#ifdef NEDEBUG
93b2b8c5
BJ
128/*{ int i,rom;
129 rom=1;
130printf("ne ram ");
131 for (i = 0; i < 0xfff0; i+=4) {
132 int pat;
133 pat = 0xa55a+i*37;
134 putram(&pat,i,4);
135 fetchram(&pat,i,4);
136 if (pat == 0xa55a+i*37) {
137 if (rom) { rom=0; printf(" %x", i); }
138 } else {
139 if (!rom) { rom=1; printf("..%x ", i); }
140 }
141 pat=0;
142 putram(&pat,i,4);
143 }
144printf("\n");
145}*/
c6b0f337 146#endif
93b2b8c5
BJ
147/* checksum data? */
148 /* extract board address */
149 for(i=0; i < 6; i++) ns->ns_addr[i] = boarddata[i];
93b2b8c5
BJ
150 splx(s);
151 return (1);
152}
153
154fetchrom (up, ad, len) u_short *up; {
155 u_char cmd;
156
157 cmd = inb(nec+ds_cmd);
158 outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_STOP);
159 outb (nec+ds0_isr, DSIS_RDC);
160 outb (nec+ds0_rbcr0, len&0xff);
161 outb (nec+ds0_rbcr1, (len>>8)&0xff);
162 outb (nec+ds0_rsar0, ad&0xff);
163 outb (nec+ds0_rsar1, (ad>>8)&0xff);
164 outb (nec+ds_cmd, DSCM_RREAD|DSCM_PG0|DSCM_START);
165 insw (nec+ne_data, up, len/2);
c6b0f337
BJ
166 pausestr ("x",1);
167 while ((inb (nec+ds0_isr) & DSIS_RDC) == 0) pausestr("fetchrom",0);
93b2b8c5
BJ
168 outb (nec+ds0_isr, DSIS_RDC);
169 outb (nec+ds_cmd, cmd);
170}
171
c6b0f337 172static recur;
93b2b8c5
BJ
173fetchram (up, ad, len) caddr_t up; {
174 u_char cmd;
175
c6b0f337 176 recur++;
93b2b8c5
BJ
177 cmd = inb(nec+ds_cmd);
178 outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START);
179 outb (nec+ds0_isr, DSIS_RDC);
180 outb (nec+ds0_rbcr0, len&0xff);
181 outb (nec+ds0_rbcr1, (len>>8)&0xff);
182 outb (nec+ds0_rsar0, ad&0xff);
183 outb (nec+ds0_rsar1, (ad>>8)&0xff);
184 outb (nec+ds_cmd, DSCM_RREAD|DSCM_PG0|DSCM_START);
185 insw (nec+ne_data, up, len/2);
c6b0f337
BJ
186 pausestr ("x",1);
187 while ((inb (nec+ds0_isr) & DSIS_RDC) == 0) pausestr("fetchram",0);
93b2b8c5
BJ
188 outb (nec+ds0_isr, DSIS_RDC);
189 outb (nec+ds_cmd, cmd);
c6b0f337 190 recur--;
93b2b8c5
BJ
191}
192
193putram (up, ad, len) caddr_t up; {
194 u_char cmd;
195
c6b0f337 196 recur++;
93b2b8c5
BJ
197 cmd = inb(nec+ds_cmd);
198 outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START);
199 outb (nec+ds0_isr, DSIS_RDC);
200 if(len&1) len++;
201 outb (nec+ds0_rbcr0, len&0xff);
202 outb (nec+ds0_rbcr1, (len>>8)&0xff);
203 outb (nec+ds0_rsar0, ad&0xff);
204 outb (nec+ds0_rsar1, (ad>>8)&0xff);
205 outb (nec+ds_cmd, DSCM_RWRITE|DSCM_PG0|DSCM_START);
206 outsw (nec+ne_data, up, len/2);
c6b0f337
BJ
207 pausestr ("x",1);
208 while ((inb (nec+ds0_isr) & DSIS_RDC) == 0)
209 if(pausestr("putram",0)<0) break;
93b2b8c5
BJ
210 outb (nec+ds0_isr, DSIS_RDC);
211 outb (nec+ds_cmd, cmd);
c6b0f337 212 recur--;
93b2b8c5
BJ
213}
214
215/*
216 * Reset of interface.
217 */
218nereset(unit, uban)
219 int unit, uban;
220{
221 if (unit >= NNE)
222 return;
223 printf("ne%d: reset\n", unit);
224 ne_softc[unit].ns_flags &= ~DSF_LOCK;
225 neinit(unit);
226}
227
228/*
229 * Interface exists: make available by filling in network interface
230 * record. System will initialize the interface when it is ready
231 * to accept packets. We get the ethernet address here.
232 */
233neattach(dvp)
c6b0f337 234 struct isa_device *dvp;
93b2b8c5 235{
c6b0f337 236 int unit = dvp->id_unit;
93b2b8c5
BJ
237 register struct ne_softc *ns = &ne_softc[unit];
238 register struct ifnet *ifp = &ns->ns_if;
239
240 ifp->if_unit = unit;
241 ifp->if_name = nedriver.name ;
242 ifp->if_mtu = ETHERMTU;
243 printf (" physical address %s", ether_sprintf(ns->ns_addr)) ;
244 ifp->if_flags = IFF_BROADCAST|IFF_NOTRAILERS;
245 ifp->if_init = neinit;
246 ifp->if_output = neoutput;
247 ifp->if_ioctl = neioctl;
248 ifp->if_reset = nereset;
249 ifp->if_watchdog = 0;
250 if_attach(ifp);
251}
252
253/*
254 * Initialization of interface; set up initialization block
255 * and transmit/receive descriptor rings.
256 */
257neinit(unit)
258 int unit;
259{
260 register struct ne_softc *ns = &ne_softc[unit];
261 struct ifnet *ifp = &ns->ns_if;
262 int s;
263 register i; char *cp;
264
265 if (ifp->if_addrlist == (struct ifaddr *)0) return;
266 if (ifp->if_flags & IFF_RUNNING) return;
267
268 s = splimp();
269
270 /* set physical address on ethernet */
271 outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG1|DSCM_STOP);
272 for (i=0 ; i < 6 ; i++) outb(nec+ds1_par0+i,ns->ns_addr[i]);
273
274 /* clr logical address hash filter for now */
275 for (i=0 ; i < 8 ; i++) outb(nec+ds1_mar0+i,0xff);
276
277 /* init regs */
278 outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_STOP);
279 outb (nec+ds0_rbcr0, 0);
280 outb (nec+ds0_rbcr1, 0);
281 outb (nec+ds0_imr, 0);
282 outb (nec+ds0_isr, 0xff);
283 /* Word Transfers, Burst Mode Select, Fifo at 8 bytes */
284 outb(nec+ds0_dcr, DSDC_WTS|DSDC_BMS|DSDC_FT1);
285 outb(nec+ds0_tcr, 0);
286 outb (nec+ds0_rcr, DSRC_MON);
287 outb (nec+ds0_tpsr, 0);
288 outb(nec+ds0_pstart, RBUF/DS_PGSIZE);
289 outb(nec+ds0_pstop, RBUFEND/DS_PGSIZE);
290 outb(nec+ds0_bnry, RBUFEND/DS_PGSIZE);
291 outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG1|DSCM_STOP);
292 outb(nec+ds1_curr, RBUF/DS_PGSIZE);
293 ns->ns_cur = RBUF/DS_PGSIZE;
294 outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START);
295 outb (nec+ds0_rcr, DSRC_AB);
296 outb(nec+ds0_dcr, DSDC_WTS|DSDC_BMS|DSDC_FT1);
297 outb (nec+ds0_imr, 0xff);
298
299 ns->ns_if.if_flags |= IFF_RUNNING;
300 ns->ns_oactive = 0; ns->ns_mask = ~0;
301 if (ns->ns_if.if_snd.ifq_head) nestart(ns);
302 splx(s);
303}
304
305/*
306 * Setup output on interface.
307 * Get another datagram to send off of the interface queue,
308 * and map it to the interface before starting the output.
309 * called only at splimp or interrupt level.
310 */
311nestart(ns)
312 register struct ne_softc *ns;
313{
314 struct mbuf *m0, *m;
315 int buffer;
316 int len = 0, i;
317
318 /*
319 * The DS8390 has only one transmit buffer, if it is busy we
320 * must wait until the transmit interrupt completes.
321 */
322 outb(nec+ds_cmd,DSCM_NODMA|DSCM_START);
323
c6b0f337
BJ
324 if (ns->ns_flags & DSF_LOCK)
325 return;
326
93b2b8c5
BJ
327 if (inb(nec+ds_cmd) & DSCM_TRANS)
328 return;
329
330 if ((ns->ns_if.if_flags & IFF_RUNNING) == 0)
331 return;
332
333 IF_DEQUEUE(&ns->ns_if.if_snd, m);
334
335 if (m == 0)
336 return;
337
338 /*
339 * Copy the mbuf chain into the transmit buffer
340 */
341
c6b0f337 342 ns->ns_flags |= DSF_LOCK; /* prevent entering nestart */
93b2b8c5
BJ
343 buffer = TBUF; len = i = 0;
344 for (m0 = m; m != 0; m = m->m_next) {
345/*int j;*/
346 putram(mtod(m, caddr_t), buffer, m->m_len);
347 buffer += m->m_len;
348 len += m->m_len;
349/*for(j=0; i < len;i++,j++) puthex(mtod(m,u_char *)[j]);
350printf("|"); */
351 }
352
353 /*
354 * If this was a broadcast packet loop it
355 * back because the hardware can't hear its own
356 * transmits.
357 */
358 /*if (bcmp((caddr_t)(mtod(m0, struct ether_header *)->ether_dhost),
359 (caddr_t)etherbroadcastaddr,
360 sizeof(etherbroadcastaddr)) == 0) {
361 neread(ns, m0);
362 } else {
363*/
364 m_freem(m0);
365 /*}*/
366
367 /*
368 * Init transmit length registers, and set transmit start flag.
369 */
370
c6b0f337
BJ
371#ifdef NEDEBUG
372if(len < 0 || len > 1536)
373pg("T Bogus Length %d\n", len);
374dprintf(DEXPAND,"snd %d ", len);
375#endif
376 if (len < 60) len = 60;
93b2b8c5
BJ
377 outb(nec+ds0_tbcr0,len&0xff);
378 outb(nec+ds0_tbcr1,(len>>8)&0xff);
379 outb(nec+ds0_tpsr, TBUF/DS_PGSIZE);
380 outb(nec+ds_cmd, DSCM_TRANS|DSCM_NODMA|DSCM_START);
381}
382
383#define succ(n) (((n)+1 > RBUFEND/DS_PGSIZE) ? RBUF/DS_PGSIZE : (n)+1)
384#define pred(n) (((n)-1 < RBUF/DS_PGSIZE) ? RBUFEND/DS_PGSIZE : (n)-1)
385/*
386 * Controller interrupt.
387 */
c6b0f337 388neintr(vec, ppl)
93b2b8c5
BJ
389 int vec;
390{
391 register struct ne_softc *ns = &ne_softc[0];
392 u_char cmd,isr;
c6b0f337 393static cnt;
93b2b8c5 394
c6b0f337
BJ
395redstack();
396 /* save cmd, clear interrupt */
93b2b8c5 397 cmd = inb (nec+ds_cmd);
c6b0f337 398loop:
93b2b8c5 399 isr = inb (nec+ds0_isr);
c6b0f337
BJ
400#ifdef NEDEBUG
401dprintf(DEXPAND,"|ppl %x isr %x ", ppl, isr);
402#endif
403
404 outb(nec+ds_cmd,DSCM_NODMA|DSCM_START);
93b2b8c5
BJ
405 outb (nec+ds0_isr, isr);
406
93b2b8c5
BJ
407
408 if (isr & (/*DSIS_RXE|*/DSIS_TXE|DSIS_ROVRN))
409 log(LOG_ERR, "ne%d: error: isr %x\n", ns-ne_softc, isr/*, DSIS_BITS*/);
410
411 /* receiver ovverun? */
412 if (isr & DSIS_ROVRN) {
413 u_char pend,lastfree;
414
415 outb(nec+ds_cmd, DSCM_STOP|DSCM_NODMA);
416 outb(nec+ds_cmd, DSCM_STOP|DSCM_NODMA|DSCM_PG1);
417 pend = inb(nec+ds1_curr);
418 outb(nec+ds_cmd, DSCM_STOP|DSCM_NODMA|DSCM_PG0);
419 lastfree = inb(nec+ds0_bnry);
c6b0f337 420#ifdef NEDEBUG
93b2b8c5 421printf("Cur %x pend %x lastfree %x ", ns->ns_cur, pend, lastfree);
c6b0f337 422#endif
93b2b8c5
BJ
423 /* have we wrapped */
424 if (lastfree > RBUFEND/DS_PGSIZE)
425 lastfree = RBUF/DS_PGSIZE;
426 /* something in the buffer? */
427 if (pend != succ(lastfree)) {
428 u_char nxt;
429
430 fetchram(&ns->ns_ph,ns->ns_cur*DS_PGSIZE, sizeof(ns->ns_ph));
431 ns->ns_ba = ns->ns_cur*DS_PGSIZE+sizeof(ns->ns_ph);
432
433 if (ns->ns_ph.pr_status & DSRS_RPC)
434 nerecv (ns);
435
436 nxt = ns->ns_ph.pr_nxtpg ;
c6b0f337 437#ifdef NEDEBUG
93b2b8c5 438printf("nxt %x ", nxt);
c6b0f337 439#endif
93b2b8c5
BJ
440 /* sanity check */
441 if ( nxt >= RBUF/DS_PGSIZE
442 && nxt <= RBUFEND/DS_PGSIZE && nxt <= pend)
443 ns->ns_cur = nxt;
444 else ns->ns_cur = nxt = pend;
445 lastfree = pred(nxt);
446 outb(nec+ds0_bnry, lastfree);
447 } else ns->ns_cur = pend;
448
449 outb(nec+ds0_rbcr0,0);
450 outb(nec+ds0_rbcr1,0);
451 outb(nec+ds0_tcr,DSTC_LB0);
452 outb(nec+ds0_rcr, DSRC_MON);
453 outb(nec+ds_cmd, DSCM_START|DSCM_NODMA);
454 outb (nec+ds0_rcr, DSRC_AB);
455 outb(nec+ds0_tcr,0);
c6b0f337 456#ifdef NEDEBUG
93b2b8c5 457printf("\n");
c6b0f337 458#endif
93b2b8c5
BJ
459 }
460
461 /* receiver error */
462 if (isr & DSIS_RXE) {
463 /* need to read these registers to clear status */
464 (void) inb(nec+ ds0_rsr);
465 (void) inb(nec+ 0xD);
466 (void) inb(nec + 0xE);
467 (void) inb(nec + 0xF);
468 ns->ns_if.if_ierrors++;
469 }
470
471 if (isr & (DSIS_RX|DSIS_RXE)) {
472 u_char pend,lastfree;
473
474 outb(nec+ds_cmd, DSCM_START|DSCM_NODMA|DSCM_PG1);
475 pend = inb(nec+ds1_curr);
476 outb(nec+ds_cmd, DSCM_START|DSCM_NODMA|DSCM_PG0);
477 lastfree = inb(nec+ds0_bnry);
c6b0f337
BJ
478#ifdef NEDEBUG
479dprintf(DEXPAND,"cur %x pnd %x lfr %x ", ns->ns_cur, pend, lastfree);
480#endif
93b2b8c5
BJ
481 /* have we wrapped */
482 if (lastfree > RBUFEND/DS_PGSIZE)
483 lastfree = RBUF/DS_PGSIZE;
484 /* something in the buffer? */
c6b0f337 485 if (pend != succ(lastfree)) {
93b2b8c5
BJ
486 u_char nxt;
487
488 fetchram(&ns->ns_ph,ns->ns_cur*DS_PGSIZE, sizeof(ns->ns_ph));
489 ns->ns_ba = ns->ns_cur*DS_PGSIZE+sizeof(ns->ns_ph);
490
c6b0f337
BJ
491 if (ns->ns_ph.pr_status == DSRS_RPC ||
492 ns->ns_ph.pr_status == 0x21)
93b2b8c5 493 nerecv (ns);
c6b0f337
BJ
494#ifdef NEDEBUG
495 else {
496printf("cur %x pnd %x lfr %x ", ns->ns_cur, pend, lastfree);
497printf("nxt %x len %x ", ns->ns_ph.pr_nxtpg, (ns->ns_ph.pr_sz1<<8)+
498 ns->ns_ph.pr_sz0);
499pg("Bogus Sts %x ", ns->ns_ph.pr_status);
500 }
501#endif
93b2b8c5
BJ
502
503 nxt = ns->ns_ph.pr_nxtpg ;
c6b0f337 504#ifdef NEDEBUG
93b2b8c5 505dprintf(DEXPAND,"nxt %x ", nxt);
c6b0f337 506#endif
93b2b8c5
BJ
507 /* sanity check */
508 if ( nxt >= RBUF/DS_PGSIZE
509 && nxt <= RBUFEND/DS_PGSIZE && nxt <= pend)
510 ns->ns_cur = nxt;
511 else ns->ns_cur = nxt = pend;
512 lastfree = pred(nxt);
513 outb(nec+ds0_bnry, lastfree);
c6b0f337
BJ
514 pend = inb(nec+ds1_curr);
515 } else ns->ns_cur = pend;
93b2b8c5 516 outb(nec+ds_cmd, DSCM_START|DSCM_NODMA);
93b2b8c5
BJ
517 }
518 if (isr & DSIS_TXE) {
c6b0f337
BJ
519 ns->ns_flags &= ~DSF_LOCK;
520#ifdef NEDEBUG
521dprintf(DEXPAND," clsn");
522#endif
93b2b8c5
BJ
523 /* need to read these registers to clear status */
524 ns->ns_if.if_collisions += inb(nec+ds0_tbcr0);
525 ns->ns_if.if_oerrors++;
526 }
c6b0f337
BJ
527 if (isr & DSIS_TX) {
528#ifdef NEDEBUG
529dprintf(DEXPAND,"tx ");
530#endif
531 ns->ns_flags &= ~DSF_LOCK;
93b2b8c5 532 ++ns->ns_if.if_opackets;
93b2b8c5
BJ
533 ns->ns_if.if_collisions +=
534 inb(nec+ds0_tbcr0);
535 }
c6b0f337 536
93b2b8c5
BJ
537 outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START);
538 nestart(ns);
c6b0f337 539 outb (nec+ds_cmd, cmd);
93b2b8c5 540 outb (nec+ds0_imr, 0xff);
c6b0f337
BJ
541 isr = inb (nec+ds0_isr);
542 if(isr) goto loop;
543
544#ifdef NEDEBUG
545 if(++cnt % 10 == 0) dprintf(DEXPAND,"\n");
546#endif
93b2b8c5
BJ
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 */
557nerecv(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);
c6b0f337
BJ
564if(len < 60 || len > 1536) {
565#ifdef NEDEBUG
566pg(DEXPAND,"R Bogus Length %d", len);
567#endif
568return;
569}
93b2b8c5 570 fetchram(ns->ns_pb,ns->ns_ba,min(len,DS_PGSIZE-sizeof(ns->ns_ph)));
c6b0f337 571#ifdef NEDEBUG
93b2b8c5
BJ
572if (!bcmp((caddr_t)ns->ns_pb, (caddr_t)ns->ns_addr, 6)
573&& !bcmp((caddr_t)ns->ns_pb, (caddr_t)etherbroadcastaddr, 6)) {
574printf("G%x ", ns->ns_cur);
575return;
576}/* else
577printf("P%x ", ns->ns_cur);*/
c6b0f337 578#endif
93b2b8c5
BJ
579 if(len > DS_PGSIZE-sizeof(ns->ns_ph)) {
580 int l = len - (DS_PGSIZE-sizeof(ns->ns_ph)), b ;
581 u_char *p = ns->ns_pb + (DS_PGSIZE-sizeof(ns->ns_ph));
582
c6b0f337
BJ
583#ifdef NEDEBUG
584dprintf(DEXPAND,"len %d(%d|", len, p - ns->ns_pb);
585#endif
93b2b8c5
BJ
586 if(++ns->ns_cur > 0x7f) ns->ns_cur = 0x46;
587 b = ns->ns_cur*DS_PGSIZE;
588
589 while (l >= DS_PGSIZE) {
590 fetchram(p,b,DS_PGSIZE);
591 p += DS_PGSIZE; l -= DS_PGSIZE;
592 if(++ns->ns_cur > 0x7f) ns->ns_cur = 0x46;
593 b = ns->ns_cur*DS_PGSIZE;
c6b0f337
BJ
594#ifdef NEDEBUG
595dprintf(DEXPAND,"%d|", p - ns->ns_pb);
596#endif
93b2b8c5 597 }
c6b0f337
BJ
598#ifdef NEDEBUG
599dprintf(DEXPAND,"%d) ", l);
600#endif
93b2b8c5
BJ
601 if (l > 0)
602 fetchram(p,b,l);
603 }
604 len -=
605 sizeof(struct ether_header)
606 + sizeof(long); /* don't forget checksum! */
607
608
609 neread(ns,(caddr_t)(ns->ns_pb), len);
610}
611
c6b0f337
BJ
612pausestr(s,n) char *s; {
613static downcnt;
614
615 if(n) { downcnt = 0xffff; return(0); }
616 if(--downcnt > 0) return(0);
617#ifdef NEDEBUG
618 pg(" <%s> recur %d sts %x ", s, recur, inb (nec+ds0_isr));
619#endif
620 return(-1);
621}
622
623
93b2b8c5
BJ
624/*
625 * Pass a packet to the higher levels.
626 * We deal with the trailer protocol here.
627 */
628neread(ns, buf, len)
629 register struct ne_softc *ns;
630 char *buf;
631 int len;
632{
633 register struct ether_header *eh;
634 struct mbuf *m;
635 int off, resid;
636 register struct ifqueue *inq;
637
638 /*
639 * Deal with trailer protocol: if type is trailer type
640 * get true type from first 16-bit word past data.
641 * Remember that type was trailer by setting off.
642 */
643 eh = (struct ether_header *)buf;
644 eh->ether_type = ntohs((u_short)eh->ether_type);
645#define nedataaddr(eh, off, type) ((type)(((caddr_t)((eh)+1)+(off))))
646 if (eh->ether_type >= ETHERTYPE_TRAIL &&
647 eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
648 off = (eh->ether_type - ETHERTYPE_TRAIL) * 512;
649 if (off >= ETHERMTU) return; /* sanity */
650 eh->ether_type = ntohs(*nedataaddr(eh, off, u_short *));
651 resid = ntohs(*(nedataaddr(eh, off+2, u_short *)));
652 if (off + resid > len) return; /* sanity */
653 len = off + resid;
654 } else off = 0;
655
656 if (len == 0) return;
657
658 /*
659 * Pull packet off interface. Off is nonzero if packet
660 * has trailing header; neget will then force this header
661 * information to be at the front, but we still have to drop
662 * the type and length which are at the front of any trailer data.
663 */
664 m = neget(buf, len, off, &ns->ns_if);
665 if (m == 0) return;
666
667 if (off) {
668 struct ifnet *ifp;
669
670 ifp = *(mtod(m, struct ifnet **));
671 m->m_off += 2 * sizeof (u_short);
672 m->m_len -= 2 * sizeof (u_short);
673 *(mtod(m, struct ifnet **)) = ifp;
674 }
675 switch (eh->ether_type) {
676#ifdef INET
677 case ETHERTYPE_IP:
678 /*if (ns->ns_ac.ac_ipaddr == 0) goto raw;*/
679 schednetisr(NETISR_IP);
680 inq = &ipintrq;
681 break;
682
683 case ETHERTYPE_ARP:
684 arpinput(&ns->ns_ac, m);
685 return;
686#endif
687#ifdef NS
688 case ETHERTYPE_NS:
689 schednetisr(NETISR_NS);
690 inq = &nsintrq;
691 break;
692
693#endif
694 default:
695 m_freem(m);
696 return;
697 }
698
699 if (IF_QFULL(inq)) {
700 IF_DROP(inq);
701 m_freem(m);
702 return;
703 }
704 IF_ENQUEUE(inq, m);
705}
706
707/*
708 * Ethernet output routine.
709 * Encapsulate a packet of type family for the local net.
710 * Use trailer local net encapsulation if enough data in first
711 * packet leaves a multiple of 512 bytes of data in remainder.
712 */
713neoutput(ifp, m0, dst)
714 struct ifnet *ifp;
715 struct mbuf *m0;
716 struct sockaddr *dst;
717{
718 int type, s, error;
719 u_char edst[6];
720 struct in_addr idst;
721 register struct ne_softc *ns = &ne_softc[ifp->if_unit];
722 register struct mbuf *m = m0;
723 register struct ether_header *eh;
724 register int off;
725 extern struct ifnet loif;
726 struct mbuf *mcopy = (struct mbuf *)0;
727 int usetrailers;
728
729 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
730 error = ENETDOWN;
731 goto bad;
732 }
733
734 switch (dst->sa_family) {
735#ifdef INET
736 case AF_INET:
737 idst = ((struct sockaddr_in *)dst)->sin_addr;
738 if (!arpresolve(&ns->ns_ac, m, &idst, edst, &usetrailers))
739 return (0); /* if not yet resolved */
740 if (!bcmp((caddr_t)edst, (caddr_t)etherbroadcastaddr,
741 sizeof(edst)))
742 mcopy = m_copy(m, 0, (int)M_COPYALL);
743 off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
744
c6b0f337 745
93b2b8c5
BJ
746 /* need per host negotiation */
747 if (usetrailers && off > 0 && (off & 0x1ff) == 0 &&
748 m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
749 type = ETHERTYPE_TRAIL + (off>>9);
750 m->m_off -= 2 * sizeof (u_short);
751 m->m_len += 2 * sizeof (u_short);
752 *mtod(m, u_short *) = ntohs((u_short)ETHERTYPE_IP);
753 *(mtod(m, u_short *) + 1) = ntohs((u_short)m->m_len);
754 goto gottrailertype;
755 }
756 type = ETHERTYPE_IP;
757 off = 0;
758 goto gottype;
759#endif
760#ifdef NS
761 case AF_NS:
762 bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host),
763 (caddr_t)edst, sizeof (edst));
764
765 if (!bcmp((caddr_t)edst, (caddr_t)&ns_broadhost,
766 sizeof(edst))) {
767
768 mcopy = m_copy(m, 0, (int)M_COPYALL);
769 } else if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost,
770 sizeof(edst))) {
771
772 return(looutput(&loif, m, dst));
773 }
774 type = ETHERTYPE_NS;
775 off = 0;
776 goto gottype;
777#endif
778
779 case AF_UNSPEC:
780 eh = (struct ether_header *)dst->sa_data;
781 bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst));
782 type = eh->ether_type;
783 goto gottype;
784
785 default:
786 printf("ne%d: can't handle af%d\n", ifp->if_unit,
787 dst->sa_family);
788 error = EAFNOSUPPORT;
789 goto bad;
790 }
791
792gottrailertype:
793 /*
794 * Packet to be sent as trailer: move first packet
795 * (control information) to end of chain.
796 */
797 while (m->m_next)
798 m = m->m_next;
799 m->m_next = m0;
800 m = m0->m_next;
801 m0->m_next = 0;
802 m0 = m;
803
804gottype:
805 /*
806 * Add local net header. If no space in first mbuf,
807 * allocate another.
808 */
809 if (m->m_off > MMAXOFF ||
810 MMINOFF + sizeof (struct ether_header) > m->m_off) {
811 m = m_get(M_DONTWAIT, MT_HEADER);
812 if (m == 0) {
813 error = ENOBUFS;
814 goto bad;
815 }
816 m->m_next = m0;
817 m->m_off = MMINOFF;
818 m->m_len = sizeof (struct ether_header);
819 } else {
820 m->m_off -= sizeof (struct ether_header);
821 m->m_len += sizeof (struct ether_header);
822 }
823 eh = mtod(m, struct ether_header *);
824 bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst));
825 bcopy((caddr_t)ns->ns_addr, (caddr_t)eh->ether_shost,
826 sizeof (eh->ether_shost));
827 eh->ether_type = htons((u_short)type);
828
829 /*
830 * Queue message on interface, and start output if interface
831 * not yet active.
832 */
833 s = splimp();
834 if (IF_QFULL(&ifp->if_snd)) {
835 IF_DROP(&ifp->if_snd);
836 splx(s);
837 m_freem(m);
838 return (ENOBUFS);
839 }
840 IF_ENQUEUE(&ifp->if_snd, m);
841 nestart(ns);
842 splx(s);
843 return (mcopy ? looutput(&loif, mcopy, dst) : 0);
844
845bad:
846 m_freem(m0);
847 if (mcopy)
848 m_freem(mcopy);
849 return (error);
850}
851
852/*
853 * Supporting routines
854 */
855
856/*
857 * Pull read data off a interface.
858 * Len is length of data, with local net header stripped.
859 * Off is non-zero if a trailer protocol was used, and
860 * gives the offset of the trailer information.
861 * We copy the trailer information and then all the normal
862 * data into mbufs. When full cluster sized units are present
863 * we copy into clusters.
864 */
865struct mbuf *
866neget(buf, totlen, off0, ifp)
867 caddr_t buf;
868 int totlen, off0;
869 struct ifnet *ifp;
870{
871 struct mbuf *top, **mp, *m, *p;
872 int off = off0, len;
873 register caddr_t cp = buf;
874
875 cp = buf + sizeof(struct ether_header);
876 top = 0;
877 mp = &top;
878 while (totlen > 0) {
879 u_char *mcp;
880
881 MGET(m, M_DONTWAIT, MT_DATA);
882 if (m == 0)
883 goto bad;
884 if (off) {
885 len = totlen - off;
886 cp = buf + off + sizeof (struct ether_header);
887 } else
888 len = totlen;
889 if (ifp)
890 len += sizeof(ifp);
891 if (len >= NBPG) {
892 MCLGET(m);
893 if (m->m_len == CLBYTES)
894 m->m_len = len = MIN(len, CLBYTES);
895 else
896 m->m_len = len = MIN(MLEN, len);
897 } else {
898 m->m_len = len = MIN(MLEN, len);
899 m->m_off = MMINOFF;
900 }
901 mcp = mtod(m, u_char *);
902 if (ifp) {
903 /*
904 * Prepend interface pointer to first mbuf.
905 */
906 *(mtod(m, struct ifnet **)) = ifp;
907 mcp += sizeof(ifp);
908 len -= sizeof(ifp);
909 ifp = (struct ifnet *)0;
910 }
911 bcopy(cp, mcp, len);
912 cp += len ; mcp += len ;
913 *mp = m;
914 mp = &m->m_next;
915 if (off == 0) {
916 totlen -= len;
917 continue;
918 }
919 off += len;
920 if (off == totlen) {
921 cp = buf + sizeof (struct ether_header);
922 off = 0;
923 totlen = off0;
924 }
925 }
926 return (top);
927bad:
928 m_freem(top);
929 return (0);
930}
931
932/*
933 * Map a chain of mbufs onto a network interface
934 * in preparation for an i/o operation.
935 * The argument chain of mbufs includes the local network
936 * header which is copied to be in the mapped, aligned
937 * i/o space.
938 */
939neput(cp, m)
940 register caddr_t cp;
941 register struct mbuf *m;
942{
943 register struct mbuf *mp;
944 register int i;
945 int x, cc = 0, t;
946 caddr_t dp;
947
948 while (m) {
949 dp = mtod(m, char *);
950 bcopy(mtod(m, caddr_t), cp, (unsigned)m->m_len);
951 cp += m->m_len;
952 cc += m->m_len;
953 MFREE(m, mp);
954 m = mp;
955 }
956 return (max(cc, ETHERMIN + sizeof(struct ether_header)));
957}
958
959/*
960 * Process an ioctl request.
961 */
962neioctl(ifp, cmd, data)
963 register struct ifnet *ifp;
964 int cmd;
965 caddr_t data;
966{
967 register struct ifaddr *ifa = (struct ifaddr *)data;
968 struct ne_softc *ns = &ne_softc[ifp->if_unit];
969 struct ifreq *ifr = (struct ifreq *)data;
970 int s = splimp(), error = 0;
971
972
973 switch (cmd) {
974
975 case SIOCSIFADDR:
976 ifp->if_flags |= IFF_UP;
977
978 switch (ifa->ifa_addr.sa_family) {
979#ifdef INET
980 case AF_INET:
981 neinit(ifp->if_unit); /* before arpwhohas */
982 ((struct arpcom *)ifp)->ac_ipaddr =
983 IA_SIN(ifa)->sin_addr;
984 arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
985 break;
986#endif
987#ifdef NS
988 case AF_NS:
989 {
990 register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
991
992 if (ns_nullhost(*ina))
993 ina->x_host = *(union ns_host *)(ns->ns_addr);
994 else {
995 /*
996 * The manual says we can't change the address
997 * while the receiver is armed,
998 * so reset everything
999 */
1000 ifp->if_flags &= ~IFF_RUNNING;
1001 bcopy((caddr_t)ina->x_host.c_host,
1002 (caddr_t)ns->ns_addr, sizeof(ns->ns_addr));
1003 }
1004 neinit(ifp->if_unit); /* does ne_setaddr() */
1005 break;
1006 }
1007#endif
1008 default:
1009 neinit(ifp->if_unit);
1010 break;
1011 }
1012 break;
1013
1014 case SIOCSIFFLAGS:
1015 if ((ifp->if_flags & IFF_UP) == 0 &&
1016 ifp->if_flags & IFF_RUNNING) {
1017 ifp->if_flags &= ~IFF_RUNNING;
1018 outb(nec+ds_cmd,DSCM_STOP|DSCM_NODMA);
1019 } else if (ifp->if_flags & IFF_UP &&
1020 (ifp->if_flags & IFF_RUNNING) == 0)
1021 neinit(ifp->if_unit);
1022 break;
1023
1024#ifdef notdef
1025 case SIOCGHWADDR:
1026 bcopy((caddr_t)ns->ns_addr, (caddr_t) &ifr->ifr_data,
1027 sizeof(ns->ns_addr));
1028 break;
1029#endif
1030
1031 default:
1032 error = EINVAL;
1033 }
1034 splx(s);
1035 return (error);
1036}
1037
1038nesetaddr(ifp, sin)
1039 register struct ifnet *ifp;
1040 register struct sockaddr_in *sin;
1041{
1042#ifdef notdef
1043 ifp->if_addr = *(struct sockaddr *)sin;
1044 ifp->if_net = in_netof(sin->sin_addr);
1045 ifp->if_host[0] = in_lnaof(sin->sin_addr);
1046 if (nepaddr[ifp->if_unit][0] == '3')
1047 nepaddr[ifp->if_unit][0] = ifp->if_host[0] << 1;
1048 sin = (struct sockaddr_in *)&ifp->if_broadaddr;
1049 sin->sin_family = AF_INET;
1050 sin->sin_addr = in_makeaddr(ifp->if_net, INADDR_ANY);
1051 ifp->if_flags |= IFF_BROADCAST;
1052#endif
1053}
1054#endif