Commit | Line | Data |
---|---|---|
d747097c WJ |
1 | /*- |
2 | * Copyright (c) 1990, 1991 William F. Jolitz. | |
3 | * Copyright (c) 1990 The Regents of the University of California. | |
4 | * All rights reserved. | |
5 | * | |
6 | * Redistribution and use in source and binary forms, with or without | |
7 | * modification, are permitted provided that the following conditions | |
8 | * are met: | |
9 | * 1. Redistributions of source code must retain the above copyright | |
10 | * notice, this list of conditions and the following disclaimer. | |
11 | * 2. Redistributions in binary form must reproduce the above copyright | |
12 | * notice, this list of conditions and the following disclaimer in the | |
13 | * documentation and/or other materials provided with the distribution. | |
14 | * 3. All advertising materials mentioning features or use of this software | |
15 | * must display the following acknowledgement: | |
16 | * This product includes software developed by the University of | |
17 | * California, Berkeley and its contributors. | |
18 | * 4. Neither the name of the University nor the names of its contributors | |
19 | * may be used to endorse or promote products derived from this software | |
20 | * without specific prior written permission. | |
21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
32 | * SUCH DAMAGE. | |
33 | * | |
34 | * @(#)if_ne.c 7.4 (Berkeley) 5/21/91 | |
35 | */ | |
36 | ||
37 | /* | |
38 | * Isolink 4110-2 Ethernet driver | |
39 | */ | |
40 | ||
41 | #include "is.h" | |
42 | #if NIS > 0 | |
43 | ||
44 | #include "param.h" | |
45 | #include "systm.h" | |
46 | #include "mbuf.h" | |
47 | #include "buf.h" | |
48 | #include "protosw.h" | |
49 | #include "socket.h" | |
50 | #include "ioctl.h" | |
51 | #include "errno.h" | |
52 | #include "syslog.h" | |
53 | ||
54 | #include "net/if.h" | |
55 | #include "net/netisr.h" | |
56 | #include "net/route.h" | |
57 | ||
58 | #ifdef INET | |
59 | #include "netinet/in.h" | |
60 | #include "netinet/in_systm.h" | |
61 | #include "netinet/in_var.h" | |
62 | #include "netinet/ip.h" | |
63 | #include "netinet/if_ether.h" | |
64 | #endif | |
65 | ||
66 | #ifdef NS | |
67 | #include "netns/ns.h" | |
68 | #include "netns/ns_if.h" | |
69 | #endif | |
70 | ||
71 | #include "i386/isa/isa_device.h" | |
72 | #include "i386/isa/if_isreg.h" | |
73 | #include "i386/isa/icu.h" | |
74 | ||
75 | #include "vm/vm.h" | |
76 | ||
77 | /* Function prototypes */ | |
78 | int isprobe(), isattach(); | |
79 | int isioctl(),isinit(),isstart(); | |
80 | ||
81 | struct isa_driver isdriver = { | |
82 | isprobe, isattach, "is", | |
83 | }; | |
84 | ||
85 | ||
86 | struct mbuf *isget(); | |
87 | ||
88 | #define ETHER_MIN_LEN 64 | |
89 | ||
90 | /* | |
91 | * Ethernet software status per interface. | |
92 | * | |
93 | * Each interface is referenced by a network interface structure, | |
94 | * ns_if, which the routing code uses to locate the interface. | |
95 | * This structure contains the output queue for the interface, its address, ... | |
96 | */ | |
97 | struct is_softc { | |
98 | struct arpcom ns_ac; /* Ethernet common part */ | |
99 | #define ns_if ns_ac.ac_if /* network-visible interface */ | |
100 | #define ns_addr ns_ac.ac_enaddr /* hardware Ethernet address */ | |
101 | int last_rd; | |
102 | int last_td; | |
103 | int no_td; | |
104 | } is_softc[NIS] ; | |
105 | ||
106 | struct init_block init_block; | |
107 | struct mds *td, *rd; | |
108 | unsigned char *rbuf,*tbuf; | |
109 | ||
110 | int isc; | |
111 | ||
112 | iswrcsr(port,val) | |
113 | u_short port; | |
114 | u_short val; | |
115 | { | |
116 | outw(isc+RAP,port); | |
117 | outw(isc+RDP,val); | |
118 | } | |
119 | ||
120 | u_short isrdcsr(port) | |
121 | u_short port; | |
122 | { | |
123 | outw(isc+RAP,port); | |
124 | return(inw(isc+RDP)); | |
125 | } | |
126 | ||
127 | isprobe(dvp) | |
128 | struct isa_device *dvp; | |
129 | { | |
130 | int val,i,s; | |
131 | register struct is_softc *ns = &is_softc[0]; | |
132 | ||
133 | isc = dvp->id_iobase; | |
134 | s = splimp(); | |
135 | ||
136 | /* Stop the lance chip, put it known state */ | |
137 | iswrcsr(0,STOP); | |
138 | DELAY(100); | |
139 | ||
140 | /* is there a lance? */ | |
141 | iswrcsr(3, 0xffff); | |
142 | if (isrdcsr(3) != 7) { | |
143 | isc = 0; | |
144 | return (0); | |
145 | } | |
146 | iswrcsr(3, 0); | |
147 | ||
148 | /* Extract board address */ | |
149 | for(i=0; i < 6; i++) ns->ns_addr[i] = inb(isc+(i*2)); | |
150 | ||
151 | splx(s); | |
152 | return (1); | |
153 | } | |
154 | ||
155 | ||
156 | ||
157 | /* | |
158 | * Reset of interface. | |
159 | */ | |
160 | isreset(unit, uban) | |
161 | int unit, uban; | |
162 | { | |
163 | if (unit >= NIS) | |
164 | return; | |
165 | printf("is%d: reset\n", unit); | |
166 | isinit(unit); | |
167 | } | |
168 | ||
169 | /* | |
170 | * Interface exists: make available by filling in network interface | |
171 | * record. System will initialize the interface when it is ready | |
172 | * to accept packets. We get the ethernet address here. | |
173 | */ | |
174 | isattach(dvp) | |
175 | struct isa_device *dvp; | |
176 | { | |
177 | int unit = dvp->id_unit; | |
178 | register struct is_softc *is = &is_softc[unit]; | |
179 | register struct ifnet *ifp = &is->ns_if; | |
180 | ||
181 | /* Set up DMA */ | |
182 | isa_dmacascade(dvp->id_drq); | |
183 | ||
184 | ifp->if_unit = unit; | |
185 | ifp->if_name = isdriver.name ; | |
186 | ifp->if_mtu = ETHERMTU; | |
187 | printf (" ethernet address %s", ether_sprintf(is->ns_addr)) ; | |
188 | ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS; | |
189 | ifp->if_init = isinit; | |
190 | ifp->if_output = ether_output; | |
191 | ifp->if_start = isstart; | |
192 | ifp->if_ioctl = isioctl; | |
193 | ifp->if_reset = isreset; | |
194 | ifp->if_watchdog = 0; | |
195 | if_attach(ifp); | |
196 | } | |
197 | ||
198 | ||
199 | /* Lance initialisation block set up */ | |
200 | init_mem() | |
201 | { | |
202 | int i; | |
203 | u_long temp; | |
204 | ||
205 | /* Allocate memory */ | |
206 | /* Temporary hack, will use kmem_alloc in future */ | |
207 | #define MAXMEM ((NRBUF+NTBUF)*(BUFSIZE) + (NRBUF+NTBUF)*sizeof(struct mds) + 8) | |
208 | static u_char lance_mem[MAXMEM]; | |
209 | ||
210 | ||
211 | /* Align message descriptors on quad word boundary | |
212 | (this is essential) */ | |
213 | ||
214 | temp = (u_long) &lance_mem; | |
215 | temp = (temp+8) - (temp%8); | |
216 | rd = (struct mds *) temp; | |
217 | td = (struct mds *) (temp + (NRBUF*sizeof(struct mds))); | |
218 | temp += (NRBUF+NTBUF) * sizeof(struct mds); | |
219 | ||
220 | init_block.mode = 0; | |
221 | ||
222 | /* Get ethernet address */ | |
223 | for (i=0; i<6; i++) | |
224 | init_block.padr[i] = inb(isc+(i*2)); | |
225 | ||
226 | /* Clear multicast address for now */ | |
227 | for (i=0; i<8; i++) | |
228 | init_block.ladrf[i] = 0; | |
229 | ||
230 | init_block.rdra = kvtop(rd); | |
231 | init_block.rlen = ((kvtop(rd) >> 16) & 0xff) | (RLEN<<13); | |
232 | init_block.tdra = kvtop(td); | |
233 | init_block.tlen = ((kvtop(td) >> 16) & 0xff) | (TLEN<<13); | |
234 | ||
235 | /* Set up receive ring descriptors */ | |
236 | rbuf = (unsigned char *)temp; | |
237 | for (i=0; i<NRBUF; i++) { | |
238 | (rd+i)->addr = kvtop(temp); | |
239 | (rd+i)->flags= ((kvtop(temp) >> 16) & 0xff) | OWN; | |
240 | (rd+i)->bcnt = -BUFSIZE; | |
241 | (rd+i)->mcnt = 0; | |
242 | temp += BUFSIZE; | |
243 | } | |
244 | ||
245 | /* Set up transmit ring descriptors */ | |
246 | tbuf = (unsigned char *)temp; | |
247 | #ifdef ISDEBUG | |
248 | printf("rd = %x,td = %x, rbuf = %x, tbuf = %x,td+1=%x\n",rd,td,rbuf,tbuf,td+1); | |
249 | #endif | |
250 | for (i=0; i<NTBUF; i++) { | |
251 | (td+i)->addr = kvtop(temp); | |
252 | (td+i)->flags= ((kvtop(temp) >> 16) & 0xff); | |
253 | (td+i)->bcnt = 0; | |
254 | (td+i)->mcnt = 0; | |
255 | temp += BUFSIZE; | |
256 | } | |
257 | ||
258 | } | |
259 | ||
260 | /* | |
261 | * Initialization of interface; set up initialization block | |
262 | * and transmit/receive descriptor rings. | |
263 | */ | |
264 | isinit(unit) | |
265 | int unit; | |
266 | { | |
267 | register struct is_softc *ns = &is_softc[unit]; | |
268 | struct ifnet *ifp = &ns->ns_if; | |
269 | int s; | |
270 | register i; | |
271 | ||
272 | if (ifp->if_addrlist == (struct ifaddr *)0) return; | |
273 | ||
274 | ns->last_rd = ns->last_td = ns->no_td = 0; | |
275 | s = splimp(); | |
276 | ||
277 | /* Set up lance's memory area */ | |
278 | init_mem(); | |
279 | ||
280 | /* Stop Lance to get access to other registers */ | |
281 | iswrcsr(0,STOP); | |
282 | ||
283 | /* I wish I knew what this was */ | |
284 | iswrcsr(3,0); | |
285 | ||
286 | /* Give lance the physical address of its memory area */ | |
287 | iswrcsr(1,kvtop(&init_block)); | |
288 | iswrcsr(2,(kvtop(&init_block) >> 16) & 0xff); | |
289 | ||
290 | /* OK, let's try and initialise the Lance */ | |
291 | iswrcsr(0,INIT); | |
292 | ||
293 | /* Wait for initialisation to finish */ | |
294 | for(i=0; i<1000; i++){ | |
295 | if (isrdcsr(0)&IDON) | |
296 | break; | |
297 | } | |
298 | if (isrdcsr(0)&IDON) { | |
299 | /* Start lance */ | |
300 | iswrcsr(0,STRT|IDON|INEA); | |
301 | ns->ns_if.if_flags |= IFF_RUNNING; | |
302 | isstart(ifp); | |
303 | } | |
304 | else | |
305 | printf("Isolink card failed to initialise\n"); | |
306 | ||
307 | splx(s); | |
308 | } | |
309 | ||
310 | /* | |
311 | * Setup output on interface. | |
312 | * Get another datagram to send off of the interface queue, | |
313 | * and map it to the interface before starting the output. | |
314 | * called only at splimp or interrupt level. | |
315 | */ | |
316 | isstart(ifp) | |
317 | struct ifnet *ifp; | |
318 | { | |
319 | register struct is_softc *ns = &is_softc[ifp->if_unit]; | |
320 | struct mbuf *m0, *m; | |
321 | unsigned char *buffer; | |
322 | u_short len; | |
323 | int i; | |
324 | struct mds *cdm; | |
325 | ||
326 | ||
327 | if ((ns->ns_if.if_flags & IFF_RUNNING) == 0) | |
328 | return; | |
329 | ||
330 | do { | |
331 | cdm = (td + ns->last_td); | |
332 | if (cdm->flags&OWN) | |
333 | return; | |
334 | ||
335 | IF_DEQUEUE(&ns->ns_if.if_snd, m); | |
336 | ||
337 | if (m == 0) | |
338 | return; | |
339 | ||
340 | /* | |
341 | * Copy the mbuf chain into the transmit buffer | |
342 | */ | |
343 | ||
344 | buffer = tbuf+(BUFSIZE*ns->last_td); | |
345 | len=0; | |
346 | for (m0=m; m != 0; m=m->m_next) { | |
347 | bcopy(mtod(m,caddr_t),buffer,m->m_len); | |
348 | buffer += m->m_len; | |
349 | len += m->m_len; | |
350 | } | |
351 | ||
352 | m_freem(m0); | |
353 | len = MAX(len,ETHER_MIN_LEN); | |
354 | ||
355 | /* | |
356 | * Init transmit registers, and set transmit start flag. | |
357 | */ | |
358 | ||
359 | cdm->flags |= (OWN|STP|ENP); | |
360 | cdm->bcnt = -len; | |
361 | cdm->mcnt = 0; | |
362 | #ifdef ISDEBUG | |
363 | xmit_print(ns->last_td); | |
364 | #endif | |
365 | ||
366 | iswrcsr(0,TDMD|INEA); | |
367 | if (++ns->last_td >= NTBUF) | |
368 | ns->last_td=0; | |
369 | }while(++ns->no_td < NTBUF); | |
370 | ns->no_td = NTBUF; | |
371 | ns->ns_if.if_flags |= IFF_OACTIVE; | |
372 | #ifdef ISDEBUG | |
373 | printf("no_td = %x, last_td = %x\n",ns->no_td, ns->last_td); | |
374 | #endif | |
375 | return(0); | |
376 | } | |
377 | ||
378 | ||
379 | /* | |
380 | * Controller interrupt. | |
381 | */ | |
382 | isintr(unit) | |
383 | { | |
384 | register struct is_softc *ns = &is_softc[unit]; | |
385 | u_short isr; | |
386 | ||
387 | while((isr=isrdcsr(0))&INTR) { | |
388 | if (isr&ERR) { | |
389 | if (isr&BABL) | |
390 | printf("BABL\n"); | |
391 | if (isr&CERR) | |
392 | printf("CERR\n"); | |
393 | if (isr&MISS) | |
394 | printf("MISS\n"); | |
395 | if (isr&MERR) | |
396 | printf("MERR\n"); | |
397 | iswrcsr(0,BABL|CERR|MISS|MERR|INEA); | |
398 | } | |
399 | if (!(isr&TXON)) { | |
400 | isreset(unit); | |
401 | return(1); | |
402 | } | |
403 | if (!(isr&RXON)) { | |
404 | isreset(unit); | |
405 | return(1); | |
406 | } | |
407 | if (isr&RINT) { | |
408 | isrint(unit); | |
409 | } | |
410 | if (isr&TINT) { | |
411 | iswrcsr(0,TINT|INEA); | |
412 | istint(unit); | |
413 | } | |
414 | } | |
415 | } | |
416 | ||
417 | istint(unit) | |
418 | int unit; | |
419 | { | |
420 | struct is_softc *is = &is_softc[unit]; | |
421 | register struct ifnet *ifp = &is->ns_if; | |
422 | int i,loopcount=0; | |
423 | struct mds *cdm; | |
424 | ||
425 | do { | |
426 | if ((i=is->last_td - is->no_td) < 0) | |
427 | i+=NTBUF; | |
428 | cdm = (td+i); | |
429 | #ifdef ISDEBUG | |
430 | printf("Trans cdm = %x\n",cdm); | |
431 | #endif | |
432 | if (cdm->flags&OWN) { | |
433 | if (loopcount) | |
434 | break; | |
435 | return; | |
436 | } | |
437 | loopcount++; | |
438 | is->ns_if.if_flags &= ~IFF_OACTIVE; | |
439 | }while(--is->no_td > 0); | |
440 | isstart(ifp); | |
441 | ||
442 | } | |
443 | ||
444 | #define NEXTRDS \ | |
445 | if (++rmd == NRBUF) rmd=0, cdm=rd; else ++cdm | |
446 | ||
447 | isrint(unit) | |
448 | int unit; | |
449 | { | |
450 | register struct is_softc *is=&is_softc[unit]; | |
451 | register int rmd = is->last_rd; | |
452 | struct mds *cdm = (rd + rmd); | |
453 | ||
454 | /* Out of sync with hardware, should never happen */ | |
455 | ||
456 | if (cdm->flags & OWN) { | |
457 | printf("is0 error: out of sync\n"); | |
458 | iswrcsr(0,RINT|INEA); | |
459 | return; | |
460 | } | |
461 | ||
462 | /* Process all buffers with valid data */ | |
463 | while (!(cdm->flags&OWN)) { | |
464 | /* Clear interrupt to avoid race condition */ | |
465 | iswrcsr(0,RINT|INEA); | |
466 | if (cdm->flags&ERR) { | |
467 | if (cdm->flags&FRAM) | |
468 | printf("FRAM\n"); | |
469 | if (cdm->flags&OFLO) | |
470 | printf("OFLO\n"); | |
471 | if (cdm->flags&CRC) | |
472 | printf("CRC\n"); | |
473 | if (cdm->flags&RBUFF) | |
474 | printf("RBUFF\n"); | |
475 | }else | |
476 | if (cdm->flags&(STP|ENP) != (STP|ENP)) { | |
477 | do { | |
478 | iswrcsr(0,RINT|INEA); | |
479 | cdm->mcnt = 0; | |
480 | cdm->flags |= OWN; | |
481 | NEXTRDS; | |
482 | }while (!(cdm->flags&(OWN|ERR|STP|ENP))); | |
483 | is->last_rd = rmd; | |
484 | printf("Chained buffer\n"); | |
485 | if ((cdm->flags & (OWN|ERR|STP|ENP)) != ENP) { | |
486 | isreset(unit); | |
487 | return; | |
488 | } | |
489 | }else | |
490 | { | |
491 | #ifdef ISDEBUG | |
492 | recv_print(is->last_rd); | |
493 | #endif | |
494 | isread(is,rbuf+(BUFSIZE*rmd),cdm->mcnt); | |
495 | } | |
496 | ||
497 | cdm->flags |= OWN; | |
498 | cdm->mcnt = 0; | |
499 | NEXTRDS; | |
500 | #ifdef ISDEBUG | |
501 | printf("is->last_rd = %x, cdm = %x\n",is->last_rd,cdm); | |
502 | #endif | |
503 | } /* while */ | |
504 | is->last_rd = rmd; | |
505 | } /* isrint */ | |
506 | ||
507 | /* | |
508 | * Pass a packet to the higher levels. | |
509 | * We deal with the trailer protocol here. | |
510 | */ | |
511 | isread(ns, buf, len) | |
512 | register struct is_softc *ns; | |
513 | char *buf; | |
514 | int len; | |
515 | { | |
516 | register struct ether_header *eh; | |
517 | struct mbuf *m; | |
518 | int off, resid; | |
519 | register struct ifqueue *inq; | |
520 | ||
521 | /* | |
522 | * Deal with trailer protocol: if type is trailer type | |
523 | * get true type from first 16-bit word past data. | |
524 | * Remember that type was trailer by setting off. | |
525 | */ | |
526 | eh = (struct ether_header *)buf; | |
527 | eh->ether_type = ntohs((u_short)eh->ether_type); | |
528 | len = len - sizeof(struct ether_header) - 4; | |
529 | #define nedataaddr(eh, off, type) ((type)(((caddr_t)((eh)+1)+(off)))) | |
530 | if (eh->ether_type >= ETHERTYPE_TRAIL && | |
531 | eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { | |
532 | off = (eh->ether_type - ETHERTYPE_TRAIL) * 512; | |
533 | if (off >= ETHERMTU) return; /* sanity */ | |
534 | eh->ether_type = ntohs(*nedataaddr(eh, off, u_short *)); | |
535 | resid = ntohs(*(nedataaddr(eh, off+2, u_short *))); | |
536 | if (off + resid > len) return; /* sanity */ | |
537 | len = off + resid; | |
538 | } else off = 0; | |
539 | ||
540 | if (len == 0) return; | |
541 | ||
542 | /* | |
543 | * Pull packet off interface. Off is nonzero if packet | |
544 | * has trailing header; neget will then force this header | |
545 | * information to be at the front, but we still have to drop | |
546 | * the type and length which are at the front of any trailer data. | |
547 | */ | |
548 | m = isget(buf, len, off, &ns->ns_if); | |
549 | if (m == 0) return; | |
550 | ||
551 | ether_input(&ns->ns_if, eh, m); | |
552 | } | |
553 | ||
554 | /* | |
555 | * Supporting routines | |
556 | */ | |
557 | ||
558 | /* | |
559 | * Pull read data off a interface. | |
560 | * Len is length of data, with local net header stripped. | |
561 | * Off is non-zero if a trailer protocol was used, and | |
562 | * gives the offset of the trailer information. | |
563 | * We copy the trailer information and then all the normal | |
564 | * data into mbufs. When full cluster sized units are present | |
565 | * we copy into clusters. | |
566 | */ | |
567 | struct mbuf * | |
568 | isget(buf, totlen, off0, ifp) | |
569 | caddr_t buf; | |
570 | int totlen, off0; | |
571 | struct ifnet *ifp; | |
572 | { | |
573 | struct mbuf *top, **mp, *m, *p; | |
574 | int off = off0, len; | |
575 | register caddr_t cp = buf; | |
576 | char *epkt; | |
577 | ||
578 | buf += sizeof(struct ether_header); | |
579 | cp = buf; | |
580 | epkt = cp + totlen; | |
581 | ||
582 | ||
583 | if (off) { | |
584 | cp += off + 2 * sizeof(u_short); | |
585 | totlen -= 2 * sizeof(u_short); | |
586 | } | |
587 | ||
588 | MGETHDR(m, M_DONTWAIT, MT_DATA); | |
589 | if (m == 0) | |
590 | return (0); | |
591 | m->m_pkthdr.rcvif = ifp; | |
592 | m->m_pkthdr.len = totlen; | |
593 | m->m_len = MHLEN; | |
594 | ||
595 | top = 0; | |
596 | mp = ⊤ | |
597 | while (totlen > 0) { | |
598 | if (top) { | |
599 | MGET(m, M_DONTWAIT, MT_DATA); | |
600 | if (m == 0) { | |
601 | m_freem(top); | |
602 | return (0); | |
603 | } | |
604 | m->m_len = MLEN; | |
605 | } | |
606 | len = min(totlen, epkt - cp); | |
607 | if (len >= MINCLSIZE) { | |
608 | MCLGET(m, M_DONTWAIT); | |
609 | if (m->m_flags & M_EXT) | |
610 | m->m_len = len = min(len, MCLBYTES); | |
611 | else | |
612 | len = m->m_len; | |
613 | } else { | |
614 | /* | |
615 | * Place initial small packet/header at end of mbuf. | |
616 | */ | |
617 | if (len < m->m_len) { | |
618 | if (top == 0 && len + max_linkhdr <= m->m_len) | |
619 | m->m_data += max_linkhdr; | |
620 | m->m_len = len; | |
621 | } else | |
622 | len = m->m_len; | |
623 | } | |
624 | bcopy(cp, mtod(m, caddr_t), (unsigned)len); | |
625 | cp += len; | |
626 | *mp = m; | |
627 | mp = &m->m_next; | |
628 | totlen -= len; | |
629 | if (cp == epkt) | |
630 | cp = buf; | |
631 | } | |
632 | return (top); | |
633 | } | |
634 | ||
635 | /* | |
636 | * Process an ioctl request. | |
637 | */ | |
638 | isioctl(ifp, cmd, data) | |
639 | register struct ifnet *ifp; | |
640 | int cmd; | |
641 | caddr_t data; | |
642 | { | |
643 | register struct ifaddr *ifa = (struct ifaddr *)data; | |
644 | struct is_softc *ns = &is_softc[ifp->if_unit]; | |
645 | struct ifreq *ifr = (struct ifreq *)data; | |
646 | int s = splimp(), error = 0; | |
647 | ||
648 | ||
649 | switch (cmd) { | |
650 | ||
651 | case SIOCSIFADDR: | |
652 | ifp->if_flags |= IFF_UP; | |
653 | ||
654 | switch (ifa->ifa_addr->sa_family) { | |
655 | #ifdef INET | |
656 | case AF_INET: | |
657 | isinit(ifp->if_unit); /* before arpwhohas */ | |
658 | ((struct arpcom *)ifp)->ac_ipaddr = | |
659 | IA_SIN(ifa)->sin_addr; | |
660 | arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); | |
661 | break; | |
662 | #endif | |
663 | #ifdef NS | |
664 | case AF_NS: | |
665 | { | |
666 | register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); | |
667 | ||
668 | if (ns_nullhost(*ina)) | |
669 | ina->x_host = *(union ns_host *)(ns->ns_addr); | |
670 | else { | |
671 | /* | |
672 | * The manual says we can't change the address | |
673 | * while the receiver is armed, | |
674 | * so reset everything | |
675 | */ | |
676 | ifp->if_flags &= ~IFF_RUNNING; | |
677 | bcopy((caddr_t)ina->x_host.c_host, | |
678 | (caddr_t)ns->ns_addr, sizeof(ns->ns_addr)); | |
679 | } | |
680 | isinit(ifp->if_unit); /* does ne_setaddr() */ | |
681 | break; | |
682 | } | |
683 | #endif | |
684 | default: | |
685 | isinit(ifp->if_unit); | |
686 | break; | |
687 | } | |
688 | break; | |
689 | ||
690 | case SIOCSIFFLAGS: | |
691 | if ((ifp->if_flags & IFF_UP) == 0 && | |
692 | ifp->if_flags & IFF_RUNNING) { | |
693 | ifp->if_flags &= ~IFF_RUNNING; | |
694 | iswrcsr(0,STOP); | |
695 | } else if (ifp->if_flags & IFF_UP && | |
696 | (ifp->if_flags & IFF_RUNNING) == 0) | |
697 | isinit(ifp->if_unit); | |
698 | break; | |
699 | ||
700 | #ifdef notdef | |
701 | case SIOCGHWADDR: | |
702 | bcopy((caddr_t)ns->ns_addr, (caddr_t) &ifr->ifr_data, | |
703 | sizeof(ns->ns_addr)); | |
704 | break; | |
705 | #endif | |
706 | ||
707 | default: | |
708 | error = EINVAL; | |
709 | } | |
710 | splx(s); | |
711 | return (error); | |
712 | } | |
713 | ||
714 | recv_print(no) | |
715 | int no; | |
716 | { | |
717 | struct mds *rmd; | |
718 | int len,i; | |
719 | ||
720 | rmd = (rd+no); | |
721 | len = rmd->mcnt; | |
722 | printf("Receive buffer %d, len = %d\n",no,len); | |
723 | printf("Status %x\n",isrdcsr(0)); | |
724 | for (i=0; i<len; i++) | |
725 | printf("%x ",*(rbuf+(BUFSIZE*no)+i)); | |
726 | printf("\n"); | |
727 | } | |
728 | ||
729 | xmit_print(no) | |
730 | int no; | |
731 | { | |
732 | struct mds *rmd; | |
733 | int i; | |
734 | u_short len; | |
735 | ||
736 | rmd = (td+no); | |
737 | len = -(rmd->bcnt); | |
738 | printf("Transmit buffer %d, len = %d\n",no,len); | |
739 | printf("Status %x\n",isrdcsr(0)); | |
740 | printf("addr %x, flags %x, bcnt %x, mcnt %x\n", | |
741 | rmd->addr,rmd->flags,rmd->bcnt,rmd->mcnt); | |
742 | for (i=0; i<len; i++) | |
743 | printf("%x ",*(tbuf+(BUFSIZE*no)+i)); | |
744 | printf("\n"); | |
745 | } | |
746 | ||
747 | #endif |