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