if_le.c revision 1.4 1 /*
2 * Copyright (c) 1982, 1990 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * from: @(#)if_le.c 7.6 (Berkeley) 5/8/91
34 * $Id: if_le.c,v 1.4 1994/02/12 00:00:08 chopps Exp $
35 */
36
37 #include "le.h"
38 #if NLE > 0
39
40 #include "bpfilter.h"
41
42 /*
43 * AMD 7990 LANCE
44 *
45 * This driver will generate and accept tailer encapsulated packets even
46 * though it buys us nothing. The motivation was to avoid incompatibilities
47 * with VAXen, SUNs, and others that handle and benefit from them.
48 * This reasoning is dubious.
49 */
50 #include "sys/param.h"
51 #include "sys/systm.h"
52 #include "sys/mbuf.h"
53 #include "sys/buf.h"
54 #include "sys/protosw.h"
55 #include "sys/socket.h"
56 #include "sys/syslog.h"
57 #include "sys/ioctl.h"
58 #include "sys/errno.h"
59
60 #include "net/if.h"
61 #include "net/netisr.h"
62 #include "net/route.h"
63
64 #ifdef INET
65 #include "netinet/in.h"
66 #include "netinet/in_systm.h"
67 #include "netinet/in_var.h"
68 #include "netinet/ip.h"
69 #include "netinet/if_ether.h"
70 #endif
71
72 #ifdef NS
73 #include "netns/ns.h"
74 #include "netns/ns_if.h"
75 #endif
76
77 #ifdef RMP
78 #include "netrmp/rmp.h"
79 #include "netrmp/rmp_var.h"
80 #endif
81
82 #include "../include/cpu.h"
83 #include "../include/mtpr.h"
84 #include "device.h"
85 #include "if_lereg.h"
86
87 #if NBPFILTER > 0
88 #include "../net/bpf.h"
89 #include "../net/bpfdesc.h"
90 #endif
91
92 #if 0
93 /* offsets for: ID, REGS, MEM, NVRAM */
94 int lestd[] = { 0, 0x4000, 0x8000, 0xC008 };
95 #else
96 /* offsets for: ID, REGS, MEM */
97 int lestd[] = { 0, 0x4000, 0x8000 };
98 #endif
99
100 int leattach();
101 struct driver ledriver = {
102 leattach, "le",
103 };
104
105 #if 0
106 struct isr le_isr[NLE];
107 #endif
108 int ledebug = 0; /* console error messages */
109
110 int leintr(), leinit(), leioctl(), lestart(), ether_output();
111 struct mbuf *leget();
112 extern struct ifnet loif;
113
114 /*
115 * Ethernet software status per interface.
116 *
117 * Each interface is referenced by a network interface structure,
118 * le_if, which the routing code uses to locate the interface.
119 * This structure contains the output queue for the interface, its address, ...
120 */
121 struct le_softc {
122 struct arpcom sc_ac; /* common Ethernet structures */
123 #define sc_if sc_ac.ac_if /* network-visible interface */
124 #define sc_addr sc_ac.ac_enaddr /* hardware Ethernet address */
125 void *sc_base; /* base address of board */
126 struct lereg1 *sc_r1; /* LANCE registers */
127 struct lereg2 *sc_r2; /* dual-port RAM */
128 int sc_rmd; /* predicted next rmd to process */
129 int sc_runt;
130 int sc_jab;
131 int sc_merr;
132 int sc_babl;
133 int sc_cerr;
134 int sc_miss;
135 int sc_xint;
136 int sc_xown;
137 int sc_uflo;
138 int sc_rxlen;
139 int sc_rxoff;
140 int sc_txoff;
141 int sc_busy;
142 short sc_iflags;
143 #if NBPFILTER > 0
144 caddr_t sc_bpf;
145 #endif
146 } le_softc[NLE];
147
148
149 /*
150 * Interface exists: make available by filling in network interface
151 * record. System will initialize the interface when it is ready
152 * to accept packets.
153 */
154 leattach(ad)
155 struct amiga_device *ad;
156 {
157 register struct lereg0 *ler0;
158 register struct lereg2 *ler2;
159 struct lereg2 *lemem = (struct lereg2 *) 0x8000;
160 struct le_softc *le = &le_softc[ad->amiga_unit];
161 struct ifnet *ifp = &le->sc_if;
162 char *cp;
163 int i;
164 unsigned long ser;
165 int s = splhigh ();
166
167 ler0 = le->sc_base = ad->amiga_addr;
168 le->sc_r1 = (struct lereg1 *)(lestd[1] + (int)ad->amiga_addr);
169 ler2 = le->sc_r2 = (struct lereg2 *)(lestd[2] + (int)ad->amiga_addr);
170
171 #if 0
172 if (ler0->ler0_id == 0xff)
173 goto noreset;
174 if (ler0->ler0_id != LEID)
175 {
176 le->sc_base = 0;
177 splx (s);
178 printf ("le%d: ler0_id[%d] != LEID[%d], board ignored.\n",
179 ad->amiga_unit, ler0->ler0_id, LEID);
180 return(0);
181 }
182 le_isr[ad->amiga_unit].isr_intr = leintr;
183 ad->amiga_ipl = le_isr[ad->amiga_unit].isr_ipl = LE_IPL(ler0->ler0_status);
184 le_isr[ad->amiga_unit].isr_arg = ad->amiga_unit;
185 ler0->ler0_id = 0xFF;
186 DELAY(100);
187 noreset:
188
189 /*
190 * Read the ethernet address off the board, one nibble at a time.
191 */
192 cp = (char *)(lestd[3] + (int)ad->amiga_addr);
193 for (i = 0; i < sizeof(le->sc_addr); i++) {
194 le->sc_addr[i] = (*++cp & 0xF) << 4;
195 cp++;
196 le->sc_addr[i] |= *++cp & 0xF;
197 cp++;
198 }
199 #else
200 /* serial number contains this information. Manufacturer decides
201 the 3 first bytes. */
202 ser = (unsigned long) ad->amiga_serno;
203 if ((ser >> 24) == 1)
204 {
205 /* Commodore */
206 le->sc_addr[0] = 0x00;
207 le->sc_addr[1] = 0x80;
208 le->sc_addr[2] = 0x10;
209 }
210 else if ((ser >> 24) == 2)
211 {
212 le->sc_addr[0] = 0x00;
213 le->sc_addr[1] = 0x00;
214 le->sc_addr[2] = 0x9f;
215 }
216 le->sc_addr[3] = (ser >> 16) & 0xff;
217 le->sc_addr[4] = (ser >> 8) & 0xff;
218 le->sc_addr[5] = (ser ) & 0xff;
219 #endif
220 printf("le%d: hardware address %s\n", ad->amiga_unit,
221 ether_sprintf(le->sc_addr));
222
223 /*
224 * Setup for transmit/receive
225 */
226 ler2->ler2_mode = LE_MODE;
227 ler2->ler2_padr[0] = le->sc_addr[1];
228 ler2->ler2_padr[1] = le->sc_addr[0];
229 ler2->ler2_padr[2] = le->sc_addr[3];
230 ler2->ler2_padr[3] = le->sc_addr[2];
231 ler2->ler2_padr[4] = le->sc_addr[5];
232 ler2->ler2_padr[5] = le->sc_addr[4];
233 #ifdef RMP
234 /*
235 * Set up logical addr filter to accept multicast 9:0:9:0:0:4
236 * This should be an ioctl() to the driver. (XXX)
237 */
238 ler2->ler2_ladrf0 = 0x00100000;
239 ler2->ler2_ladrf1 = 0x0;
240 #else
241 ler2->ler2_ladrf0 = 0;
242 ler2->ler2_ladrf1 = 0;
243 #endif
244 ler2->ler2_rlen = LE_RLEN;
245 ler2->ler2_rdra = (int)lemem->ler2_rmd;
246 ler2->ler2_tlen = LE_TLEN;
247 ler2->ler2_tdra = (int)lemem->ler2_tmd;
248 #if 0
249 isrlink(&le_isr[ad->amiga_unit]);
250 #endif
251 splx (s);
252
253 ifp->if_unit = ad->amiga_unit;
254 ifp->if_name = "le";
255 ifp->if_mtu = ETHERMTU;
256 ifp->if_ioctl = leioctl;
257 ifp->if_output = ether_output;
258 ifp->if_start = lestart;
259 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
260 #if NBPFILTER > 0
261 bpfattach(&le->sc_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
262 #endif
263 if_attach(ifp);
264 return (1);
265 }
266
267 ledrinit(ler2)
268 register struct lereg2 *ler2;
269 {
270 register struct lereg2 *lemem = (struct lereg2 *) 0x8000;
271 register int i;
272
273 for (i = 0; i < LERBUF; i++) {
274 ler2->ler2_rmd[i].rmd0 = (int)lemem->ler2_rbuf[i];
275 ler2->ler2_rmd[i].rmd1 = LE_OWN;
276 ler2->ler2_rmd[i].rmd2 = -LEMTU;
277 ler2->ler2_rmd[i].rmd3 = 0;
278 }
279 for (i = 0; i < LETBUF; i++) {
280 ler2->ler2_tmd[i].tmd0 = (int)lemem->ler2_tbuf[i];
281 ler2->ler2_tmd[i].tmd1 = 0;
282 ler2->ler2_tmd[i].tmd2 = 0;
283 ler2->ler2_tmd[i].tmd3 = 0;
284 }
285 }
286
287 lereset(unit)
288 register int unit;
289 {
290 register struct le_softc *le = &le_softc[unit];
291 register struct lereg1 *ler1 = le->sc_r1;
292 register struct lereg2 *lemem = (struct lereg2 *) 0x8000;
293 register int timo = 100000;
294 register int stat;
295
296 #ifdef lint
297 stat = unit;
298 #endif
299 #if NBPFILTER > 0
300 if (le->sc_if.if_flags & IFF_PROMISC)
301 /* set the promiscuous bit */
302 le->sc_r2->ler2_mode = LE_MODE|0x8000;
303 else
304 le->sc_r2->ler2_mode = LE_MODE;
305 #endif
306 ler1->ler1_rap = LE_CSR0;
307 ler1->ler1_rdp = LE_STOP;
308 ledrinit(le->sc_r2);
309 le->sc_rmd = 0;
310 ler1->ler1_rap = LE_CSR1;
311 ler1->ler1_rdp = (int)&lemem->ler2_mode;
312 ler1->ler1_rap = LE_CSR2;
313 ler1->ler1_rdp = 0;
314 ler1->ler1_rap = LE_CSR0;
315 ler1->ler1_rdp = LE_INIT;
316 do {
317 if (--timo == 0) {
318 printf("le%d: init timeout, stat = 0x%x\n",
319 unit, stat);
320 break;
321 }
322 stat = ler1->ler1_rdp;
323 } while ((stat & LE_IDON) == 0);
324 ler1->ler1_rdp = LE_STOP;
325 ler1->ler1_rap = LE_CSR3;
326 ler1->ler1_rdp = LE_BSWP;
327 ler1->ler1_rap = LE_CSR0;
328 ler1->ler1_rdp = LE_STRT | LE_INEA;
329 le->sc_if.if_flags &= ~IFF_OACTIVE;
330 }
331
332 /*
333 * Initialization of interface
334 */
335 leinit(unit)
336 int unit;
337 {
338 struct le_softc *le = &le_softc[unit];
339 register struct ifnet *ifp = &le->sc_if;
340 int s;
341
342 /* not yet, if address still unknown */
343 if (ifp->if_addrlist == (struct ifaddr *)0)
344 return;
345 if ((ifp->if_flags & IFF_RUNNING) == 0) {
346 s = splimp();
347 ifp->if_flags |= IFF_RUNNING;
348 lereset(unit);
349 (void) lestart(ifp);
350 splx(s);
351 }
352 }
353
354 /*
355 * Start output on interface. Get another datagram to send
356 * off of the interface queue, and copy it to the interface
357 * before starting the output.
358 */
359 lestart(ifp)
360 struct ifnet *ifp;
361 {
362 register struct le_softc *le = &le_softc[ifp->if_unit];
363 register struct letmd *tmd;
364 register struct mbuf *m;
365 int len;
366
367 if ((le->sc_if.if_flags & IFF_RUNNING) == 0)
368 return (0);
369 IF_DEQUEUE(&le->sc_if.if_snd, m);
370 if (m == 0)
371 return (0);
372 len = leput(le->sc_r2->ler2_tbuf[0], m);
373 #if NBPFILTER > 0
374 /*
375 * If bpf is listening on this interface, let it
376 * see the packet before we commit it to the wire.
377 */
378 if (le->sc_bpf)
379 bpf_tap(le->sc_bpf, le->sc_r2->ler2_tbuf[0], len);
380 #endif
381 tmd = le->sc_r2->ler2_tmd;
382 tmd->tmd3 = 0;
383 tmd->tmd2 = -len;
384 tmd->tmd1 = LE_OWN | LE_STP | LE_ENP;
385 le->sc_if.if_flags |= IFF_OACTIVE;
386 return (0);
387 }
388
389 leintr(unit)
390 register int unit;
391 {
392 register struct le_softc *le = &le_softc[unit];
393 register struct lereg1 *ler1;
394 register int stat;
395
396 /* if not even initialized, don't do anything further.. */
397 if (! le->sc_base)
398 return 0;
399
400 ler1 = le->sc_r1;
401 stat = ler1->ler1_rdp;
402
403 if (! (stat & LE_INTR))
404 return 0;
405
406 if (stat & LE_SERR) {
407 leerror(unit, stat);
408 if (stat & LE_MERR) {
409 le->sc_merr++;
410 lereset(unit);
411 return(1);
412 }
413 if (stat & LE_BABL)
414 le->sc_babl++;
415 if (stat & LE_CERR)
416 le->sc_cerr++;
417 if (stat & LE_MISS)
418 le->sc_miss++;
419 ler1->ler1_rdp = LE_BABL|LE_CERR|LE_MISS|LE_INEA;
420 }
421 if ((stat & LE_RXON) == 0) {
422 le->sc_rxoff++;
423 lereset(unit);
424 return(1);
425 }
426 if ((stat & LE_TXON) == 0) {
427 le->sc_txoff++;
428 lereset(unit);
429 return(1);
430 }
431 if (stat & LE_RINT) {
432 /* interrupt is cleared in lerint */
433 lerint(unit);
434 }
435 if (stat & LE_TINT) {
436 ler1->ler1_rdp = LE_TINT|LE_INEA;
437 lexint(unit);
438 }
439 return(1);
440 }
441
442 /*
443 * Ethernet interface transmitter interrupt.
444 * Start another output if more data to send.
445 */
446 lexint(unit)
447 register int unit;
448 {
449 register struct le_softc *le = &le_softc[unit];
450 register struct letmd *tmd = le->sc_r2->ler2_tmd;
451
452 if ((le->sc_if.if_flags & IFF_OACTIVE) == 0) {
453 le->sc_xint++;
454 return;
455 }
456 if (tmd->tmd1 & LE_OWN) {
457 le->sc_xown++;
458 return;
459 }
460 if (tmd->tmd1 & LE_ERR) {
461 err:
462 lexerror(unit);
463 le->sc_if.if_oerrors++;
464 if (tmd->tmd3 & (LE_TBUFF|LE_UFLO)) {
465 le->sc_uflo++;
466 lereset(unit);
467 }
468 else if (tmd->tmd3 & LE_LCOL)
469 le->sc_if.if_collisions++;
470 else if (tmd->tmd3 & LE_RTRY)
471 le->sc_if.if_collisions += 16;
472 }
473 else if (tmd->tmd3 & LE_TBUFF)
474 /* XXX documentation says BUFF not included in ERR */
475 goto err;
476 else if (tmd->tmd1 & LE_ONE)
477 le->sc_if.if_collisions++;
478 else if (tmd->tmd1 & LE_MORE)
479 /* what is the real number? */
480 le->sc_if.if_collisions += 2;
481 else
482 le->sc_if.if_opackets++;
483 le->sc_if.if_flags &= ~IFF_OACTIVE;
484 (void) lestart(&le->sc_if);
485 }
486
487 #define LENEXTRMP \
488 if (++bix == LERBUF) bix = 0, rmd = le->sc_r2->ler2_rmd; else ++rmd
489
490 /*
491 * Ethernet interface receiver interrupt.
492 * If input error just drop packet.
493 * Decapsulate packet based on type and pass to type specific
494 * higher-level input routine.
495 */
496 lerint(unit)
497 int unit;
498 {
499 register struct le_softc *le = &le_softc[unit];
500 register int bix = le->sc_rmd;
501 register struct lermd *rmd = &le->sc_r2->ler2_rmd[bix];
502
503 /*
504 * Out of sync with hardware, should never happen?
505 */
506 if (rmd->rmd1 & LE_OWN) {
507 le->sc_r1->ler1_rdp = LE_RINT|LE_INEA;
508 return;
509 }
510
511 /*
512 * Process all buffers with valid data
513 */
514 while ((rmd->rmd1 & LE_OWN) == 0) {
515 int len = rmd->rmd3;
516
517 /* Clear interrupt to avoid race condition */
518 le->sc_r1->ler1_rdp = LE_RINT|LE_INEA;
519
520 if (rmd->rmd1 & LE_ERR) {
521 le->sc_rmd = bix;
522 lererror(unit, "bad packet");
523 le->sc_if.if_ierrors++;
524 } else if ((rmd->rmd1 & (LE_STP|LE_ENP)) != (LE_STP|LE_ENP)) {
525 /*
526 * Find the end of the packet so we can see how long
527 * it was. We still throw it away.
528 */
529 do {
530 le->sc_r1->ler1_rdp = LE_RINT|LE_INEA;
531 rmd->rmd3 = 0;
532 rmd->rmd1 = LE_OWN;
533 LENEXTRMP;
534 } while (!(rmd->rmd1 & (LE_OWN|LE_ERR|LE_STP|LE_ENP)));
535 le->sc_rmd = bix;
536 lererror(unit, "chained buffer");
537 le->sc_rxlen++;
538 /*
539 * If search terminated without successful completion
540 * we reset the hardware (conservative).
541 */
542 if ((rmd->rmd1 & (LE_OWN|LE_ERR|LE_STP|LE_ENP)) !=
543 LE_ENP) {
544 lereset(unit);
545 return;
546 }
547 } else
548 leread(unit, le->sc_r2->ler2_rbuf[bix], len);
549 rmd->rmd3 = 0;
550 rmd->rmd1 = LE_OWN;
551 LENEXTRMP;
552 }
553 le->sc_rmd = bix;
554 }
555
556 leread(unit, buf, len)
557 int unit;
558 char *buf;
559 int len;
560 {
561 register struct le_softc *le = &le_softc[unit];
562 register struct ether_header *et;
563 struct mbuf *m;
564 int off, resid;
565
566 le->sc_if.if_ipackets++;
567 et = (struct ether_header *)buf;
568 et->ether_type = ntohs((u_short)et->ether_type);
569 /* adjust input length to account for header and CRC */
570 len = len - sizeof(struct ether_header) - 4;
571
572 #ifdef RMP
573 /* (XXX)
574 *
575 * If Ethernet Type field is < MaxPacketSize, we probably have
576 * a IEEE802 packet here. Make sure that the size is at least
577 * that of the HP LLC. Also do sanity checks on length of LLC
578 * (old Ethernet Type field) and packet length.
579 *
580 * Provided the above checks succeed, change `len' to reflect
581 * the length of the LLC (i.e. et->ether_type) and change the
582 * type field to ETHERTYPE_IEEE so we can switch() on it later.
583 * Yes, this is a hack and will eventually be done "right".
584 */
585 if (et->ether_type <= IEEE802LEN_MAX && len >= sizeof(struct amiga_llc) &&
586 len >= et->ether_type && len >= IEEE802LEN_MIN) {
587 len = et->ether_type;
588 et->ether_type = ETHERTYPE_IEEE; /* hack! */
589 }
590 #endif
591
592 #define ledataaddr(et, off, type) ((type)(((caddr_t)((et)+1)+(off))))
593 if (et->ether_type >= ETHERTYPE_TRAIL &&
594 et->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
595 off = (et->ether_type - ETHERTYPE_TRAIL) * 512;
596 if (off >= ETHERMTU)
597 return; /* sanity */
598 et->ether_type = ntohs(*ledataaddr(et, off, u_short *));
599 resid = ntohs(*(ledataaddr(et, off+2, u_short *)));
600 if (off + resid > len)
601 return; /* sanity */
602 len = off + resid;
603 } else
604 off = 0;
605
606 if (len <= 0) {
607 if (ledebug)
608 log(LOG_WARNING,
609 "le%d: ierror(runt packet): from %s: len=%d\n",
610 unit, ether_sprintf(et->ether_shost), len);
611 le->sc_runt++;
612 le->sc_if.if_ierrors++;
613 return;
614 }
615 #if NBPFILTER > 0
616 /*
617 * Check if there's a bpf filter listening on this interface.
618 * If so, hand off the raw packet to bpf, which must deal with
619 * trailers in its own way.
620 */
621 if (le->sc_bpf) {
622 bpf_tap(le->sc_bpf, buf, len + sizeof(struct ether_header));
623
624 /*
625 * Note that the interface cannot be in promiscuous mode if
626 * there are no bpf listeners. And if we are in promiscuous
627 * mode, we have to check if this packet is really ours.
628 *
629 * XXX This test does not support multicasts.
630 */
631 if ((le->sc_if.if_flags & IFF_PROMISC)
632 && bcmp(et->ether_dhost, le->sc_addr,
633 sizeof(et->ether_dhost)) != 0
634 && bcmp(et->ether_dhost, etherbroadcastaddr,
635 sizeof(et->ether_dhost)) != 0)
636 return;
637 }
638 #endif
639 /*
640 * Pull packet off interface. Off is nonzero if packet
641 * has trailing header; leget will then force this header
642 * information to be at the front, but we still have to drop
643 * the type and length which are at the front of any trailer data.
644 */
645 m = leget(buf, len, off, &le->sc_if);
646 if (m == 0)
647 return;
648 #ifdef RMP
649 /*
650 * (XXX)
651 * This needs to be integrated with the ISO stuff in ether_input()
652 */
653 if (et->ether_type == ETHERTYPE_IEEE) {
654 /*
655 * Snag the Logical Link Control header (IEEE 802.2).
656 */
657 struct amiga_llc *llc = &(mtod(m, struct rmp_packet *)->amiga_llc);
658
659 /*
660 * If the DSAP (and HP's extended DXSAP) indicate this
661 * is an RMP packet, hand it to the raw input routine.
662 */
663 if (llc->dsap == IEEE_DSAP_HP && llc->dxsap == HPEXT_DXSAP) {
664 static struct sockproto rmp_sp = {AF_RMP,RMPPROTO_BOOT};
665 static struct sockaddr rmp_src = {AF_RMP};
666 static struct sockaddr rmp_dst = {AF_RMP};
667
668 bcopy(et->ether_shost, rmp_src.sa_data,
669 sizeof(et->ether_shost));
670 bcopy(et->ether_dhost, rmp_dst.sa_data,
671 sizeof(et->ether_dhost));
672
673 raw_input(m, &rmp_sp, &rmp_src, &rmp_dst);
674 return;
675 }
676 }
677 #endif
678 ether_input(&le->sc_if, et, m);
679 }
680
681 /*
682 * Routine to copy from mbuf chain to transmit
683 * buffer in board local memory.
684 */
685 leput(lebuf, m)
686 register char *lebuf;
687 register struct mbuf *m;
688 {
689 register struct mbuf *mp;
690 register int len, tlen = 0;
691
692 for (mp = m; mp; mp = mp->m_next) {
693 len = mp->m_len;
694 if (len == 0)
695 continue;
696 tlen += len;
697 bcopy(mtod(mp, char *), lebuf, len);
698 lebuf += len;
699 }
700 m_freem(m);
701 if (tlen < LEMINSIZE) {
702 bzero(lebuf, LEMINSIZE - tlen);
703 tlen = LEMINSIZE;
704 }
705 return(tlen);
706 }
707
708 /*
709 * Routine to copy from board local memory into mbufs.
710 */
711 struct mbuf *
712 leget(lebuf, totlen, off0, ifp)
713 char *lebuf;
714 int totlen, off0;
715 struct ifnet *ifp;
716 {
717 register struct mbuf *m;
718 struct mbuf *top = 0, **mp = ⊤
719 register int off = off0, len;
720 register char *cp;
721 char *epkt;
722
723 lebuf += sizeof (struct ether_header);
724 cp = lebuf;
725 epkt = cp + totlen;
726 if (off) {
727 cp += off + 2 * sizeof(u_short);
728 totlen -= 2 * sizeof(u_short);
729 }
730
731 MGETHDR(m, M_DONTWAIT, MT_DATA);
732 if (m == 0)
733 return (0);
734 m->m_pkthdr.rcvif = ifp;
735 m->m_pkthdr.len = totlen;
736 m->m_len = MHLEN;
737
738 while (totlen > 0) {
739 if (top) {
740 MGET(m, M_DONTWAIT, MT_DATA);
741 if (m == 0) {
742 m_freem(top);
743 return (0);
744 }
745 m->m_len = MLEN;
746 }
747 len = min(totlen, epkt - cp);
748 if (len >= MINCLSIZE) {
749 MCLGET(m, M_DONTWAIT);
750 if (m->m_flags & M_EXT)
751 m->m_len = len = min(len, MCLBYTES);
752 else
753 len = m->m_len;
754 } else {
755 /*
756 * Place initial small packet/header at end of mbuf.
757 */
758 if (len < m->m_len) {
759 if (top == 0 && len + max_linkhdr <= m->m_len)
760 m->m_data += max_linkhdr;
761 m->m_len = len;
762 } else
763 len = m->m_len;
764 }
765 bcopy(cp, mtod(m, caddr_t), (unsigned)len);
766 cp += len;
767 *mp = m;
768 mp = &m->m_next;
769 totlen -= len;
770 if (cp == epkt)
771 cp = lebuf;
772 }
773 return (top);
774 }
775
776 /*
777 * Process an ioctl request.
778 */
779 leioctl(ifp, cmd, data)
780 register struct ifnet *ifp;
781 int cmd;
782 caddr_t data;
783 {
784 register struct ifaddr *ifa = (struct ifaddr *)data;
785 struct le_softc *le = &le_softc[ifp->if_unit];
786 struct lereg1 *ler1 = le->sc_r1;
787 int s = splimp(), error = 0;
788
789 switch (cmd) {
790
791 case SIOCSIFADDR:
792 ifp->if_flags |= IFF_UP;
793 switch (ifa->ifa_addr->sa_family) {
794 #ifdef INET
795 case AF_INET:
796 leinit(ifp->if_unit); /* before arpwhohas */
797 ((struct arpcom *)ifp)->ac_ipaddr =
798 IA_SIN(ifa)->sin_addr;
799 arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
800 break;
801 #endif
802 #ifdef NS
803 case AF_NS:
804 {
805 register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
806
807 if (ns_nullhost(*ina))
808 ina->x_host = *(union ns_host *)(le->sc_addr);
809 else {
810 /*
811 * The manual says we can't change the address
812 * while the receiver is armed,
813 * so reset everything
814 */
815 ifp->if_flags &= ~IFF_RUNNING;
816 bcopy((caddr_t)ina->x_host.c_host,
817 (caddr_t)le->sc_addr, sizeof(le->sc_addr));
818 }
819 leinit(ifp->if_unit); /* does le_setaddr() */
820 break;
821 }
822 #endif
823 default:
824 leinit(ifp->if_unit);
825 break;
826 }
827 break;
828
829 case SIOCSIFFLAGS:
830 if ((ifp->if_flags & IFF_UP) == 0 &&
831 ifp->if_flags & IFF_RUNNING) {
832 ler1->ler1_rdp = LE_STOP;
833 ifp->if_flags &= ~IFF_RUNNING;
834 } else if (ifp->if_flags & IFF_UP &&
835 (ifp->if_flags & IFF_RUNNING) == 0)
836 leinit(ifp->if_unit);
837 /*
838 * If the state of the promiscuous bit changes, the interface
839 * must be reset to effect the change.
840 */
841 if (((ifp->if_flags ^ le->sc_iflags) & IFF_PROMISC) &&
842 (ifp->if_flags & IFF_RUNNING)) {
843 le->sc_iflags = ifp->if_flags;
844 lereset(ifp->if_unit);
845 lestart(ifp);
846 }
847 break;
848
849 default:
850 error = EINVAL;
851 }
852 splx(s);
853 return (error);
854 }
855
856 leerror(unit, stat)
857 int unit;
858 int stat;
859 {
860 if (!ledebug)
861 return;
862
863 /*
864 * Not all transceivers implement heartbeat
865 * so we only log CERR once.
866 */
867 if ((stat & LE_CERR) && le_softc[unit].sc_cerr)
868 return;
869 log(LOG_WARNING,
870 "le%d: error: stat=%b\n", unit,
871 stat,
872 "\20\20ERR\17BABL\16CERR\15MISS\14MERR\13RINT\12TINT\11IDON\10INTR\07INEA\06RXON\05TXON\04TDMD\03STOP\02STRT\01INIT");
873 }
874
875 lererror(unit, msg)
876 int unit;
877 char *msg;
878 {
879 register struct le_softc *le = &le_softc[unit];
880 register struct lermd *rmd;
881 int len;
882
883 if (!ledebug)
884 return;
885
886 rmd = &le->sc_r2->ler2_rmd[le->sc_rmd];
887 len = rmd->rmd3;
888 log(LOG_WARNING,
889 "le%d: ierror(%s): from %s: buf=%d, len=%d, rmd1=%b\n",
890 unit, msg,
891 len > 11 ? ether_sprintf(&le->sc_r2->ler2_rbuf[le->sc_rmd][6]) : "unknown",
892 le->sc_rmd, len,
893 rmd->rmd1,
894 "\20\20OWN\17ERR\16FRAM\15OFLO\14CRC\13RBUF\12STP\11ENP");
895 }
896
897 lexerror(unit)
898 int unit;
899 {
900 register struct le_softc *le = &le_softc[unit];
901 register struct letmd *tmd;
902 int len;
903
904 if (!ledebug)
905 return;
906
907 tmd = le->sc_r2->ler2_tmd;
908 len = -tmd->tmd2;
909 log(LOG_WARNING,
910 "le%d: oerror: to %s: buf=%d, len=%d, tmd1=%b, tmd3=%b\n",
911 unit,
912 len > 5 ? ether_sprintf(&le->sc_r2->ler2_tbuf[0][0]) : "unknown",
913 0, len,
914 tmd->tmd1,
915 "\20\20OWN\17ERR\16RES\15MORE\14ONE\13DEF\12STP\11ENP",
916 tmd->tmd3,
917 "\20\20BUFF\17UFLO\16RES\15LCOL\14LCAR\13RTRY");
918 }
919 #endif
920