if_le.c revision 1.2 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.2 1993/10/30 23:41:14 mw 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_init = leinit;
257 ifp->if_ioctl = leioctl;
258 ifp->if_output = ether_output;
259 ifp->if_start = lestart;
260 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
261 #if NBPFILTER > 0
262 bpfattach(&le->sc_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
263 #endif
264 if_attach(ifp);
265 return (1);
266 }
267
268 ledrinit(ler2)
269 register struct lereg2 *ler2;
270 {
271 register struct lereg2 *lemem = (struct lereg2 *) 0x8000;
272 register int i;
273
274 for (i = 0; i < LERBUF; i++) {
275 ler2->ler2_rmd[i].rmd0 = (int)lemem->ler2_rbuf[i];
276 ler2->ler2_rmd[i].rmd1 = LE_OWN;
277 ler2->ler2_rmd[i].rmd2 = -LEMTU;
278 ler2->ler2_rmd[i].rmd3 = 0;
279 }
280 for (i = 0; i < LETBUF; i++) {
281 ler2->ler2_tmd[i].tmd0 = (int)lemem->ler2_tbuf[i];
282 ler2->ler2_tmd[i].tmd1 = 0;
283 ler2->ler2_tmd[i].tmd2 = 0;
284 ler2->ler2_tmd[i].tmd3 = 0;
285 }
286 }
287
288 lereset(unit)
289 register int unit;
290 {
291 register struct le_softc *le = &le_softc[unit];
292 register struct lereg1 *ler1 = le->sc_r1;
293 register struct lereg2 *lemem = (struct lereg2 *) 0x8000;
294 register int timo = 100000;
295 register int stat;
296
297 #ifdef lint
298 stat = unit;
299 #endif
300 #if NBPFILTER > 0
301 if (le->sc_if.if_flags & IFF_PROMISC)
302 /* set the promiscuous bit */
303 le->sc_r2->ler2_mode = LE_MODE|0x8000;
304 else
305 le->sc_r2->ler2_mode = LE_MODE;
306 #endif
307 ler1->ler1_rap = LE_CSR0;
308 ler1->ler1_rdp = LE_STOP;
309 ledrinit(le->sc_r2);
310 le->sc_rmd = 0;
311 ler1->ler1_rap = LE_CSR1;
312 ler1->ler1_rdp = (int)&lemem->ler2_mode;
313 ler1->ler1_rap = LE_CSR2;
314 ler1->ler1_rdp = 0;
315 ler1->ler1_rap = LE_CSR0;
316 ler1->ler1_rdp = LE_INIT;
317 do {
318 if (--timo == 0) {
319 printf("le%d: init timeout, stat = 0x%x\n",
320 unit, stat);
321 break;
322 }
323 stat = ler1->ler1_rdp;
324 } while ((stat & LE_IDON) == 0);
325 ler1->ler1_rdp = LE_STOP;
326 ler1->ler1_rap = LE_CSR3;
327 ler1->ler1_rdp = LE_BSWP;
328 ler1->ler1_rap = LE_CSR0;
329 ler1->ler1_rdp = LE_STRT | LE_INEA;
330 le->sc_if.if_flags &= ~IFF_OACTIVE;
331 }
332
333 /*
334 * Initialization of interface
335 */
336 leinit(unit)
337 int unit;
338 {
339 struct le_softc *le = &le_softc[unit];
340 register struct ifnet *ifp = &le->sc_if;
341 int s;
342
343 /* not yet, if address still unknown */
344 if (ifp->if_addrlist == (struct ifaddr *)0)
345 return;
346 if ((ifp->if_flags & IFF_RUNNING) == 0) {
347 s = splimp();
348 ifp->if_flags |= IFF_RUNNING;
349 lereset(unit);
350 (void) lestart(ifp);
351 splx(s);
352 }
353 }
354
355 /*
356 * Start output on interface. Get another datagram to send
357 * off of the interface queue, and copy it to the interface
358 * before starting the output.
359 */
360 lestart(ifp)
361 struct ifnet *ifp;
362 {
363 register struct le_softc *le = &le_softc[ifp->if_unit];
364 register struct letmd *tmd;
365 register struct mbuf *m;
366 int len;
367
368 if ((le->sc_if.if_flags & IFF_RUNNING) == 0)
369 return (0);
370 IF_DEQUEUE(&le->sc_if.if_snd, m);
371 if (m == 0)
372 return (0);
373 len = leput(le->sc_r2->ler2_tbuf[0], m);
374 #if NBPFILTER > 0
375 /*
376 * If bpf is listening on this interface, let it
377 * see the packet before we commit it to the wire.
378 */
379 if (le->sc_bpf)
380 bpf_tap(le->sc_bpf, le->sc_r2->ler2_tbuf[0], len);
381 #endif
382 tmd = le->sc_r2->ler2_tmd;
383 tmd->tmd3 = 0;
384 tmd->tmd2 = -len;
385 tmd->tmd1 = LE_OWN | LE_STP | LE_ENP;
386 le->sc_if.if_flags |= IFF_OACTIVE;
387 return (0);
388 }
389
390 leintr(unit)
391 register int unit;
392 {
393 register struct le_softc *le = &le_softc[unit];
394 register struct lereg1 *ler1;
395 register int stat;
396
397 /* if not even initialized, don't do anything further.. */
398 if (! le->sc_base)
399 return 0;
400
401 ler1 = le->sc_r1;
402 stat = ler1->ler1_rdp;
403
404 if (! (stat & LE_INTR))
405 return 0;
406
407 if (stat & LE_SERR) {
408 leerror(unit, stat);
409 if (stat & LE_MERR) {
410 le->sc_merr++;
411 lereset(unit);
412 return(1);
413 }
414 if (stat & LE_BABL)
415 le->sc_babl++;
416 if (stat & LE_CERR)
417 le->sc_cerr++;
418 if (stat & LE_MISS)
419 le->sc_miss++;
420 ler1->ler1_rdp = LE_BABL|LE_CERR|LE_MISS|LE_INEA;
421 }
422 if ((stat & LE_RXON) == 0) {
423 le->sc_rxoff++;
424 lereset(unit);
425 return(1);
426 }
427 if ((stat & LE_TXON) == 0) {
428 le->sc_txoff++;
429 lereset(unit);
430 return(1);
431 }
432 if (stat & LE_RINT) {
433 /* interrupt is cleared in lerint */
434 lerint(unit);
435 }
436 if (stat & LE_TINT) {
437 ler1->ler1_rdp = LE_TINT|LE_INEA;
438 lexint(unit);
439 }
440 return(1);
441 }
442
443 /*
444 * Ethernet interface transmitter interrupt.
445 * Start another output if more data to send.
446 */
447 lexint(unit)
448 register int unit;
449 {
450 register struct le_softc *le = &le_softc[unit];
451 register struct letmd *tmd = le->sc_r2->ler2_tmd;
452
453 if ((le->sc_if.if_flags & IFF_OACTIVE) == 0) {
454 le->sc_xint++;
455 return;
456 }
457 if (tmd->tmd1 & LE_OWN) {
458 le->sc_xown++;
459 return;
460 }
461 if (tmd->tmd1 & LE_ERR) {
462 err:
463 lexerror(unit);
464 le->sc_if.if_oerrors++;
465 if (tmd->tmd3 & (LE_TBUFF|LE_UFLO)) {
466 le->sc_uflo++;
467 lereset(unit);
468 }
469 else if (tmd->tmd3 & LE_LCOL)
470 le->sc_if.if_collisions++;
471 else if (tmd->tmd3 & LE_RTRY)
472 le->sc_if.if_collisions += 16;
473 }
474 else if (tmd->tmd3 & LE_TBUFF)
475 /* XXX documentation says BUFF not included in ERR */
476 goto err;
477 else if (tmd->tmd1 & LE_ONE)
478 le->sc_if.if_collisions++;
479 else if (tmd->tmd1 & LE_MORE)
480 /* what is the real number? */
481 le->sc_if.if_collisions += 2;
482 else
483 le->sc_if.if_opackets++;
484 le->sc_if.if_flags &= ~IFF_OACTIVE;
485 (void) lestart(&le->sc_if);
486 }
487
488 #define LENEXTRMP \
489 if (++bix == LERBUF) bix = 0, rmd = le->sc_r2->ler2_rmd; else ++rmd
490
491 /*
492 * Ethernet interface receiver interrupt.
493 * If input error just drop packet.
494 * Decapsulate packet based on type and pass to type specific
495 * higher-level input routine.
496 */
497 lerint(unit)
498 int unit;
499 {
500 register struct le_softc *le = &le_softc[unit];
501 register int bix = le->sc_rmd;
502 register struct lermd *rmd = &le->sc_r2->ler2_rmd[bix];
503
504 /*
505 * Out of sync with hardware, should never happen?
506 */
507 if (rmd->rmd1 & LE_OWN) {
508 le->sc_r1->ler1_rdp = LE_RINT|LE_INEA;
509 return;
510 }
511
512 /*
513 * Process all buffers with valid data
514 */
515 while ((rmd->rmd1 & LE_OWN) == 0) {
516 int len = rmd->rmd3;
517
518 /* Clear interrupt to avoid race condition */
519 le->sc_r1->ler1_rdp = LE_RINT|LE_INEA;
520
521 if (rmd->rmd1 & LE_ERR) {
522 le->sc_rmd = bix;
523 lererror(unit, "bad packet");
524 le->sc_if.if_ierrors++;
525 } else if ((rmd->rmd1 & (LE_STP|LE_ENP)) != (LE_STP|LE_ENP)) {
526 /*
527 * Find the end of the packet so we can see how long
528 * it was. We still throw it away.
529 */
530 do {
531 le->sc_r1->ler1_rdp = LE_RINT|LE_INEA;
532 rmd->rmd3 = 0;
533 rmd->rmd1 = LE_OWN;
534 LENEXTRMP;
535 } while (!(rmd->rmd1 & (LE_OWN|LE_ERR|LE_STP|LE_ENP)));
536 le->sc_rmd = bix;
537 lererror(unit, "chained buffer");
538 le->sc_rxlen++;
539 /*
540 * If search terminated without successful completion
541 * we reset the hardware (conservative).
542 */
543 if ((rmd->rmd1 & (LE_OWN|LE_ERR|LE_STP|LE_ENP)) !=
544 LE_ENP) {
545 lereset(unit);
546 return;
547 }
548 } else
549 leread(unit, le->sc_r2->ler2_rbuf[bix], len);
550 rmd->rmd3 = 0;
551 rmd->rmd1 = LE_OWN;
552 LENEXTRMP;
553 }
554 le->sc_rmd = bix;
555 }
556
557 leread(unit, buf, len)
558 int unit;
559 char *buf;
560 int len;
561 {
562 register struct le_softc *le = &le_softc[unit];
563 register struct ether_header *et;
564 struct mbuf *m;
565 int off, resid;
566
567 le->sc_if.if_ipackets++;
568 et = (struct ether_header *)buf;
569 et->ether_type = ntohs((u_short)et->ether_type);
570 /* adjust input length to account for header and CRC */
571 len = len - sizeof(struct ether_header) - 4;
572
573 #ifdef RMP
574 /* (XXX)
575 *
576 * If Ethernet Type field is < MaxPacketSize, we probably have
577 * a IEEE802 packet here. Make sure that the size is at least
578 * that of the HP LLC. Also do sanity checks on length of LLC
579 * (old Ethernet Type field) and packet length.
580 *
581 * Provided the above checks succeed, change `len' to reflect
582 * the length of the LLC (i.e. et->ether_type) and change the
583 * type field to ETHERTYPE_IEEE so we can switch() on it later.
584 * Yes, this is a hack and will eventually be done "right".
585 */
586 if (et->ether_type <= IEEE802LEN_MAX && len >= sizeof(struct amiga_llc) &&
587 len >= et->ether_type && len >= IEEE802LEN_MIN) {
588 len = et->ether_type;
589 et->ether_type = ETHERTYPE_IEEE; /* hack! */
590 }
591 #endif
592
593 #define ledataaddr(et, off, type) ((type)(((caddr_t)((et)+1)+(off))))
594 if (et->ether_type >= ETHERTYPE_TRAIL &&
595 et->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
596 off = (et->ether_type - ETHERTYPE_TRAIL) * 512;
597 if (off >= ETHERMTU)
598 return; /* sanity */
599 et->ether_type = ntohs(*ledataaddr(et, off, u_short *));
600 resid = ntohs(*(ledataaddr(et, off+2, u_short *)));
601 if (off + resid > len)
602 return; /* sanity */
603 len = off + resid;
604 } else
605 off = 0;
606
607 if (len <= 0) {
608 if (ledebug)
609 log(LOG_WARNING,
610 "le%d: ierror(runt packet): from %s: len=%d\n",
611 unit, ether_sprintf(et->ether_shost), len);
612 le->sc_runt++;
613 le->sc_if.if_ierrors++;
614 return;
615 }
616 #if NBPFILTER > 0
617 /*
618 * Check if there's a bpf filter listening on this interface.
619 * If so, hand off the raw packet to bpf, which must deal with
620 * trailers in its own way.
621 */
622 if (le->sc_bpf) {
623 bpf_tap(le->sc_bpf, buf, len + sizeof(struct ether_header));
624
625 /*
626 * Note that the interface cannot be in promiscuous mode if
627 * there are no bpf listeners. And if we are in promiscuous
628 * mode, we have to check if this packet is really ours.
629 *
630 * XXX This test does not support multicasts.
631 */
632 if ((le->sc_if.if_flags & IFF_PROMISC)
633 && bcmp(et->ether_dhost, le->sc_addr,
634 sizeof(et->ether_dhost)) != 0
635 && bcmp(et->ether_dhost, etherbroadcastaddr,
636 sizeof(et->ether_dhost)) != 0)
637 return;
638 }
639 #endif
640 /*
641 * Pull packet off interface. Off is nonzero if packet
642 * has trailing header; leget will then force this header
643 * information to be at the front, but we still have to drop
644 * the type and length which are at the front of any trailer data.
645 */
646 m = leget(buf, len, off, &le->sc_if);
647 if (m == 0)
648 return;
649 #ifdef RMP
650 /*
651 * (XXX)
652 * This needs to be integrated with the ISO stuff in ether_input()
653 */
654 if (et->ether_type == ETHERTYPE_IEEE) {
655 /*
656 * Snag the Logical Link Control header (IEEE 802.2).
657 */
658 struct amiga_llc *llc = &(mtod(m, struct rmp_packet *)->amiga_llc);
659
660 /*
661 * If the DSAP (and HP's extended DXSAP) indicate this
662 * is an RMP packet, hand it to the raw input routine.
663 */
664 if (llc->dsap == IEEE_DSAP_HP && llc->dxsap == HPEXT_DXSAP) {
665 static struct sockproto rmp_sp = {AF_RMP,RMPPROTO_BOOT};
666 static struct sockaddr rmp_src = {AF_RMP};
667 static struct sockaddr rmp_dst = {AF_RMP};
668
669 bcopy(et->ether_shost, rmp_src.sa_data,
670 sizeof(et->ether_shost));
671 bcopy(et->ether_dhost, rmp_dst.sa_data,
672 sizeof(et->ether_dhost));
673
674 raw_input(m, &rmp_sp, &rmp_src, &rmp_dst);
675 return;
676 }
677 }
678 #endif
679 ether_input(&le->sc_if, et, m);
680 }
681
682 /*
683 * Routine to copy from mbuf chain to transmit
684 * buffer in board local memory.
685 */
686 leput(lebuf, m)
687 register char *lebuf;
688 register struct mbuf *m;
689 {
690 register struct mbuf *mp;
691 register int len, tlen = 0;
692
693 for (mp = m; mp; mp = mp->m_next) {
694 len = mp->m_len;
695 if (len == 0)
696 continue;
697 tlen += len;
698 bcopy(mtod(mp, char *), lebuf, len);
699 lebuf += len;
700 }
701 m_freem(m);
702 if (tlen < LEMINSIZE) {
703 bzero(lebuf, LEMINSIZE - tlen);
704 tlen = LEMINSIZE;
705 }
706 return(tlen);
707 }
708
709 /*
710 * Routine to copy from board local memory into mbufs.
711 */
712 struct mbuf *
713 leget(lebuf, totlen, off0, ifp)
714 char *lebuf;
715 int totlen, off0;
716 struct ifnet *ifp;
717 {
718 register struct mbuf *m;
719 struct mbuf *top = 0, **mp = ⊤
720 register int off = off0, len;
721 register char *cp;
722 char *epkt;
723
724 lebuf += sizeof (struct ether_header);
725 cp = lebuf;
726 epkt = cp + totlen;
727 if (off) {
728 cp += off + 2 * sizeof(u_short);
729 totlen -= 2 * sizeof(u_short);
730 }
731
732 MGETHDR(m, M_DONTWAIT, MT_DATA);
733 if (m == 0)
734 return (0);
735 m->m_pkthdr.rcvif = ifp;
736 m->m_pkthdr.len = totlen;
737 m->m_len = MHLEN;
738
739 while (totlen > 0) {
740 if (top) {
741 MGET(m, M_DONTWAIT, MT_DATA);
742 if (m == 0) {
743 m_freem(top);
744 return (0);
745 }
746 m->m_len = MLEN;
747 }
748 len = min(totlen, epkt - cp);
749 if (len >= MINCLSIZE) {
750 MCLGET(m, M_DONTWAIT);
751 if (m->m_flags & M_EXT)
752 m->m_len = len = min(len, MCLBYTES);
753 else
754 len = m->m_len;
755 } else {
756 /*
757 * Place initial small packet/header at end of mbuf.
758 */
759 if (len < m->m_len) {
760 if (top == 0 && len + max_linkhdr <= m->m_len)
761 m->m_data += max_linkhdr;
762 m->m_len = len;
763 } else
764 len = m->m_len;
765 }
766 bcopy(cp, mtod(m, caddr_t), (unsigned)len);
767 cp += len;
768 *mp = m;
769 mp = &m->m_next;
770 totlen -= len;
771 if (cp == epkt)
772 cp = lebuf;
773 }
774 return (top);
775 }
776
777 /*
778 * Process an ioctl request.
779 */
780 leioctl(ifp, cmd, data)
781 register struct ifnet *ifp;
782 int cmd;
783 caddr_t data;
784 {
785 register struct ifaddr *ifa = (struct ifaddr *)data;
786 struct le_softc *le = &le_softc[ifp->if_unit];
787 struct lereg1 *ler1 = le->sc_r1;
788 int s = splimp(), error = 0;
789
790 switch (cmd) {
791
792 case SIOCSIFADDR:
793 ifp->if_flags |= IFF_UP;
794 switch (ifa->ifa_addr->sa_family) {
795 #ifdef INET
796 case AF_INET:
797 leinit(ifp->if_unit); /* before arpwhohas */
798 ((struct arpcom *)ifp)->ac_ipaddr =
799 IA_SIN(ifa)->sin_addr;
800 arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
801 break;
802 #endif
803 #ifdef NS
804 case AF_NS:
805 {
806 register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
807
808 if (ns_nullhost(*ina))
809 ina->x_host = *(union ns_host *)(le->sc_addr);
810 else {
811 /*
812 * The manual says we can't change the address
813 * while the receiver is armed,
814 * so reset everything
815 */
816 ifp->if_flags &= ~IFF_RUNNING;
817 bcopy((caddr_t)ina->x_host.c_host,
818 (caddr_t)le->sc_addr, sizeof(le->sc_addr));
819 }
820 leinit(ifp->if_unit); /* does le_setaddr() */
821 break;
822 }
823 #endif
824 default:
825 leinit(ifp->if_unit);
826 break;
827 }
828 break;
829
830 case SIOCSIFFLAGS:
831 if ((ifp->if_flags & IFF_UP) == 0 &&
832 ifp->if_flags & IFF_RUNNING) {
833 ler1->ler1_rdp = LE_STOP;
834 ifp->if_flags &= ~IFF_RUNNING;
835 } else if (ifp->if_flags & IFF_UP &&
836 (ifp->if_flags & IFF_RUNNING) == 0)
837 leinit(ifp->if_unit);
838 /*
839 * If the state of the promiscuous bit changes, the interface
840 * must be reset to effect the change.
841 */
842 if (((ifp->if_flags ^ le->sc_iflags) & IFF_PROMISC) &&
843 (ifp->if_flags & IFF_RUNNING)) {
844 le->sc_iflags = ifp->if_flags;
845 lereset(ifp->if_unit);
846 lestart(ifp);
847 }
848 break;
849
850 default:
851 error = EINVAL;
852 }
853 splx(s);
854 return (error);
855 }
856
857 leerror(unit, stat)
858 int unit;
859 int stat;
860 {
861 if (!ledebug)
862 return;
863
864 /*
865 * Not all transceivers implement heartbeat
866 * so we only log CERR once.
867 */
868 if ((stat & LE_CERR) && le_softc[unit].sc_cerr)
869 return;
870 log(LOG_WARNING,
871 "le%d: error: stat=%b\n", unit,
872 stat,
873 "\20\20ERR\17BABL\16CERR\15MISS\14MERR\13RINT\12TINT\11IDON\10INTR\07INEA\06RXON\05TXON\04TDMD\03STOP\02STRT\01INIT");
874 }
875
876 lererror(unit, msg)
877 int unit;
878 char *msg;
879 {
880 register struct le_softc *le = &le_softc[unit];
881 register struct lermd *rmd;
882 int len;
883
884 if (!ledebug)
885 return;
886
887 rmd = &le->sc_r2->ler2_rmd[le->sc_rmd];
888 len = rmd->rmd3;
889 log(LOG_WARNING,
890 "le%d: ierror(%s): from %s: buf=%d, len=%d, rmd1=%b\n",
891 unit, msg,
892 len > 11 ? ether_sprintf(&le->sc_r2->ler2_rbuf[le->sc_rmd][6]) : "unknown",
893 le->sc_rmd, len,
894 rmd->rmd1,
895 "\20\20OWN\17ERR\16FRAM\15OFLO\14CRC\13RBUF\12STP\11ENP");
896 }
897
898 lexerror(unit)
899 int unit;
900 {
901 register struct le_softc *le = &le_softc[unit];
902 register struct letmd *tmd;
903 int len;
904
905 if (!ledebug)
906 return;
907
908 tmd = le->sc_r2->ler2_tmd;
909 len = -tmd->tmd2;
910 log(LOG_WARNING,
911 "le%d: oerror: to %s: buf=%d, len=%d, tmd1=%b, tmd3=%b\n",
912 unit,
913 len > 5 ? ether_sprintf(&le->sc_r2->ler2_tbuf[0][0]) : "unknown",
914 0, len,
915 tmd->tmd1,
916 "\20\20OWN\17ERR\16RES\15MORE\14ONE\13DEF\12STP\11ENP",
917 tmd->tmd3,
918 "\20\20BUFF\17UFLO\16RES\15LCOL\14LCAR\13RTRY");
919 }
920 #endif
921