Commit | Line | Data |
---|---|---|
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 | ||
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; | |
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 | */ | |
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); | |
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 | */ | |
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 | ||
c6b0f337 BJ |
371 | #ifdef NEDEBUG |
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 | ||
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 | 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 BJ |
395 | redstack(); |
396 | /* save cmd, clear interrupt */ | |
93b2b8c5 | 397 | cmd = inb (nec+ds_cmd); |
c6b0f337 | 398 | loop: |
93b2b8c5 | 399 | isr = inb (nec+ds0_isr); |
c6b0f337 BJ |
400 | #ifdef NEDEBUG |
401 | dprintf(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 | 421 | printf("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 | 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); | |
c6b0f337 | 456 | #ifdef NEDEBUG |
93b2b8c5 | 457 | printf("\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 |
479 | dprintf(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 { | |
496 | printf("cur %x pnd %x lfr %x ", ns->ns_cur, pend, lastfree); | |
497 | printf("nxt %x len %x ", ns->ns_ph.pr_nxtpg, (ns->ns_ph.pr_sz1<<8)+ | |
498 | ns->ns_ph.pr_sz0); | |
499 | pg("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 | 505 | dprintf(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 | |
521 | dprintf(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 | |
529 | dprintf(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 | */ | |
557 | nerecv(ns) | |
558 | register struct ne_softc *ns; | |
559 | { | |
560 | int len,i; | |
561 | ||
562 | ns->ns_if.if_ipackets++; | |
563 | len = ns->ns_ph.pr_sz0 + (ns->ns_ph.pr_sz1<<8); | |
c6b0f337 BJ |
564 | if(len < 60 || len > 1536) { |
565 | #ifdef NEDEBUG | |
566 | pg(DEXPAND,"R Bogus Length %d", len); | |
567 | #endif | |
568 | return; | |
569 | } | |
93b2b8c5 | 570 | fetchram(ns->ns_pb,ns->ns_ba,min(len,DS_PGSIZE-sizeof(ns->ns_ph))); |
c6b0f337 | 571 | #ifdef NEDEBUG |
93b2b8c5 BJ |
572 | if (!bcmp((caddr_t)ns->ns_pb, (caddr_t)ns->ns_addr, 6) |
573 | && !bcmp((caddr_t)ns->ns_pb, (caddr_t)etherbroadcastaddr, 6)) { | |
574 | printf("G%x ", ns->ns_cur); | |
575 | return; | |
576 | }/* else | |
577 | printf("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 |
584 | dprintf(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 |
595 | dprintf(DEXPAND,"%d|", p - ns->ns_pb); | |
596 | #endif | |
93b2b8c5 | 597 | } |
c6b0f337 BJ |
598 | #ifdef NEDEBUG |
599 | dprintf(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 |
612 | pausestr(s,n) char *s; { |
613 | static 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 | */ | |
628 | neread(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 | */ | |
713 | neoutput(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 | ||
792 | gottrailertype: | |
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 | ||
804 | gottype: | |
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 | ||
845 | bad: | |
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 | */ | |
865 | struct mbuf * | |
866 | neget(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 = ⊤ | |
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); | |
927 | bad: | |
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 | */ | |
939 | neput(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 | */ | |
962 | neioctl(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 | ||
1038 | nesetaddr(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 |