Commit | Line | Data |
---|---|---|
93b2b8c5 BJ |
1 | #include "ne.h" |
2 | #if NNE > 0 | |
3 | /* | |
4 | * NE2000 Ethernet driver | |
5 | * Copyright (C) 1990 W. Jolitz | |
5033d830 | 6 | * @(#)if_ne.c 1.6 (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 | ||
4686adac | 39 | #include "machine/isa/isa_device.h" |
93b2b8c5 BJ |
40 | #include "if_nereg.h" |
41 | #include "icu.h" | |
42 | ||
43 | int neprobe(), neattach(), neintr(); | |
44 | int neinit(), neoutput(), neioctl(); | |
45 | ||
c6b0f337 BJ |
46 | #include "dbg.h" |
47 | struct isa_driver nedriver = { | |
93b2b8c5 BJ |
48 | neprobe, neattach, "ne", |
49 | }; | |
50 | ||
93b2b8c5 BJ |
51 | struct 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 | */ | |
60 | struct 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 | ||
76 | int nec; | |
77 | ||
78 | u_short boarddata[16]; | |
79 | ||
80 | neprobe(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; | |
130 | printf("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 | } | |
144 | printf("\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 | ||
154 | fetchrom (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 | 172 | static recur; |
93b2b8c5 BJ |
173 | fetchram (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 | ||
193 | putram (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 | */ | |
218 | nereset(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 | */ | |
233 | neattach(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; | |
e243739b | 243 | printf (" ethernet address %s", ether_sprintf(ns->ns_addr)) ; |
93b2b8c5 BJ |
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 | */ | |
257 | neinit(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); | |
c67ce870 | 290 | outb(nec+ds0_bnry, RBUF/DS_PGSIZE); |
93b2b8c5 BJ |
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 | */ | |
311 | nestart(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]); | |
350 | printf("|"); */ | |
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 | ||
c67ce870 | 371 | #ifdef NEDEBUGx |
c6b0f337 BJ |
372 | if(len < 0 || len > 1536) |
373 | pg("T Bogus Length %d\n", len); | |
374 | dprintf(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 | ||
c67ce870 BJ |
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-1 : (n)-1) | |
93b2b8c5 BJ |
385 | /* |
386 | * Controller interrupt. | |
387 | */ | |
c6b0f337 | 388 | neintr(vec, ppl) |
93b2b8c5 BJ |
389 | int vec; |
390 | { | |
391 | register struct ne_softc *ns = &ne_softc[0]; | |
392 | u_char cmd,isr; | |
c6b0f337 | 393 | static cnt; |
93b2b8c5 | 394 | |
c6b0f337 | 395 | /* save cmd, clear interrupt */ |
93b2b8c5 | 396 | cmd = inb (nec+ds_cmd); |
c6b0f337 | 397 | loop: |
93b2b8c5 | 398 | isr = inb (nec+ds0_isr); |
c67ce870 | 399 | #ifdef NEDEBUGx |
c6b0f337 BJ |
400 | dprintf(DEXPAND,"|ppl %x isr %x ", ppl, isr); |
401 | #endif | |
402 | ||
403 | outb(nec+ds_cmd,DSCM_NODMA|DSCM_START); | |
c67ce870 | 404 | outb(nec+ds0_isr, isr); |
93b2b8c5 | 405 | |
93b2b8c5 | 406 | |
c67ce870 | 407 | if (isr & (DSIS_RXE|DSIS_TXE|DSIS_ROVRN)) |
93b2b8c5 BJ |
408 | log(LOG_ERR, "ne%d: error: isr %x\n", ns-ne_softc, isr/*, DSIS_BITS*/); |
409 | ||
c67ce870 | 410 | #ifdef notdef |
93b2b8c5 BJ |
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 | 421 | printf("Cur %x pend %x lastfree %x ", ns->ns_cur, pend, lastfree); |
c6b0f337 | 422 | #endif |
93b2b8c5 | 423 | /* have we wrapped */ |
c67ce870 | 424 | if (lastfree >= RBUFEND/DS_PGSIZE) |
93b2b8c5 BJ |
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 | 438 | printf("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); | |
93b2b8c5 | 456 | } |
c67ce870 | 457 | #endif |
93b2b8c5 BJ |
458 | |
459 | /* receiver error */ | |
460 | if (isr & DSIS_RXE) { | |
461 | /* need to read these registers to clear status */ | |
462 | (void) inb(nec+ ds0_rsr); | |
463 | (void) inb(nec+ 0xD); | |
464 | (void) inb(nec + 0xE); | |
465 | (void) inb(nec + 0xF); | |
466 | ns->ns_if.if_ierrors++; | |
467 | } | |
468 | ||
c67ce870 | 469 | if (isr & (DSIS_RX|DSIS_RXE|DSIS_ROVRN)) { |
93b2b8c5 BJ |
470 | u_char pend,lastfree; |
471 | ||
472 | outb(nec+ds_cmd, DSCM_START|DSCM_NODMA|DSCM_PG1); | |
473 | pend = inb(nec+ds1_curr); | |
474 | outb(nec+ds_cmd, DSCM_START|DSCM_NODMA|DSCM_PG0); | |
475 | lastfree = inb(nec+ds0_bnry); | |
c6b0f337 BJ |
476 | #ifdef NEDEBUG |
477 | dprintf(DEXPAND,"cur %x pnd %x lfr %x ", ns->ns_cur, pend, lastfree); | |
478 | #endif | |
93b2b8c5 | 479 | /* have we wrapped */ |
c67ce870 | 480 | if (lastfree >= RBUFEND/DS_PGSIZE) |
93b2b8c5 | 481 | lastfree = RBUF/DS_PGSIZE; |
c67ce870 BJ |
482 | if (pend < lastfree && ns->ns_cur < pend) |
483 | lastfree = ns->ns_cur; | |
484 | else if (ns->ns_cur > lastfree) | |
485 | lastfree = ns->ns_cur; | |
486 | ||
93b2b8c5 | 487 | /* something in the buffer? */ |
c67ce870 | 488 | while (pend != lastfree) { |
93b2b8c5 BJ |
489 | u_char nxt; |
490 | ||
c67ce870 BJ |
491 | fetchram(&ns->ns_ph,lastfree*DS_PGSIZE, |
492 | sizeof(ns->ns_ph)); | |
493 | ns->ns_ba = lastfree*DS_PGSIZE+sizeof(ns->ns_ph); | |
93b2b8c5 | 494 | |
c67ce870 | 495 | /* paranoia */ |
c6b0f337 BJ |
496 | if (ns->ns_ph.pr_status == DSRS_RPC || |
497 | ns->ns_ph.pr_status == 0x21) | |
93b2b8c5 | 498 | nerecv (ns); |
c6b0f337 BJ |
499 | #ifdef NEDEBUG |
500 | else { | |
501 | printf("cur %x pnd %x lfr %x ", ns->ns_cur, pend, lastfree); | |
502 | printf("nxt %x len %x ", ns->ns_ph.pr_nxtpg, (ns->ns_ph.pr_sz1<<8)+ | |
503 | ns->ns_ph.pr_sz0); | |
504 | pg("Bogus Sts %x ", ns->ns_ph.pr_status); | |
505 | } | |
506 | #endif | |
93b2b8c5 BJ |
507 | |
508 | nxt = ns->ns_ph.pr_nxtpg ; | |
c6b0f337 | 509 | #ifdef NEDEBUG |
93b2b8c5 | 510 | dprintf(DEXPAND,"nxt %x ", nxt); |
c6b0f337 | 511 | #endif |
93b2b8c5 BJ |
512 | /* sanity check */ |
513 | if ( nxt >= RBUF/DS_PGSIZE | |
514 | && nxt <= RBUFEND/DS_PGSIZE && nxt <= pend) | |
515 | ns->ns_cur = nxt; | |
516 | else ns->ns_cur = nxt = pend; | |
c67ce870 BJ |
517 | lastfree = nxt; |
518 | outb(nec+ds0_bnry, pred(nxt)); | |
519 | outb(nec+ds_cmd, DSCM_START|DSCM_NODMA|DSCM_PG1); | |
c6b0f337 | 520 | pend = inb(nec+ds1_curr); |
c67ce870 BJ |
521 | outb(nec+ds_cmd, DSCM_START|DSCM_NODMA|DSCM_PG0); |
522 | } /*else ns->ns_cur = pend;*/ | |
523 | #ifdef NEDEBUG | |
524 | dprintf(DEXPAND,"cur %x pnd %x lfR %x ", ns->ns_cur, pend, lastfree); | |
525 | #endif | |
93b2b8c5 | 526 | outb(nec+ds_cmd, DSCM_START|DSCM_NODMA); |
93b2b8c5 BJ |
527 | } |
528 | if (isr & DSIS_TXE) { | |
c67ce870 | 529 | ns->ns_flags &= ~DSF_LOCK; |
c6b0f337 BJ |
530 | #ifdef NEDEBUG |
531 | dprintf(DEXPAND," clsn"); | |
532 | #endif | |
93b2b8c5 BJ |
533 | /* need to read these registers to clear status */ |
534 | ns->ns_if.if_collisions += inb(nec+ds0_tbcr0); | |
535 | ns->ns_if.if_oerrors++; | |
536 | } | |
c6b0f337 | 537 | if (isr & DSIS_TX) { |
c67ce870 | 538 | #ifdef NEDEBUGx |
c6b0f337 BJ |
539 | dprintf(DEXPAND,"tx "); |
540 | #endif | |
c67ce870 | 541 | ns->ns_flags &= ~DSF_LOCK; |
93b2b8c5 | 542 | ++ns->ns_if.if_opackets; |
c67ce870 BJ |
543 | ns->ns_if.if_collisions += inb(nec+ds0_tbcr0); |
544 | } | |
545 | ||
546 | /* receiver ovverun? */ | |
547 | if (isr & DSIS_ROVRN) { | |
548 | outb(nec+ds0_rbcr0, 0); | |
549 | outb(nec+ds0_rbcr1, 0); | |
550 | outb(nec+ds0_tcr, DSTC_LB0); | |
551 | outb(nec+ds0_rcr, DSRC_MON); | |
552 | outb(nec+ds_cmd, DSCM_START|DSCM_NODMA); | |
553 | outb(nec+ds0_rcr, DSRC_AB); | |
554 | outb(nec+ds0_tcr, 0); | |
93b2b8c5 | 555 | } |
c6b0f337 | 556 | |
93b2b8c5 BJ |
557 | outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START); |
558 | nestart(ns); | |
c6b0f337 | 559 | outb (nec+ds_cmd, cmd); |
93b2b8c5 | 560 | outb (nec+ds0_imr, 0xff); |
c6b0f337 BJ |
561 | isr = inb (nec+ds0_isr); |
562 | if(isr) goto loop; | |
563 | ||
564 | #ifdef NEDEBUG | |
565 | if(++cnt % 10 == 0) dprintf(DEXPAND,"\n"); | |
566 | #endif | |
93b2b8c5 BJ |
567 | } |
568 | ||
569 | /* | |
570 | * Ethernet interface receiver interface. | |
571 | * If input error just drop packet. | |
572 | * Otherwise examine packet to determine type. If can't determine length | |
573 | * from type, then have to drop packet. Othewise decapsulate | |
574 | * packet based on type and pass to type specific higher-level | |
575 | * input routine. | |
576 | */ | |
577 | nerecv(ns) | |
578 | register struct ne_softc *ns; | |
579 | { | |
580 | int len,i; | |
581 | ||
582 | ns->ns_if.if_ipackets++; | |
583 | len = ns->ns_ph.pr_sz0 + (ns->ns_ph.pr_sz1<<8); | |
c6b0f337 BJ |
584 | if(len < 60 || len > 1536) { |
585 | #ifdef NEDEBUG | |
586 | pg(DEXPAND,"R Bogus Length %d", len); | |
587 | #endif | |
588 | return; | |
589 | } | |
93b2b8c5 | 590 | fetchram(ns->ns_pb,ns->ns_ba,min(len,DS_PGSIZE-sizeof(ns->ns_ph))); |
c6b0f337 | 591 | #ifdef NEDEBUG |
93b2b8c5 BJ |
592 | if (!bcmp((caddr_t)ns->ns_pb, (caddr_t)ns->ns_addr, 6) |
593 | && !bcmp((caddr_t)ns->ns_pb, (caddr_t)etherbroadcastaddr, 6)) { | |
594 | printf("G%x ", ns->ns_cur); | |
595 | return; | |
596 | }/* else | |
597 | printf("P%x ", ns->ns_cur);*/ | |
c6b0f337 | 598 | #endif |
93b2b8c5 BJ |
599 | if(len > DS_PGSIZE-sizeof(ns->ns_ph)) { |
600 | int l = len - (DS_PGSIZE-sizeof(ns->ns_ph)), b ; | |
601 | u_char *p = ns->ns_pb + (DS_PGSIZE-sizeof(ns->ns_ph)); | |
602 | ||
c6b0f337 BJ |
603 | #ifdef NEDEBUG |
604 | dprintf(DEXPAND,"len %d(%d|", len, p - ns->ns_pb); | |
605 | #endif | |
93b2b8c5 BJ |
606 | if(++ns->ns_cur > 0x7f) ns->ns_cur = 0x46; |
607 | b = ns->ns_cur*DS_PGSIZE; | |
608 | ||
609 | while (l >= DS_PGSIZE) { | |
610 | fetchram(p,b,DS_PGSIZE); | |
611 | p += DS_PGSIZE; l -= DS_PGSIZE; | |
612 | if(++ns->ns_cur > 0x7f) ns->ns_cur = 0x46; | |
613 | b = ns->ns_cur*DS_PGSIZE; | |
c6b0f337 BJ |
614 | #ifdef NEDEBUG |
615 | dprintf(DEXPAND,"%d|", p - ns->ns_pb); | |
616 | #endif | |
93b2b8c5 | 617 | } |
c6b0f337 BJ |
618 | #ifdef NEDEBUG |
619 | dprintf(DEXPAND,"%d) ", l); | |
620 | #endif | |
93b2b8c5 BJ |
621 | if (l > 0) |
622 | fetchram(p,b,l); | |
623 | } | |
624 | len -= | |
625 | sizeof(struct ether_header) | |
626 | + sizeof(long); /* don't forget checksum! */ | |
627 | ||
628 | ||
629 | neread(ns,(caddr_t)(ns->ns_pb), len); | |
630 | } | |
631 | ||
c6b0f337 BJ |
632 | pausestr(s,n) char *s; { |
633 | static downcnt; | |
634 | ||
635 | if(n) { downcnt = 0xffff; return(0); } | |
636 | if(--downcnt > 0) return(0); | |
637 | #ifdef NEDEBUG | |
638 | pg(" <%s> recur %d sts %x ", s, recur, inb (nec+ds0_isr)); | |
639 | #endif | |
640 | return(-1); | |
641 | } | |
642 | ||
643 | ||
93b2b8c5 BJ |
644 | /* |
645 | * Pass a packet to the higher levels. | |
646 | * We deal with the trailer protocol here. | |
647 | */ | |
648 | neread(ns, buf, len) | |
649 | register struct ne_softc *ns; | |
650 | char *buf; | |
651 | int len; | |
652 | { | |
653 | register struct ether_header *eh; | |
654 | struct mbuf *m; | |
655 | int off, resid; | |
656 | register struct ifqueue *inq; | |
657 | ||
658 | /* | |
659 | * Deal with trailer protocol: if type is trailer type | |
660 | * get true type from first 16-bit word past data. | |
661 | * Remember that type was trailer by setting off. | |
662 | */ | |
663 | eh = (struct ether_header *)buf; | |
664 | eh->ether_type = ntohs((u_short)eh->ether_type); | |
665 | #define nedataaddr(eh, off, type) ((type)(((caddr_t)((eh)+1)+(off)))) | |
666 | if (eh->ether_type >= ETHERTYPE_TRAIL && | |
667 | eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { | |
668 | off = (eh->ether_type - ETHERTYPE_TRAIL) * 512; | |
669 | if (off >= ETHERMTU) return; /* sanity */ | |
670 | eh->ether_type = ntohs(*nedataaddr(eh, off, u_short *)); | |
671 | resid = ntohs(*(nedataaddr(eh, off+2, u_short *))); | |
672 | if (off + resid > len) return; /* sanity */ | |
673 | len = off + resid; | |
674 | } else off = 0; | |
675 | ||
676 | if (len == 0) return; | |
677 | ||
678 | /* | |
679 | * Pull packet off interface. Off is nonzero if packet | |
680 | * has trailing header; neget will then force this header | |
681 | * information to be at the front, but we still have to drop | |
682 | * the type and length which are at the front of any trailer data. | |
683 | */ | |
684 | m = neget(buf, len, off, &ns->ns_if); | |
685 | if (m == 0) return; | |
686 | ||
687 | if (off) { | |
688 | struct ifnet *ifp; | |
689 | ||
690 | ifp = *(mtod(m, struct ifnet **)); | |
691 | m->m_off += 2 * sizeof (u_short); | |
692 | m->m_len -= 2 * sizeof (u_short); | |
693 | *(mtod(m, struct ifnet **)) = ifp; | |
694 | } | |
695 | switch (eh->ether_type) { | |
696 | #ifdef INET | |
697 | case ETHERTYPE_IP: | |
698 | /*if (ns->ns_ac.ac_ipaddr == 0) goto raw;*/ | |
699 | schednetisr(NETISR_IP); | |
700 | inq = &ipintrq; | |
701 | break; | |
702 | ||
703 | case ETHERTYPE_ARP: | |
704 | arpinput(&ns->ns_ac, m); | |
705 | return; | |
706 | #endif | |
707 | #ifdef NS | |
708 | case ETHERTYPE_NS: | |
709 | schednetisr(NETISR_NS); | |
710 | inq = &nsintrq; | |
711 | break; | |
712 | ||
713 | #endif | |
714 | default: | |
715 | m_freem(m); | |
716 | return; | |
717 | } | |
718 | ||
719 | if (IF_QFULL(inq)) { | |
720 | IF_DROP(inq); | |
721 | m_freem(m); | |
722 | return; | |
723 | } | |
724 | IF_ENQUEUE(inq, m); | |
725 | } | |
726 | ||
727 | /* | |
728 | * Ethernet output routine. | |
729 | * Encapsulate a packet of type family for the local net. | |
730 | * Use trailer local net encapsulation if enough data in first | |
731 | * packet leaves a multiple of 512 bytes of data in remainder. | |
732 | */ | |
733 | neoutput(ifp, m0, dst) | |
734 | struct ifnet *ifp; | |
735 | struct mbuf *m0; | |
736 | struct sockaddr *dst; | |
737 | { | |
738 | int type, s, error; | |
739 | u_char edst[6]; | |
740 | struct in_addr idst; | |
741 | register struct ne_softc *ns = &ne_softc[ifp->if_unit]; | |
742 | register struct mbuf *m = m0; | |
743 | register struct ether_header *eh; | |
744 | register int off; | |
745 | extern struct ifnet loif; | |
746 | struct mbuf *mcopy = (struct mbuf *)0; | |
747 | int usetrailers; | |
748 | ||
749 | if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) { | |
750 | error = ENETDOWN; | |
751 | goto bad; | |
752 | } | |
753 | ||
754 | switch (dst->sa_family) { | |
755 | #ifdef INET | |
756 | case AF_INET: | |
757 | idst = ((struct sockaddr_in *)dst)->sin_addr; | |
758 | if (!arpresolve(&ns->ns_ac, m, &idst, edst, &usetrailers)) | |
759 | return (0); /* if not yet resolved */ | |
760 | if (!bcmp((caddr_t)edst, (caddr_t)etherbroadcastaddr, | |
761 | sizeof(edst))) | |
762 | mcopy = m_copy(m, 0, (int)M_COPYALL); | |
763 | off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; | |
764 | ||
c6b0f337 | 765 | |
93b2b8c5 BJ |
766 | /* need per host negotiation */ |
767 | if (usetrailers && off > 0 && (off & 0x1ff) == 0 && | |
768 | m->m_off >= MMINOFF + 2 * sizeof (u_short)) { | |
769 | type = ETHERTYPE_TRAIL + (off>>9); | |
770 | m->m_off -= 2 * sizeof (u_short); | |
771 | m->m_len += 2 * sizeof (u_short); | |
772 | *mtod(m, u_short *) = ntohs((u_short)ETHERTYPE_IP); | |
773 | *(mtod(m, u_short *) + 1) = ntohs((u_short)m->m_len); | |
774 | goto gottrailertype; | |
775 | } | |
776 | type = ETHERTYPE_IP; | |
777 | off = 0; | |
778 | goto gottype; | |
779 | #endif | |
780 | #ifdef NS | |
781 | case AF_NS: | |
782 | bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host), | |
783 | (caddr_t)edst, sizeof (edst)); | |
784 | ||
785 | if (!bcmp((caddr_t)edst, (caddr_t)&ns_broadhost, | |
786 | sizeof(edst))) { | |
787 | ||
788 | mcopy = m_copy(m, 0, (int)M_COPYALL); | |
789 | } else if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost, | |
790 | sizeof(edst))) { | |
791 | ||
792 | return(looutput(&loif, m, dst)); | |
793 | } | |
794 | type = ETHERTYPE_NS; | |
795 | off = 0; | |
796 | goto gottype; | |
797 | #endif | |
798 | ||
799 | case AF_UNSPEC: | |
800 | eh = (struct ether_header *)dst->sa_data; | |
801 | bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst)); | |
802 | type = eh->ether_type; | |
803 | goto gottype; | |
804 | ||
805 | default: | |
806 | printf("ne%d: can't handle af%d\n", ifp->if_unit, | |
807 | dst->sa_family); | |
808 | error = EAFNOSUPPORT; | |
809 | goto bad; | |
810 | } | |
811 | ||
812 | gottrailertype: | |
813 | /* | |
814 | * Packet to be sent as trailer: move first packet | |
815 | * (control information) to end of chain. | |
816 | */ | |
817 | while (m->m_next) | |
818 | m = m->m_next; | |
819 | m->m_next = m0; | |
820 | m = m0->m_next; | |
821 | m0->m_next = 0; | |
822 | m0 = m; | |
823 | ||
824 | gottype: | |
825 | /* | |
826 | * Add local net header. If no space in first mbuf, | |
827 | * allocate another. | |
828 | */ | |
829 | if (m->m_off > MMAXOFF || | |
830 | MMINOFF + sizeof (struct ether_header) > m->m_off) { | |
831 | m = m_get(M_DONTWAIT, MT_HEADER); | |
832 | if (m == 0) { | |
833 | error = ENOBUFS; | |
834 | goto bad; | |
835 | } | |
836 | m->m_next = m0; | |
837 | m->m_off = MMINOFF; | |
838 | m->m_len = sizeof (struct ether_header); | |
839 | } else { | |
840 | m->m_off -= sizeof (struct ether_header); | |
841 | m->m_len += sizeof (struct ether_header); | |
842 | } | |
843 | eh = mtod(m, struct ether_header *); | |
844 | bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst)); | |
845 | bcopy((caddr_t)ns->ns_addr, (caddr_t)eh->ether_shost, | |
846 | sizeof (eh->ether_shost)); | |
847 | eh->ether_type = htons((u_short)type); | |
848 | ||
849 | /* | |
850 | * Queue message on interface, and start output if interface | |
851 | * not yet active. | |
852 | */ | |
853 | s = splimp(); | |
854 | if (IF_QFULL(&ifp->if_snd)) { | |
855 | IF_DROP(&ifp->if_snd); | |
856 | splx(s); | |
857 | m_freem(m); | |
858 | return (ENOBUFS); | |
859 | } | |
860 | IF_ENQUEUE(&ifp->if_snd, m); | |
861 | nestart(ns); | |
862 | splx(s); | |
863 | return (mcopy ? looutput(&loif, mcopy, dst) : 0); | |
864 | ||
865 | bad: | |
866 | m_freem(m0); | |
867 | if (mcopy) | |
868 | m_freem(mcopy); | |
869 | return (error); | |
870 | } | |
871 | ||
872 | /* | |
873 | * Supporting routines | |
874 | */ | |
875 | ||
876 | /* | |
877 | * Pull read data off a interface. | |
878 | * Len is length of data, with local net header stripped. | |
879 | * Off is non-zero if a trailer protocol was used, and | |
880 | * gives the offset of the trailer information. | |
881 | * We copy the trailer information and then all the normal | |
882 | * data into mbufs. When full cluster sized units are present | |
883 | * we copy into clusters. | |
884 | */ | |
885 | struct mbuf * | |
886 | neget(buf, totlen, off0, ifp) | |
887 | caddr_t buf; | |
888 | int totlen, off0; | |
889 | struct ifnet *ifp; | |
890 | { | |
891 | struct mbuf *top, **mp, *m, *p; | |
892 | int off = off0, len; | |
893 | register caddr_t cp = buf; | |
894 | ||
895 | cp = buf + sizeof(struct ether_header); | |
896 | top = 0; | |
897 | mp = ⊤ | |
898 | while (totlen > 0) { | |
899 | u_char *mcp; | |
900 | ||
901 | MGET(m, M_DONTWAIT, MT_DATA); | |
902 | if (m == 0) | |
903 | goto bad; | |
904 | if (off) { | |
905 | len = totlen - off; | |
906 | cp = buf + off + sizeof (struct ether_header); | |
907 | } else | |
908 | len = totlen; | |
909 | if (ifp) | |
910 | len += sizeof(ifp); | |
911 | if (len >= NBPG) { | |
912 | MCLGET(m); | |
913 | if (m->m_len == CLBYTES) | |
914 | m->m_len = len = MIN(len, CLBYTES); | |
915 | else | |
916 | m->m_len = len = MIN(MLEN, len); | |
917 | } else { | |
918 | m->m_len = len = MIN(MLEN, len); | |
919 | m->m_off = MMINOFF; | |
920 | } | |
921 | mcp = mtod(m, u_char *); | |
922 | if (ifp) { | |
923 | /* | |
924 | * Prepend interface pointer to first mbuf. | |
925 | */ | |
926 | *(mtod(m, struct ifnet **)) = ifp; | |
927 | mcp += sizeof(ifp); | |
928 | len -= sizeof(ifp); | |
929 | ifp = (struct ifnet *)0; | |
930 | } | |
931 | bcopy(cp, mcp, len); | |
932 | cp += len ; mcp += len ; | |
933 | *mp = m; | |
934 | mp = &m->m_next; | |
935 | if (off == 0) { | |
936 | totlen -= len; | |
937 | continue; | |
938 | } | |
939 | off += len; | |
940 | if (off == totlen) { | |
941 | cp = buf + sizeof (struct ether_header); | |
942 | off = 0; | |
943 | totlen = off0; | |
944 | } | |
945 | } | |
946 | return (top); | |
947 | bad: | |
948 | m_freem(top); | |
949 | return (0); | |
950 | } | |
951 | ||
952 | /* | |
953 | * Map a chain of mbufs onto a network interface | |
954 | * in preparation for an i/o operation. | |
955 | * The argument chain of mbufs includes the local network | |
956 | * header which is copied to be in the mapped, aligned | |
957 | * i/o space. | |
958 | */ | |
959 | neput(cp, m) | |
960 | register caddr_t cp; | |
961 | register struct mbuf *m; | |
962 | { | |
963 | register struct mbuf *mp; | |
964 | register int i; | |
965 | int x, cc = 0, t; | |
966 | caddr_t dp; | |
967 | ||
968 | while (m) { | |
969 | dp = mtod(m, char *); | |
970 | bcopy(mtod(m, caddr_t), cp, (unsigned)m->m_len); | |
971 | cp += m->m_len; | |
972 | cc += m->m_len; | |
973 | MFREE(m, mp); | |
974 | m = mp; | |
975 | } | |
976 | return (max(cc, ETHERMIN + sizeof(struct ether_header))); | |
977 | } | |
978 | ||
979 | /* | |
980 | * Process an ioctl request. | |
981 | */ | |
982 | neioctl(ifp, cmd, data) | |
983 | register struct ifnet *ifp; | |
984 | int cmd; | |
985 | caddr_t data; | |
986 | { | |
987 | register struct ifaddr *ifa = (struct ifaddr *)data; | |
988 | struct ne_softc *ns = &ne_softc[ifp->if_unit]; | |
989 | struct ifreq *ifr = (struct ifreq *)data; | |
990 | int s = splimp(), error = 0; | |
991 | ||
992 | ||
993 | switch (cmd) { | |
994 | ||
995 | case SIOCSIFADDR: | |
996 | ifp->if_flags |= IFF_UP; | |
997 | ||
998 | switch (ifa->ifa_addr.sa_family) { | |
999 | #ifdef INET | |
1000 | case AF_INET: | |
1001 | neinit(ifp->if_unit); /* before arpwhohas */ | |
1002 | ((struct arpcom *)ifp)->ac_ipaddr = | |
1003 | IA_SIN(ifa)->sin_addr; | |
1004 | arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); | |
1005 | break; | |
1006 | #endif | |
1007 | #ifdef NS | |
1008 | case AF_NS: | |
1009 | { | |
1010 | register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); | |
1011 | ||
1012 | if (ns_nullhost(*ina)) | |
1013 | ina->x_host = *(union ns_host *)(ns->ns_addr); | |
1014 | else { | |
1015 | /* | |
1016 | * The manual says we can't change the address | |
1017 | * while the receiver is armed, | |
1018 | * so reset everything | |
1019 | */ | |
1020 | ifp->if_flags &= ~IFF_RUNNING; | |
1021 | bcopy((caddr_t)ina->x_host.c_host, | |
1022 | (caddr_t)ns->ns_addr, sizeof(ns->ns_addr)); | |
1023 | } | |
1024 | neinit(ifp->if_unit); /* does ne_setaddr() */ | |
1025 | break; | |
1026 | } | |
1027 | #endif | |
1028 | default: | |
1029 | neinit(ifp->if_unit); | |
1030 | break; | |
1031 | } | |
1032 | break; | |
1033 | ||
1034 | case SIOCSIFFLAGS: | |
1035 | if ((ifp->if_flags & IFF_UP) == 0 && | |
1036 | ifp->if_flags & IFF_RUNNING) { | |
1037 | ifp->if_flags &= ~IFF_RUNNING; | |
1038 | outb(nec+ds_cmd,DSCM_STOP|DSCM_NODMA); | |
1039 | } else if (ifp->if_flags & IFF_UP && | |
1040 | (ifp->if_flags & IFF_RUNNING) == 0) | |
1041 | neinit(ifp->if_unit); | |
1042 | break; | |
1043 | ||
1044 | #ifdef notdef | |
1045 | case SIOCGHWADDR: | |
1046 | bcopy((caddr_t)ns->ns_addr, (caddr_t) &ifr->ifr_data, | |
1047 | sizeof(ns->ns_addr)); | |
1048 | break; | |
1049 | #endif | |
1050 | ||
1051 | default: | |
1052 | error = EINVAL; | |
1053 | } | |
1054 | splx(s); | |
1055 | return (error); | |
1056 | } | |
1057 | ||
1058 | nesetaddr(ifp, sin) | |
1059 | register struct ifnet *ifp; | |
1060 | register struct sockaddr_in *sin; | |
1061 | { | |
1062 | #ifdef notdef | |
1063 | ifp->if_addr = *(struct sockaddr *)sin; | |
1064 | ifp->if_net = in_netof(sin->sin_addr); | |
1065 | ifp->if_host[0] = in_lnaof(sin->sin_addr); | |
1066 | if (nepaddr[ifp->if_unit][0] == '3') | |
1067 | nepaddr[ifp->if_unit][0] = ifp->if_host[0] << 1; | |
1068 | sin = (struct sockaddr_in *)&ifp->if_broadaddr; | |
1069 | sin->sin_family = AF_INET; | |
1070 | sin->sin_addr = in_makeaddr(ifp->if_net, INADDR_ANY); | |
1071 | ifp->if_flags |= IFF_BROADCAST; | |
1072 | #endif | |
1073 | } | |
1074 | #endif |