ARP ARP
[unix-history] / usr / src / sys / vax / if / if_il.c
CommitLineData
8ae4cebd 1/* if_il.c 4.18 83/03/15 */
f0d51478
BF
2
3#include "il.h"
f0d51478
BF
4
5/*
6 * Interlan Ethernet Communications Controller interface
7 */
961945a8
SL
8#include "../machine/pte.h"
9
f0d51478
BF
10#include "../h/param.h"
11#include "../h/systm.h"
12#include "../h/mbuf.h"
f0d51478
BF
13#include "../h/buf.h"
14#include "../h/protosw.h"
15#include "../h/socket.h"
f0d51478 16#include "../h/vmmac.h"
eaa60542
BJ
17#include <errno.h>
18
19#include "../net/if.h"
20#include "../net/netisr.h"
21#include "../net/route.h"
d2cc167c
BJ
22#include "../netinet/in.h"
23#include "../netinet/in_systm.h"
d2cc167c
BJ
24#include "../netinet/ip.h"
25#include "../netinet/ip_var.h"
8ae4cebd 26#include "../netinet/if_ether.h"
d2cc167c 27#include "../netpup/pup.h"
eaa60542
BJ
28
29#include "../vax/cpu.h"
30#include "../vax/mtpr.h"
eaa60542 31#include "../vaxif/if_il.h"
3fa8d9bb 32#include "../vaxif/if_ilreg.h"
eaa60542
BJ
33#include "../vaxif/if_uba.h"
34#include "../vaxuba/ubareg.h"
35#include "../vaxuba/ubavar.h"
f0d51478 36
f0d51478
BF
37int ilprobe(), ilattach(), ilrint(), ilcint();
38struct uba_device *ilinfo[NIL];
39u_short ilstd[] = { 0 };
40struct uba_driver ildriver =
41 { ilprobe, 0, ilattach, 0, ilstd, "il", ilinfo };
f0d51478 42#define ILUNIT(x) minor(x)
8d38dbc2 43int ilinit(),iloutput(),ilreset(),ilwatch();
f0d51478
BF
44
45/*
46 * Ethernet software status per interface.
47 *
48 * Each interface is referenced by a network interface structure,
49 * is_if, which the routing code uses to locate the interface.
50 * This structure contains the output queue for the interface, its address, ...
51 * We also have, for each interface, a UBA interface structure, which
52 * contains information about the UNIBUS resources held by the interface:
53 * map registers, buffered data paths, etc. Information is cached in this
54 * structure for use by the if_uba.c routines in running the interface
55 * efficiently.
56 */
57struct il_softc {
8ae4cebd
SL
58 struct arpcom is_ac; /* Ethernet common part */
59#define is_if is_ac.ac_if /* network-visible interface */
60#define is_addr is_ac.ac_enaddr /* hardware Ethernet address */
f0d51478 61 struct ifuba is_ifuba; /* UNIBUS resources */
8d38dbc2
SL
62 int is_flags;
63#define ILF_OACTIVE 0x1 /* output is active */
64#define ILF_RCVPENDING 0x2 /* start rcv in ilcint */
65#define ILF_STATPENDING 0x4 /* stat cmd pending */
66 short is_lastcmd; /* can't read csr, so must save it */
67 short is_scaninterval; /* interval of stat collection */
68#define ILWATCHINTERVAL 60 /* once every 60 seconds */
69 struct il_stats is_stats; /* holds on-board statistics */
70 struct il_stats is_sum; /* summation over time */
71 int is_ubaddr; /* mapping registers of is_stats */
f0d51478
BF
72} il_softc[NIL];
73
f0d51478
BF
74ilprobe(reg)
75 caddr_t reg;
76{
77 register int br, cvec; /* r11, r10 value-result */
78 register struct ildevice *addr = (struct ildevice *)reg;
79 register i;
80
f0d51478
BF
81#ifdef lint
82 br = 0; cvec = br; br = cvec;
4fce3bf9 83 i = 0; ilrint(i); ilcint(i); ilwatch(i);
f0d51478
BF
84#endif
85
86 addr->il_csr = ILC_OFFLINE|IL_CIE;
87 DELAY(100000);
8d38dbc2 88 i = addr->il_csr; /* clear CDONE */
f0d51478
BF
89 if (cvec > 0 && cvec != 0x200)
90 cvec -= 4;
91 return (1);
92}
93
f0d51478
BF
94/*
95 * Interface exists: make available by filling in network interface
96 * record. System will initialize the interface when it is ready
97 * to accept packets. A STATUS command is done to get the ethernet
98 * address and other interesting data.
99 */
100ilattach(ui)
101 struct uba_device *ui;
102{
103 register struct il_softc *is = &il_softc[ui->ui_unit];
caf0e371 104 register struct ifnet *ifp = &is->is_if;
f0d51478 105 register struct ildevice *addr = (struct ildevice *)ui->ui_addr;
caf0e371 106 struct sockaddr_in *sin;
f0d51478 107
caf0e371
SL
108 ifp->if_unit = ui->ui_unit;
109 ifp->if_name = "il";
3fa8d9bb 110 ifp->if_mtu = ETHERMTU;
f0d51478
BF
111
112 /*
8d38dbc2
SL
113 * Reset the board and map the statistics
114 * buffer onto the Unibus.
f0d51478 115 */
8d38dbc2
SL
116 addr->il_csr = ILC_RESET;
117 while ((addr->il_csr&IL_CDONE) == 0)
118 ;
119 if (addr->il_csr&IL_STATUS)
120 printf("il%d: reset failed, csr=%b\n", ui->ui_unit,
121 addr->il_csr, IL_BITS);
f0d51478 122
4fce3bf9 123 is->is_ubaddr = uballoc(ui->ui_ubanum, (caddr_t)&is->is_stats,
8d38dbc2
SL
124 sizeof (struct il_stats), 0);
125 addr->il_bar = is->is_ubaddr & 0xffff;
126 addr->il_bcr = sizeof (struct il_stats);
127 addr->il_csr = ((is->is_ubaddr >> 2) & IL_EUA)|ILC_STAT;
128 while ((addr->il_csr&IL_CDONE) == 0)
129 ;
130 if (addr->il_csr&IL_STATUS)
131 printf("il%d: status failed, csr=%b\n", ui->ui_unit,
132 addr->il_csr, IL_BITS);
133 ubarelse(ui->ui_ubanum, &is->is_ubaddr);
8ae4cebd 134#ifdef notdef
f0d51478
BF
135 printf("il%d: addr=%x:%x:%x:%x:%x:%x module=%s firmware=%s\n",
136 ui->ui_unit,
8d38dbc2
SL
137 is->is_stats.ils_addr[0]&0xff, is->is_stats.ils_addr[1]&0xff,
138 is->is_stats.ils_addr[2]&0xff, is->is_stats.ils_addr[3]&0xff,
139 is->is_stats.ils_addr[4]&0xff, is->is_stats.ils_addr[5]&0xff,
140 is->is_stats.ils_module, is->is_stats.ils_firmware);
8ae4cebd
SL
141#endif
142 bcopy(is->is_stats.ils_addr, is->is_addr, sizeof (is->is_addr));
caf0e371 143 sin = (struct sockaddr_in *)&ifp->if_addr;
f0d51478 144 sin->sin_family = AF_INET;
8ae4cebd
SL
145 if (ui->ui_flags) {
146 int i = ((is->is_addr[3]&0xff)<<16) |
147 ((is->is_addr[4]&0xff)<<8) |
148 (is->is_addr[5]&0xff);
149 sin->sin_addr = if_makeaddr(ui->ui_flags, i);
150 } else
151 sin->sin_addr = arpmyaddr();
f0d51478 152
caf0e371
SL
153 ifp->if_init = ilinit;
154 ifp->if_output = iloutput;
51595ca2 155 ifp->if_reset = ilreset;
8d38dbc2
SL
156 ifp->if_watchdog = ilwatch;
157 is->is_scaninterval = ILWATCHINTERVAL;
158 ifp->if_timer = is->is_scaninterval;
f0d51478 159 is->is_ifuba.ifu_flags = UBA_CANTWAIT;
caf0e371
SL
160#ifdef notdef
161 is->is_ifuba.ifu_flags |= UBA_NEEDBDP;
162#endif
163 if_attach(ifp);
f0d51478
BF
164}
165
166/*
167 * Reset of interface after UNIBUS reset.
168 * If interface is on specified uba, reset its state.
169 */
170ilreset(unit, uban)
171 int unit, uban;
172{
173 register struct uba_device *ui;
f0d51478
BF
174
175 if (unit >= NIL || (ui = ilinfo[unit]) == 0 || ui->ui_alive == 0 ||
176 ui->ui_ubanum != uban)
177 return;
178 printf(" il%d", unit);
179 ilinit(unit);
180}
181
182/*
183 * Initialization of interface; clear recorded pending
184 * operations, and reinitialize UNIBUS usage.
185 */
186ilinit(unit)
187 int unit;
188{
189 register struct il_softc *is = &il_softc[unit];
190 register struct uba_device *ui = ilinfo[unit];
191 register struct ildevice *addr;
8d38dbc2 192 int s;
8ae4cebd
SL
193 register struct ifnet *ifp = &is->is_if;
194 register struct sockaddr_in *sin, *sinb;
195
196 sin = (struct sockaddr_in *)&ifp->if_addr;
197 if (sin->sin_addr.s_addr == 0) /* if address still unknown */
198 return;
199 ifp->if_net = in_netof(sin->sin_addr);
200 ifp->if_host[0] = in_lnaof(sin->sin_addr);
201 sinb = (struct sockaddr_in *)&ifp->if_broadaddr;
202 sinb->sin_family = AF_INET;
203 sinb->sin_addr = if_makeaddr(ifp->if_net, INADDR_ANY);
204 ifp->if_flags = IFF_BROADCAST;
f0d51478
BF
205
206 if (if_ubainit(&is->is_ifuba, ui->ui_ubanum,
3fa8d9bb 207 sizeof (struct il_rheader), (int)btoc(ETHERMTU)) == 0) {
f0d51478
BF
208 printf("il%d: can't initialize\n", unit);
209 is->is_if.if_flags &= ~IFF_UP;
210 return;
211 }
4fce3bf9 212 is->is_ubaddr = uballoc(ui->ui_ubanum, (caddr_t)&is->is_stats,
8d38dbc2 213 sizeof (struct il_stats), 0);
f0d51478
BF
214 addr = (struct ildevice *)ui->ui_addr;
215
4fce3bf9
SL
216 /*
217 * Turn off source address insertion (it's faster this way),
218 * and set board online.
219 */
220 s = splimp();
221 addr->il_csr = ILC_CISA;
222 while ((addr->il_csr & IL_CDONE) == 0)
223 ;
224 addr->il_csr = ILC_ONLINE;
225 while ((addr->il_csr & IL_CDONE) == 0)
226 ;
f0d51478
BF
227 /*
228 * Set board online.
229 * Hang receive buffer and start any pending
230 * writes by faking a transmit complete.
231 * Receive bcr is not a muliple of 4 so buffer
232 * chaining can't happen.
233 */
234 s = splimp();
235 addr->il_csr = ILC_ONLINE;
caf0e371
SL
236 while ((addr->il_csr & IL_CDONE) == 0)
237 ;
f0d51478 238 addr->il_bar = is->is_ifuba.ifu_r.ifrw_info & 0xffff;
3fa8d9bb 239 addr->il_bcr = sizeof(struct il_rheader) + ETHERMTU + 6;
8d38dbc2
SL
240 addr->il_csr =
241 ((is->is_ifuba.ifu_r.ifrw_info >> 2) & IL_EUA)|ILC_RCV|IL_RIE;
caf0e371
SL
242 while ((addr->il_csr & IL_CDONE) == 0)
243 ;
8d38dbc2 244 is->is_flags = ILF_OACTIVE;
f0d51478 245 is->is_if.if_flags |= IFF_UP;
8d38dbc2 246 is->is_lastcmd = 0;
f0d51478
BF
247 ilcint(unit);
248 splx(s);
a13c006d 249 if_rtinit(&is->is_if, RTF_UP);
8ae4cebd
SL
250 arpattach(&is->is_ac);
251 arpwhohas(&is->is_ac, &sin->sin_addr);
f0d51478
BF
252}
253
254/*
255 * Start output on interface.
256 * Get another datagram to send off of the interface queue,
257 * and map it to the interface before starting the output.
258 */
259ilstart(dev)
260 dev_t dev;
261{
4fce3bf9 262 int unit = ILUNIT(dev), len;
f0d51478
BF
263 struct uba_device *ui = ilinfo[unit];
264 register struct il_softc *is = &il_softc[unit];
265 register struct ildevice *addr;
f0d51478 266 struct mbuf *m;
caf0e371 267 short csr;
f0d51478 268
f0d51478 269 IF_DEQUEUE(&is->is_if.if_snd, m);
8d38dbc2
SL
270 addr = (struct ildevice *)ui->ui_addr;
271 if (m == 0) {
272 if ((is->is_flags & ILF_STATPENDING) == 0)
273 return;
4fce3bf9 274 addr->il_bar = is->is_ubaddr & 0xffff;
8d38dbc2
SL
275 addr->il_bcr = sizeof (struct il_stats);
276 csr = ((is->is_ubaddr >> 2) & IL_EUA)|ILC_STAT|IL_RIE|IL_CIE;
277 is->is_flags &= ~ILF_STATPENDING;
278 goto startcmd;
279 }
f0d51478 280 len = if_wubaput(&is->is_ifuba, m);
4fce3bf9
SL
281 /*
282 * Ensure minimum packet length.
283 * This makes the safe assumtion that there are no virtual holes
284 * after the data.
285 * For security, it might be wise to zero out the added bytes,
286 * but we're mainly interested in speed at the moment.
287 */
3fa8d9bb
SL
288 if (len - sizeof(struct ether_header) < ETHERMIN)
289 len = ETHERMIN + sizeof(struct ether_header);
f0d51478
BF
290 if (is->is_ifuba.ifu_flags & UBA_NEEDBDP)
291 UBAPURGE(is->is_ifuba.ifu_uba, is->is_ifuba.ifu_w.ifrw_bdp);
f0d51478
BF
292 addr->il_bar = is->is_ifuba.ifu_w.ifrw_info & 0xffff;
293 addr->il_bcr = len;
8d38dbc2
SL
294 csr =
295 ((is->is_ifuba.ifu_w.ifrw_info >> 2) & IL_EUA)|ILC_XMIT|IL_CIE|IL_RIE;
296
297startcmd:
298 is->is_lastcmd = csr & IL_CMD;
caf0e371 299 addr->il_csr = csr;
8d38dbc2 300 is->is_flags |= ILF_OACTIVE;
f0d51478
BF
301}
302
303/*
304 * Command done interrupt.
f0d51478
BF
305 */
306ilcint(unit)
307 int unit;
308{
f0d51478 309 register struct il_softc *is = &il_softc[unit];
caf0e371 310 struct uba_device *ui = ilinfo[unit];
f0d51478 311 register struct ildevice *addr = (struct ildevice *)ui->ui_addr;
5565eee9 312 short csr;
f0d51478 313
8d38dbc2 314 if ((is->is_flags & ILF_OACTIVE) == 0) {
caf0e371 315 printf("il%d: stray xmit interrupt, csr=%b\n", unit,
8d38dbc2 316 addr->il_csr, IL_BITS);
f0d51478
BF
317 return;
318 }
caf0e371 319
5565eee9 320 csr = addr->il_csr;
f0d51478 321 /*
8d38dbc2
SL
322 * Hang receive buffer if it couldn't
323 * be done earlier (in ilrint).
f0d51478 324 */
8d38dbc2 325 if (is->is_flags & ILF_RCVPENDING) {
f0d51478 326 addr->il_bar = is->is_ifuba.ifu_r.ifrw_info & 0xffff;
3fa8d9bb 327 addr->il_bcr = sizeof(struct il_rheader) + ETHERMTU + 6;
8d38dbc2
SL
328 addr->il_csr =
329 ((is->is_ifuba.ifu_r.ifrw_info >> 2) & IL_EUA)|ILC_RCV|IL_RIE;
caf0e371
SL
330 while ((addr->il_csr & IL_CDONE) == 0)
331 ;
8d38dbc2
SL
332 is->is_flags &= ~ILF_RCVPENDING;
333 }
334 is->is_flags &= ~ILF_OACTIVE;
5565eee9 335 csr &= IL_STATUS;
8d38dbc2
SL
336 switch (is->is_lastcmd) {
337
338 case ILC_XMIT:
339 is->is_if.if_opackets++;
5565eee9 340 if (csr > ILERR_RETRIES)
8d38dbc2
SL
341 is->is_if.if_oerrors++;
342 break;
343
344 case ILC_STAT:
5565eee9 345 if (csr == ILERR_SUCCESS)
8d38dbc2
SL
346 iltotal(is);
347 break;
f0d51478
BF
348 }
349 if (is->is_ifuba.ifu_xtofree) {
350 m_freem(is->is_ifuba.ifu_xtofree);
351 is->is_ifuba.ifu_xtofree = 0;
352 }
8d38dbc2 353 ilstart(unit);
f0d51478
BF
354}
355
356/*
357 * Ethernet interface receiver interrupt.
358 * If input error just drop packet.
359 * Otherwise purge input buffered data path and examine
360 * packet to determine type. If can't determine length
361 * from type, then have to drop packet. Othewise decapsulate
362 * packet based on type and pass to type specific higher-level
363 * input routine.
364 */
365ilrint(unit)
366 int unit;
367{
368 register struct il_softc *is = &il_softc[unit];
369 struct ildevice *addr = (struct ildevice *)ilinfo[unit]->ui_addr;
370 register struct il_rheader *il;
371 struct mbuf *m;
372 int len, off, resid;
373 register struct ifqueue *inq;
374
f0d51478
BF
375 is->is_if.if_ipackets++;
376 if (is->is_ifuba.ifu_flags & UBA_NEEDBDP)
377 UBAPURGE(is->is_ifuba.ifu_uba, is->is_ifuba.ifu_r.ifrw_bdp);
378 il = (struct il_rheader *)(is->is_ifuba.ifu_r.ifrw_addr);
379 len = il->ilr_length - sizeof(struct il_rheader);
3fa8d9bb
SL
380 if ((il->ilr_status&(ILFSTAT_A|ILFSTAT_C)) || len < 46 ||
381 len > ETHERMTU) {
f0d51478
BF
382 is->is_if.if_ierrors++;
383#ifdef notdef
384 if (is->is_if.if_ierrors % 100 == 0)
385 printf("il%d: += 100 input errors\n", unit);
386#endif
f0d51478
BF
387 goto setup;
388 }
389
390 /*
391 * Deal with trailer protocol: if type is PUP trailer
392 * get true type from first 16-bit word past data.
393 * Remember that type was trailer by setting off.
394 */
3fa8d9bb 395 il->ilr_type = ntohs((u_short)il->ilr_type);
f0d51478 396#define ildataaddr(il, off, type) ((type)(((caddr_t)((il)+1)+(off))))
3fa8d9bb
SL
397 if (il->ilr_type >= ETHERPUP_TRAIL &&
398 il->ilr_type < ETHERPUP_TRAIL+ETHERPUP_NTRAILER) {
399 off = (il->ilr_type - ETHERPUP_TRAIL) * 512;
400 if (off >= ETHERMTU)
f0d51478 401 goto setup; /* sanity */
3fa8d9bb
SL
402 il->ilr_type = ntohs(*ildataaddr(il, off, u_short *));
403 resid = ntohs(*(ildataaddr(il, off+2, u_short *)));
f0d51478
BF
404 if (off + resid > len)
405 goto setup; /* sanity */
406 len = off + resid;
407 } else
408 off = 0;
409 if (len == 0)
410 goto setup;
411
412 /*
413 * Pull packet off interface. Off is nonzero if packet
414 * has trailing header; ilget will then force this header
415 * information to be at the front, but we still have to drop
416 * the type and length which are at the front of any trailer data.
417 */
418 m = if_rubaget(&is->is_ifuba, len, off);
419 if (m == 0)
420 goto setup;
421 if (off) {
422 m->m_off += 2 * sizeof (u_short);
423 m->m_len -= 2 * sizeof (u_short);
424 }
425 switch (il->ilr_type) {
426
427#ifdef INET
3fa8d9bb 428 case ETHERPUP_IPTYPE:
f0d51478
BF
429 schednetisr(NETISR_IP);
430 inq = &ipintrq;
431 break;
8ae4cebd
SL
432
433 case ETHERPUP_ARPTYPE:
434 arpinput(&is->is_ac, m);
435 return;
f0d51478
BF
436#endif
437 default:
438 m_freem(m);
439 goto setup;
440 }
441
442 if (IF_QFULL(inq)) {
443 IF_DROP(inq);
444 m_freem(m);
caf0e371
SL
445 goto setup;
446 }
447 IF_ENQUEUE(inq, m);
f0d51478
BF
448
449setup:
450 /*
451 * Reset for next packet if possible.
452 * If waiting for transmit command completion, set flag
453 * and wait until command completes.
454 */
8d38dbc2
SL
455 if (is->is_flags & ILF_OACTIVE) {
456 is->is_flags |= ILF_RCVPENDING;
caf0e371
SL
457 return;
458 }
459 addr->il_bar = is->is_ifuba.ifu_r.ifrw_info & 0xffff;
3fa8d9bb 460 addr->il_bcr = sizeof(struct il_rheader) + ETHERMTU + 6;
8d38dbc2
SL
461 addr->il_csr =
462 ((is->is_ifuba.ifu_r.ifrw_info >> 2) & IL_EUA)|ILC_RCV|IL_RIE;
caf0e371
SL
463 while ((addr->il_csr & IL_CDONE) == 0)
464 ;
f0d51478
BF
465}
466
467/*
468 * Ethernet output routine.
469 * Encapsulate a packet of type family for the local net.
470 * Use trailer local net encapsulation if enough data in first
471 * packet leaves a multiple of 512 bytes of data in remainder.
472 */
473iloutput(ifp, m0, dst)
474 struct ifnet *ifp;
475 struct mbuf *m0;
476 struct sockaddr *dst;
477{
8ae4cebd
SL
478 int type, s, error;
479 u_char edst[6];
480 struct in_addr idst;
f0d51478
BF
481 register struct il_softc *is = &il_softc[ifp->if_unit];
482 register struct mbuf *m = m0;
3fa8d9bb 483 register struct ether_header *il;
4fce3bf9 484 register int off;
f0d51478 485
f0d51478
BF
486 switch (dst->sa_family) {
487
488#ifdef INET
489 case AF_INET:
8ae4cebd
SL
490 idst = ((struct sockaddr_in *)dst)->sin_addr;
491 if (!arpresolve(&is->is_ac, m, &idst, edst))
492 return (0); /* if not yet resolved */
f0d51478
BF
493 off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
494 if (off > 0 && (off & 0x1ff) == 0 &&
495 m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
3fa8d9bb 496 type = ETHERPUP_TRAIL + (off>>9);
f0d51478
BF
497 m->m_off -= 2 * sizeof (u_short);
498 m->m_len += 2 * sizeof (u_short);
3fa8d9bb
SL
499 *mtod(m, u_short *) = htons((u_short)ETHERPUP_IPTYPE);
500 *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
f0d51478
BF
501 goto gottrailertype;
502 }
3fa8d9bb 503 type = ETHERPUP_IPTYPE;
f0d51478
BF
504 off = 0;
505 goto gottype;
506#endif
507
8ae4cebd
SL
508 case AF_UNSPEC:
509 il = (struct ether_header *)dst->sa_data;
510 bcopy(il->ether_dhost, edst, sizeof (edst));
511 type = il->ether_type;
512 goto gottype;
513
f0d51478
BF
514 default:
515 printf("il%d: can't handle af%d\n", ifp->if_unit,
516 dst->sa_family);
517 error = EAFNOSUPPORT;
518 goto bad;
519 }
520
521gottrailertype:
522 /*
523 * Packet to be sent as trailer: move first packet
524 * (control information) to end of chain.
525 */
526 while (m->m_next)
527 m = m->m_next;
528 m->m_next = m0;
529 m = m0->m_next;
530 m0->m_next = 0;
531 m0 = m;
532
533gottype:
534 /*
535 * Add local net header. If no space in first mbuf,
536 * allocate another.
537 */
538 if (m->m_off > MMAXOFF ||
3fa8d9bb 539 MMINOFF + sizeof (struct ether_header) > m->m_off) {
cce93e4b 540 m = m_get(M_DONTWAIT, MT_HEADER);
f0d51478
BF
541 if (m == 0) {
542 error = ENOBUFS;
543 goto bad;
544 }
545 m->m_next = m0;
546 m->m_off = MMINOFF;
3fa8d9bb 547 m->m_len = sizeof (struct ether_header);
f0d51478 548 } else {
3fa8d9bb
SL
549 m->m_off -= sizeof (struct ether_header);
550 m->m_len += sizeof (struct ether_header);
f0d51478 551 }
3fa8d9bb 552 il = mtod(m, struct ether_header *);
3fa8d9bb 553 il->ether_type = htons((u_short)type);
8ae4cebd
SL
554 bcopy(edst, il->ether_dhost, sizeof (edst));
555 bcopy((caddr_t)is->is_addr, (caddr_t)il->ether_shost, 6);
f0d51478
BF
556
557 /*
558 * Queue message on interface, and start output if interface
559 * not yet active.
560 */
561 s = splimp();
562 if (IF_QFULL(&ifp->if_snd)) {
563 IF_DROP(&ifp->if_snd);
caf0e371
SL
564 splx(s);
565 m_freem(m);
566 return (ENOBUFS);
f0d51478
BF
567 }
568 IF_ENQUEUE(&ifp->if_snd, m);
8d38dbc2 569 if ((is->is_flags & ILF_OACTIVE) == 0)
f0d51478
BF
570 ilstart(ifp->if_unit);
571 splx(s);
572 return (0);
caf0e371 573
f0d51478
BF
574bad:
575 m_freem(m0);
caf0e371 576 return (error);
f0d51478 577}
8d38dbc2
SL
578
579/*
580 * Watchdog routine, request statistics from board.
581 */
582ilwatch(unit)
583 int unit;
584{
585 register struct il_softc *is = &il_softc[unit];
586 register struct ifnet *ifp = &is->is_if;
587 int s;
588
589 if (is->is_flags & ILF_STATPENDING) {
590 ifp->if_timer = is->is_scaninterval;
591 return;
592 }
593 s = splimp();
594 is->is_flags |= ILF_STATPENDING;
595 if ((is->is_flags & ILF_OACTIVE) == 0)
596 ilstart(ifp->if_unit);
597 splx(s);
598 ifp->if_timer = is->is_scaninterval;
599}
600
601/*
602 * Total up the on-board statistics.
603 */
604iltotal(is)
605 register struct il_softc *is;
606{
607 register u_short *interval, *sum, *end;
608
609 interval = &is->is_stats.ils_frames;
610 sum = &is->is_sum.ils_frames;
611 end = is->is_sum.ils_fill2;
612 while (sum < end)
613 *sum++ += *interval++;
614 is->is_if.if_collisions = is->is_sum.ils_collis;
615}