BSD 4_3_Tahoe release
[unix-history] / usr / src / sys / vaxif / if_il.c
CommitLineData
cd4baa58 1/*
2eb4e665 2 * Copyright (c) 1982, 1986 Regents of the University of California.
cd4baa58
KS
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 *
ca67e7b4 6 * @(#)if_il.c 7.2 (Berkeley) 8/7/86
cd4baa58 7 */
f0d51478
BF
8
9#include "il.h"
9a0b0c74 10#if NIL > 0
f0d51478
BF
11
12/*
13 * Interlan Ethernet Communications Controller interface
14 */
961945a8
SL
15#include "../machine/pte.h"
16
a6e960e7
JB
17#include "param.h"
18#include "systm.h"
19#include "mbuf.h"
20#include "buf.h"
21#include "protosw.h"
22#include "socket.h"
23#include "vmmac.h"
24#include "ioctl.h"
25#include "errno.h"
f883ae2e 26#include "syslog.h"
eaa60542
BJ
27
28#include "../net/if.h"
29#include "../net/netisr.h"
30#include "../net/route.h"
cd4baa58
KS
31
32#ifdef INET
d2cc167c
BJ
33#include "../netinet/in.h"
34#include "../netinet/in_systm.h"
7f0e1e06 35#include "../netinet/in_var.h"
d2cc167c 36#include "../netinet/ip.h"
8ae4cebd 37#include "../netinet/if_ether.h"
cd4baa58
KS
38#endif
39
cd4baa58
KS
40#ifdef NS
41#include "../netns/ns.h"
42#include "../netns/ns_if.h"
43#endif
44
eaa60542
BJ
45#include "../vax/cpu.h"
46#include "../vax/mtpr.h"
a6e960e7
JB
47#include "if_il.h"
48#include "if_ilreg.h"
49#include "if_uba.h"
eaa60542
BJ
50#include "../vaxuba/ubareg.h"
51#include "../vaxuba/ubavar.h"
f0d51478 52
f0d51478
BF
53int ilprobe(), ilattach(), ilrint(), ilcint();
54struct uba_device *ilinfo[NIL];
55u_short ilstd[] = { 0 };
56struct uba_driver ildriver =
57 { ilprobe, 0, ilattach, 0, ilstd, "il", ilinfo };
f0d51478 58#define ILUNIT(x) minor(x)
1cd789fb 59int ilinit(),iloutput(),ilioctl(),ilreset(),ilwatch();
955bf7a0 60int ildebug = 0;
f0d51478
BF
61
62/*
63 * Ethernet software status per interface.
64 *
65 * Each interface is referenced by a network interface structure,
66 * is_if, which the routing code uses to locate the interface.
67 * This structure contains the output queue for the interface, its address, ...
68 * We also have, for each interface, a UBA interface structure, which
69 * contains information about the UNIBUS resources held by the interface:
70 * map registers, buffered data paths, etc. Information is cached in this
71 * structure for use by the if_uba.c routines in running the interface
72 * efficiently.
73 */
74struct il_softc {
8ae4cebd
SL
75 struct arpcom is_ac; /* Ethernet common part */
76#define is_if is_ac.ac_if /* network-visible interface */
77#define is_addr is_ac.ac_enaddr /* hardware Ethernet address */
f0d51478 78 struct ifuba is_ifuba; /* UNIBUS resources */
8d38dbc2
SL
79 int is_flags;
80#define ILF_OACTIVE 0x1 /* output is active */
81#define ILF_RCVPENDING 0x2 /* start rcv in ilcint */
82#define ILF_STATPENDING 0x4 /* stat cmd pending */
0f487295 83#define ILF_RUNNING 0x8 /* board is running */
d4ce9212 84#define ILF_SETADDR 0x10 /* physical address is changed */
8d38dbc2
SL
85 short is_lastcmd; /* can't read csr, so must save it */
86 short is_scaninterval; /* interval of stat collection */
87#define ILWATCHINTERVAL 60 /* once every 60 seconds */
88 struct il_stats is_stats; /* holds on-board statistics */
89 struct il_stats is_sum; /* summation over time */
90 int is_ubaddr; /* mapping registers of is_stats */
f0d51478
BF
91} il_softc[NIL];
92
f0d51478
BF
93ilprobe(reg)
94 caddr_t reg;
95{
96 register int br, cvec; /* r11, r10 value-result */
97 register struct ildevice *addr = (struct ildevice *)reg;
98 register i;
99
f0d51478
BF
100#ifdef lint
101 br = 0; cvec = br; br = cvec;
4fce3bf9 102 i = 0; ilrint(i); ilcint(i); ilwatch(i);
f0d51478
BF
103#endif
104
105 addr->il_csr = ILC_OFFLINE|IL_CIE;
106 DELAY(100000);
8d38dbc2 107 i = addr->il_csr; /* clear CDONE */
f0d51478
BF
108 if (cvec > 0 && cvec != 0x200)
109 cvec -= 4;
110 return (1);
111}
112
f0d51478
BF
113/*
114 * Interface exists: make available by filling in network interface
115 * record. System will initialize the interface when it is ready
116 * to accept packets. A STATUS command is done to get the ethernet
117 * address and other interesting data.
118 */
119ilattach(ui)
120 struct uba_device *ui;
121{
122 register struct il_softc *is = &il_softc[ui->ui_unit];
caf0e371 123 register struct ifnet *ifp = &is->is_if;
f0d51478 124 register struct ildevice *addr = (struct ildevice *)ui->ui_addr;
f0d51478 125
caf0e371
SL
126 ifp->if_unit = ui->ui_unit;
127 ifp->if_name = "il";
3fa8d9bb 128 ifp->if_mtu = ETHERMTU;
7f0e1e06 129 ifp->if_flags = IFF_BROADCAST;
f0d51478
BF
130
131 /*
8d38dbc2
SL
132 * Reset the board and map the statistics
133 * buffer onto the Unibus.
f0d51478 134 */
8d38dbc2 135 addr->il_csr = ILC_RESET;
d4ce9212 136 (void)ilwait(ui, "reset");
f0d51478 137
4fce3bf9 138 is->is_ubaddr = uballoc(ui->ui_ubanum, (caddr_t)&is->is_stats,
1cd789fb 139 sizeof (struct il_stats), 0);
8d38dbc2
SL
140 addr->il_bar = is->is_ubaddr & 0xffff;
141 addr->il_bcr = sizeof (struct il_stats);
142 addr->il_csr = ((is->is_ubaddr >> 2) & IL_EUA)|ILC_STAT;
d4ce9212 143 (void)ilwait(ui, "status");
8d38dbc2 144 ubarelse(ui->ui_ubanum, &is->is_ubaddr);
955bf7a0
MK
145 if (ildebug)
146 printf("il%d: module=%s firmware=%s\n", ui->ui_unit,
147 is->is_stats.ils_module, is->is_stats.ils_firmware);
7f0e1e06
MK
148 bcopy((caddr_t)is->is_stats.ils_addr, (caddr_t)is->is_addr,
149 sizeof (is->is_addr));
d4ce9212
MK
150 printf("il%d: hardware address %s\n", ui->ui_unit,
151 ether_sprintf(is->is_addr));
caf0e371
SL
152 ifp->if_init = ilinit;
153 ifp->if_output = iloutput;
1cd789fb 154 ifp->if_ioctl = ilioctl;
51595ca2 155 ifp->if_reset = ilreset;
f0d51478 156 is->is_ifuba.ifu_flags = UBA_CANTWAIT;
caf0e371 157 if_attach(ifp);
f0d51478
BF
158}
159
d4ce9212
MK
160ilwait(ui, op)
161 struct uba_device *ui;
162 char *op;
163{
164 register struct ildevice *addr = (struct ildevice *)ui->ui_addr;
165
166 while ((addr->il_csr&IL_CDONE) == 0)
167 ;
168 if (addr->il_csr&IL_STATUS) {
169 printf("il%d: %s failed, csr=%b\n", ui->ui_unit, op,
170 addr->il_csr, IL_BITS);
171 return (-1);
172 }
173 return (0);
174}
175
f0d51478
BF
176/*
177 * Reset of interface after UNIBUS reset.
178 * If interface is on specified uba, reset its state.
179 */
180ilreset(unit, uban)
181 int unit, uban;
182{
183 register struct uba_device *ui;
f0d51478
BF
184
185 if (unit >= NIL || (ui = ilinfo[unit]) == 0 || ui->ui_alive == 0 ||
186 ui->ui_ubanum != uban)
187 return;
188 printf(" il%d", unit);
0f487295
MK
189 il_softc[unit].is_if.if_flags &= ~IFF_RUNNING;
190 il_softc[unit].is_flags &= ~ILF_RUNNING;
f0d51478
BF
191 ilinit(unit);
192}
193
194/*
195 * Initialization of interface; clear recorded pending
196 * operations, and reinitialize UNIBUS usage.
197 */
198ilinit(unit)
199 int unit;
200{
201 register struct il_softc *is = &il_softc[unit];
202 register struct uba_device *ui = ilinfo[unit];
203 register struct ildevice *addr;
8ae4cebd 204 register struct ifnet *ifp = &is->is_if;
1cd789fb 205 int s;
8ae4cebd 206
7f0e1e06
MK
207 /* not yet, if address still unknown */
208 if (ifp->if_addrlist == (struct ifaddr *)0)
8ae4cebd 209 return;
0f487295 210 if (is->is_flags & ILF_RUNNING)
f0d51478 211 return;
0f487295
MK
212
213 if ((ifp->if_flags & IFF_RUNNING) == 0) {
214 if (if_ubainit(&is->is_ifuba, ui->ui_ubanum,
215 sizeof (struct il_rheader), (int)btoc(ETHERMTU)) == 0) {
216 printf("il%d: can't initialize\n", unit);
217 is->is_if.if_flags &= ~IFF_UP;
218 return;
219 }
220 is->is_ubaddr = uballoc(ui->ui_ubanum, (caddr_t)&is->is_stats,
221 sizeof (struct il_stats), 0);
f0d51478 222 }
84afd52f
MK
223 ifp->if_watchdog = ilwatch;
224 is->is_scaninterval = ILWATCHINTERVAL;
225 ifp->if_timer = is->is_scaninterval;
f0d51478
BF
226 addr = (struct ildevice *)ui->ui_addr;
227
4fce3bf9
SL
228 /*
229 * Turn off source address insertion (it's faster this way),
e99cc7c6
SL
230 * and set board online. Former doesn't work if board is
231 * already online (happens on ubareset), so we put it offline
232 * first.
4fce3bf9
SL
233 */
234 s = splimp();
0f487295 235 addr->il_csr = ILC_RESET;
d4ce9212 236 if (ilwait(ui, "hardware diag")) {
0f487295
MK
237 is->is_if.if_flags &= ~IFF_UP;
238 splx(s);
239 return;
240 }
e99cc7c6 241 addr->il_csr = ILC_CISA;
4fce3bf9
SL
242 while ((addr->il_csr & IL_CDONE) == 0)
243 ;
35871340
KS
244 /*
245 * If we must reprogram this board's physical ethernet
246 * address (as for secondary XNS interfaces), we do so
247 * before putting it on line, and starting receive requests.
248 * If you try this on an older 1010 board, it will total
249 * wedge the board.
250 */
251 if (is->is_flags & ILF_SETADDR) {
252 bcopy((caddr_t)is->is_addr, (caddr_t)&is->is_stats,
253 sizeof is->is_addr);
254 addr->il_bar = is->is_ubaddr & 0xffff;
255 addr->il_bcr = sizeof is->is_addr;
256 addr->il_csr = ((is->is_ubaddr >> 2) & IL_EUA)|ILC_LDPA;
257 if (ilwait(ui, "setaddr"))
258 return;
259 addr->il_bar = is->is_ubaddr & 0xffff;
260 addr->il_bcr = sizeof (struct il_stats);
261 addr->il_csr = ((is->is_ubaddr >> 2) & IL_EUA)|ILC_STAT;
262 if (ilwait(ui, "verifying setaddr"))
263 return;
264 if (bcmp((caddr_t)is->is_stats.ils_addr, (caddr_t)is->is_addr,
265 sizeof (is->is_addr)) != 0) {
266 printf("il%d: setaddr didn't work\n", ui->ui_unit);
267 return;
268 }
269 }
f0d51478
BF
270 /*
271 * Set board online.
272 * Hang receive buffer and start any pending
273 * writes by faking a transmit complete.
0f487295 274 * Receive bcr is not a multiple of 8 so buffer
f0d51478
BF
275 * chaining can't happen.
276 */
f0d51478 277 addr->il_csr = ILC_ONLINE;
caf0e371
SL
278 while ((addr->il_csr & IL_CDONE) == 0)
279 ;
f0d51478 280 addr->il_bar = is->is_ifuba.ifu_r.ifrw_info & 0xffff;
3fa8d9bb 281 addr->il_bcr = sizeof(struct il_rheader) + ETHERMTU + 6;
8d38dbc2 282 addr->il_csr =
1cd789fb 283 ((is->is_ifuba.ifu_r.ifrw_info >> 2) & IL_EUA)|ILC_RCV|IL_RIE;
caf0e371
SL
284 while ((addr->il_csr & IL_CDONE) == 0)
285 ;
8d38dbc2 286 is->is_flags = ILF_OACTIVE;
7f0e1e06 287 is->is_if.if_flags |= IFF_RUNNING;
0f487295 288 is->is_flags |= ILF_RUNNING;
8d38dbc2 289 is->is_lastcmd = 0;
f0d51478
BF
290 ilcint(unit);
291 splx(s);
f0d51478
BF
292}
293
294/*
295 * Start output on interface.
296 * Get another datagram to send off of the interface queue,
297 * and map it to the interface before starting the output.
298 */
299ilstart(dev)
300 dev_t dev;
301{
4fce3bf9 302 int unit = ILUNIT(dev), len;
f0d51478
BF
303 struct uba_device *ui = ilinfo[unit];
304 register struct il_softc *is = &il_softc[unit];
305 register struct ildevice *addr;
f0d51478 306 struct mbuf *m;
caf0e371 307 short csr;
f0d51478 308
f0d51478 309 IF_DEQUEUE(&is->is_if.if_snd, m);
8d38dbc2
SL
310 addr = (struct ildevice *)ui->ui_addr;
311 if (m == 0) {
312 if ((is->is_flags & ILF_STATPENDING) == 0)
313 return;
4fce3bf9 314 addr->il_bar = is->is_ubaddr & 0xffff;
8d38dbc2
SL
315 addr->il_bcr = sizeof (struct il_stats);
316 csr = ((is->is_ubaddr >> 2) & IL_EUA)|ILC_STAT|IL_RIE|IL_CIE;
317 is->is_flags &= ~ILF_STATPENDING;
318 goto startcmd;
319 }
f0d51478 320 len = if_wubaput(&is->is_ifuba, m);
4fce3bf9
SL
321 /*
322 * Ensure minimum packet length.
323 * This makes the safe assumtion that there are no virtual holes
324 * after the data.
325 * For security, it might be wise to zero out the added bytes,
326 * but we're mainly interested in speed at the moment.
327 */
3fa8d9bb
SL
328 if (len - sizeof(struct ether_header) < ETHERMIN)
329 len = ETHERMIN + sizeof(struct ether_header);
f0d51478
BF
330 if (is->is_ifuba.ifu_flags & UBA_NEEDBDP)
331 UBAPURGE(is->is_ifuba.ifu_uba, is->is_ifuba.ifu_w.ifrw_bdp);
f0d51478
BF
332 addr->il_bar = is->is_ifuba.ifu_w.ifrw_info & 0xffff;
333 addr->il_bcr = len;
8d38dbc2
SL
334 csr =
335 ((is->is_ifuba.ifu_w.ifrw_info >> 2) & IL_EUA)|ILC_XMIT|IL_CIE|IL_RIE;
336
337startcmd:
338 is->is_lastcmd = csr & IL_CMD;
caf0e371 339 addr->il_csr = csr;
8d38dbc2 340 is->is_flags |= ILF_OACTIVE;
f0d51478
BF
341}
342
343/*
344 * Command done interrupt.
f0d51478
BF
345 */
346ilcint(unit)
347 int unit;
348{
f0d51478 349 register struct il_softc *is = &il_softc[unit];
caf0e371 350 struct uba_device *ui = ilinfo[unit];
f0d51478 351 register struct ildevice *addr = (struct ildevice *)ui->ui_addr;
5565eee9 352 short csr;
f0d51478 353
8d38dbc2 354 if ((is->is_flags & ILF_OACTIVE) == 0) {
caf0e371 355 printf("il%d: stray xmit interrupt, csr=%b\n", unit,
8d38dbc2 356 addr->il_csr, IL_BITS);
f0d51478
BF
357 return;
358 }
caf0e371 359
5565eee9 360 csr = addr->il_csr;
f0d51478 361 /*
8d38dbc2
SL
362 * Hang receive buffer if it couldn't
363 * be done earlier (in ilrint).
f0d51478 364 */
8d38dbc2 365 if (is->is_flags & ILF_RCVPENDING) {
0f487295
MK
366 int s;
367
f0d51478 368 addr->il_bar = is->is_ifuba.ifu_r.ifrw_info & 0xffff;
3fa8d9bb 369 addr->il_bcr = sizeof(struct il_rheader) + ETHERMTU + 6;
8d38dbc2
SL
370 addr->il_csr =
371 ((is->is_ifuba.ifu_r.ifrw_info >> 2) & IL_EUA)|ILC_RCV|IL_RIE;
0f487295 372 s = splhigh();
caf0e371
SL
373 while ((addr->il_csr & IL_CDONE) == 0)
374 ;
0f487295 375 splx(s);
8d38dbc2
SL
376 is->is_flags &= ~ILF_RCVPENDING;
377 }
378 is->is_flags &= ~ILF_OACTIVE;
5565eee9 379 csr &= IL_STATUS;
8d38dbc2
SL
380 switch (is->is_lastcmd) {
381
382 case ILC_XMIT:
383 is->is_if.if_opackets++;
5565eee9 384 if (csr > ILERR_RETRIES)
8d38dbc2
SL
385 is->is_if.if_oerrors++;
386 break;
387
388 case ILC_STAT:
5565eee9 389 if (csr == ILERR_SUCCESS)
8d38dbc2
SL
390 iltotal(is);
391 break;
f0d51478
BF
392 }
393 if (is->is_ifuba.ifu_xtofree) {
394 m_freem(is->is_ifuba.ifu_xtofree);
395 is->is_ifuba.ifu_xtofree = 0;
396 }
8d38dbc2 397 ilstart(unit);
f0d51478
BF
398}
399
400/*
401 * Ethernet interface receiver interrupt.
402 * If input error just drop packet.
403 * Otherwise purge input buffered data path and examine
404 * packet to determine type. If can't determine length
405 * from type, then have to drop packet. Othewise decapsulate
406 * packet based on type and pass to type specific higher-level
407 * input routine.
408 */
409ilrint(unit)
410 int unit;
411{
412 register struct il_softc *is = &il_softc[unit];
413 struct ildevice *addr = (struct ildevice *)ilinfo[unit]->ui_addr;
414 register struct il_rheader *il;
415 struct mbuf *m;
56739ded 416 int len, off, resid, s;
f0d51478
BF
417 register struct ifqueue *inq;
418
f0d51478
BF
419 is->is_if.if_ipackets++;
420 if (is->is_ifuba.ifu_flags & UBA_NEEDBDP)
421 UBAPURGE(is->is_ifuba.ifu_uba, is->is_ifuba.ifu_r.ifrw_bdp);
422 il = (struct il_rheader *)(is->is_ifuba.ifu_r.ifrw_addr);
423 len = il->ilr_length - sizeof(struct il_rheader);
3fa8d9bb
SL
424 if ((il->ilr_status&(ILFSTAT_A|ILFSTAT_C)) || len < 46 ||
425 len > ETHERMTU) {
f0d51478
BF
426 is->is_if.if_ierrors++;
427#ifdef notdef
428 if (is->is_if.if_ierrors % 100 == 0)
429 printf("il%d: += 100 input errors\n", unit);
430#endif
f0d51478
BF
431 goto setup;
432 }
433
434 /*
7f0e1e06 435 * Deal with trailer protocol: if type is trailer type
f0d51478
BF
436 * get true type from first 16-bit word past data.
437 * Remember that type was trailer by setting off.
438 */
3fa8d9bb 439 il->ilr_type = ntohs((u_short)il->ilr_type);
f0d51478 440#define ildataaddr(il, off, type) ((type)(((caddr_t)((il)+1)+(off))))
7f0e1e06
MK
441 if (il->ilr_type >= ETHERTYPE_TRAIL &&
442 il->ilr_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
443 off = (il->ilr_type - ETHERTYPE_TRAIL) * 512;
3fa8d9bb 444 if (off >= ETHERMTU)
f0d51478 445 goto setup; /* sanity */
3fa8d9bb
SL
446 il->ilr_type = ntohs(*ildataaddr(il, off, u_short *));
447 resid = ntohs(*(ildataaddr(il, off+2, u_short *)));
f0d51478
BF
448 if (off + resid > len)
449 goto setup; /* sanity */
450 len = off + resid;
451 } else
452 off = 0;
453 if (len == 0)
454 goto setup;
455
456 /*
457 * Pull packet off interface. Off is nonzero if packet
458 * has trailing header; ilget will then force this header
459 * information to be at the front, but we still have to drop
460 * the type and length which are at the front of any trailer data.
461 */
67eb6277 462 m = if_rubaget(&is->is_ifuba, len, off, &is->is_if);
f0d51478
BF
463 if (m == 0)
464 goto setup;
465 if (off) {
67eb6277
MK
466 struct ifnet *ifp;
467
468 ifp = *(mtod(m, struct ifnet **));
f0d51478
BF
469 m->m_off += 2 * sizeof (u_short);
470 m->m_len -= 2 * sizeof (u_short);
67eb6277 471 *(mtod(m, struct ifnet **)) = ifp;
f0d51478
BF
472 }
473 switch (il->ilr_type) {
474
475#ifdef INET
7f0e1e06 476 case ETHERTYPE_IP:
f0d51478
BF
477 schednetisr(NETISR_IP);
478 inq = &ipintrq;
479 break;
8ae4cebd 480
7f0e1e06 481 case ETHERTYPE_ARP:
8ae4cebd 482 arpinput(&is->is_ac, m);
27bcf34c 483 goto setup;
cd4baa58
KS
484#endif
485#ifdef NS
486 case ETHERTYPE_NS:
487 schednetisr(NETISR_NS);
488 inq = &nsintrq;
489 break;
490
f0d51478
BF
491#endif
492 default:
493 m_freem(m);
494 goto setup;
495 }
496
56739ded 497 s = splimp();
f0d51478
BF
498 if (IF_QFULL(inq)) {
499 IF_DROP(inq);
500 m_freem(m);
56739ded
CL
501 } else
502 IF_ENQUEUE(inq, m);
503 splx(s);
f0d51478
BF
504
505setup:
506 /*
507 * Reset for next packet if possible.
508 * If waiting for transmit command completion, set flag
509 * and wait until command completes.
510 */
8d38dbc2
SL
511 if (is->is_flags & ILF_OACTIVE) {
512 is->is_flags |= ILF_RCVPENDING;
caf0e371
SL
513 return;
514 }
515 addr->il_bar = is->is_ifuba.ifu_r.ifrw_info & 0xffff;
3fa8d9bb 516 addr->il_bcr = sizeof(struct il_rheader) + ETHERMTU + 6;
8d38dbc2
SL
517 addr->il_csr =
518 ((is->is_ifuba.ifu_r.ifrw_info >> 2) & IL_EUA)|ILC_RCV|IL_RIE;
0f487295 519 s = splhigh();
caf0e371
SL
520 while ((addr->il_csr & IL_CDONE) == 0)
521 ;
0f487295 522 splx(s);
f0d51478
BF
523}
524
525/*
526 * Ethernet output routine.
527 * Encapsulate a packet of type family for the local net.
528 * Use trailer local net encapsulation if enough data in first
529 * packet leaves a multiple of 512 bytes of data in remainder.
530 */
531iloutput(ifp, m0, dst)
532 struct ifnet *ifp;
533 struct mbuf *m0;
534 struct sockaddr *dst;
535{
8ae4cebd 536 int type, s, error;
7f0e1e06 537 u_char edst[6];
8ae4cebd 538 struct in_addr idst;
f0d51478
BF
539 register struct il_softc *is = &il_softc[ifp->if_unit];
540 register struct mbuf *m = m0;
3fa8d9bb 541 register struct ether_header *il;
4fce3bf9 542 register int off;
d4ce9212 543 int usetrailers;
f0d51478 544
0f487295
MK
545 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
546 error = ENETDOWN;
547 goto bad;
548 }
f0d51478
BF
549 switch (dst->sa_family) {
550
551#ifdef INET
552 case AF_INET:
8ae4cebd 553 idst = ((struct sockaddr_in *)dst)->sin_addr;
d4ce9212 554 if (!arpresolve(&is->is_ac, m, &idst, edst, &usetrailers))
8ae4cebd 555 return (0); /* if not yet resolved */
f0d51478 556 off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
d4ce9212 557 if (usetrailers && off > 0 && (off & 0x1ff) == 0 &&
f0d51478 558 m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
7f0e1e06 559 type = ETHERTYPE_TRAIL + (off>>9);
f0d51478
BF
560 m->m_off -= 2 * sizeof (u_short);
561 m->m_len += 2 * sizeof (u_short);
7f0e1e06 562 *mtod(m, u_short *) = htons((u_short)ETHERTYPE_IP);
3fa8d9bb 563 *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
f0d51478
BF
564 goto gottrailertype;
565 }
7f0e1e06 566 type = ETHERTYPE_IP;
f0d51478
BF
567 off = 0;
568 goto gottype;
569#endif
cd4baa58
KS
570#ifdef NS
571 case AF_NS:
572 type = ETHERTYPE_NS;
573 bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host),
574 (caddr_t)edst, sizeof (edst));
575 off = 0;
576 goto gottype;
577#endif
f0d51478 578
8ae4cebd
SL
579 case AF_UNSPEC:
580 il = (struct ether_header *)dst->sa_data;
7f0e1e06 581 bcopy((caddr_t)il->ether_dhost, (caddr_t)edst, sizeof (edst));
8ae4cebd
SL
582 type = il->ether_type;
583 goto gottype;
584
f0d51478
BF
585 default:
586 printf("il%d: can't handle af%d\n", ifp->if_unit,
587 dst->sa_family);
588 error = EAFNOSUPPORT;
589 goto bad;
590 }
591
592gottrailertype:
593 /*
594 * Packet to be sent as trailer: move first packet
595 * (control information) to end of chain.
596 */
597 while (m->m_next)
598 m = m->m_next;
599 m->m_next = m0;
600 m = m0->m_next;
601 m0->m_next = 0;
602 m0 = m;
603
604gottype:
605 /*
606 * Add local net header. If no space in first mbuf,
607 * allocate another.
608 */
609 if (m->m_off > MMAXOFF ||
3fa8d9bb 610 MMINOFF + sizeof (struct ether_header) > m->m_off) {
cce93e4b 611 m = m_get(M_DONTWAIT, MT_HEADER);
f0d51478
BF
612 if (m == 0) {
613 error = ENOBUFS;
614 goto bad;
615 }
616 m->m_next = m0;
617 m->m_off = MMINOFF;
3fa8d9bb 618 m->m_len = sizeof (struct ether_header);
f0d51478 619 } else {
3fa8d9bb
SL
620 m->m_off -= sizeof (struct ether_header);
621 m->m_len += sizeof (struct ether_header);
f0d51478 622 }
3fa8d9bb 623 il = mtod(m, struct ether_header *);
3fa8d9bb 624 il->ether_type = htons((u_short)type);
7f0e1e06
MK
625 bcopy((caddr_t)edst, (caddr_t)il->ether_dhost, sizeof (edst));
626 bcopy((caddr_t)is->is_addr, (caddr_t)il->ether_shost,
627 sizeof(il->ether_shost));
f0d51478
BF
628
629 /*
630 * Queue message on interface, and start output if interface
631 * not yet active.
632 */
633 s = splimp();
634 if (IF_QFULL(&ifp->if_snd)) {
635 IF_DROP(&ifp->if_snd);
caf0e371
SL
636 splx(s);
637 m_freem(m);
638 return (ENOBUFS);
f0d51478
BF
639 }
640 IF_ENQUEUE(&ifp->if_snd, m);
8d38dbc2 641 if ((is->is_flags & ILF_OACTIVE) == 0)
f0d51478
BF
642 ilstart(ifp->if_unit);
643 splx(s);
644 return (0);
caf0e371 645
f0d51478
BF
646bad:
647 m_freem(m0);
caf0e371 648 return (error);
f0d51478 649}
8d38dbc2
SL
650
651/*
652 * Watchdog routine, request statistics from board.
653 */
654ilwatch(unit)
655 int unit;
656{
657 register struct il_softc *is = &il_softc[unit];
658 register struct ifnet *ifp = &is->is_if;
659 int s;
660
661 if (is->is_flags & ILF_STATPENDING) {
662 ifp->if_timer = is->is_scaninterval;
663 return;
664 }
665 s = splimp();
666 is->is_flags |= ILF_STATPENDING;
667 if ((is->is_flags & ILF_OACTIVE) == 0)
668 ilstart(ifp->if_unit);
669 splx(s);
670 ifp->if_timer = is->is_scaninterval;
671}
672
673/*
674 * Total up the on-board statistics.
675 */
676iltotal(is)
677 register struct il_softc *is;
678{
679 register u_short *interval, *sum, *end;
680
681 interval = &is->is_stats.ils_frames;
682 sum = &is->is_sum.ils_frames;
683 end = is->is_sum.ils_fill2;
684 while (sum < end)
685 *sum++ += *interval++;
686 is->is_if.if_collisions = is->is_sum.ils_collis;
f883ae2e
KS
687 if ((is->is_flags & ILF_SETADDR) &&
688 (bcmp((caddr_t)is->is_stats.ils_addr, (caddr_t)is->is_addr,
689 sizeof (is->is_addr)) != 0)) {
690 log(LOG_ERR, "il%d: physaddr reverted\n", is->is_if.if_unit);
691 is->is_flags &= ~ILF_RUNNING;
692 ilinit(is->is_if.if_unit);
693 }
8d38dbc2 694}
1cd789fb
SL
695
696/*
697 * Process an ioctl request.
698 */
699ilioctl(ifp, cmd, data)
700 register struct ifnet *ifp;
701 int cmd;
702 caddr_t data;
703{
7f0e1e06 704 register struct ifaddr *ifa = (struct ifaddr *)data;
0f487295 705 register struct il_softc *is = &il_softc[ifp->if_unit];
1cd789fb
SL
706 int s = splimp(), error = 0;
707
708 switch (cmd) {
709
710 case SIOCSIFADDR:
7f0e1e06 711 ifp->if_flags |= IFF_UP;
1cd789fb 712 ilinit(ifp->if_unit);
7f0e1e06
MK
713
714 switch (ifa->ifa_addr.sa_family) {
cd4baa58 715#ifdef INET
7f0e1e06
MK
716 case AF_INET:
717 ((struct arpcom *)ifp)->ac_ipaddr =
718 IA_SIN(ifa)->sin_addr;
719 arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
720 break;
cd4baa58
KS
721#endif
722#ifdef NS
723 case AF_NS:
d4ce9212
MK
724 {
725 register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
726
727 if (ns_nullhost(*ina)) {
728 ina->x_host = * (union ns_host *)
729 (il_softc[ifp->if_unit].is_addr);
730 } else {
d4ce9212 731 il_setaddr(ina->x_host.c_host, ifp->if_unit);
35871340 732 return (0);
d4ce9212 733 }
cd4baa58 734 break;
d4ce9212 735 }
cd4baa58 736#endif
7f0e1e06 737 }
1cd789fb
SL
738 break;
739
0f487295
MK
740 case SIOCSIFFLAGS:
741 if ((ifp->if_flags & IFF_UP) == 0 &&
742 is->is_flags & ILF_RUNNING) {
743 ((struct ildevice *)
744 (ilinfo[ifp->if_unit]->ui_addr))->il_csr = ILC_RESET;
745 is->is_flags &= ~ILF_RUNNING;
746 } else if (ifp->if_flags & IFF_UP &&
747 (is->is_flags & ILF_RUNNING) == 0)
748 ilinit(ifp->if_unit);
749 break;
750
1cd789fb
SL
751 default:
752 error = EINVAL;
753 }
754 splx(s);
755 return (error);
756}
d4ce9212
MK
757
758/*
759 * set ethernet address for unit
760 */
761il_setaddr(physaddr, unit)
762u_char *physaddr;
763int unit;
764{
765 register struct il_softc *is = &il_softc[unit];
d4ce9212
MK
766
767 if (! (is->is_flags & ILF_RUNNING))
768 return;
769
35871340
KS
770 bcopy((caddr_t)physaddr, (caddr_t)is->is_addr, sizeof is->is_addr);
771 is->is_flags &= ~ILF_RUNNING;
772 is->is_flags |= ILF_SETADDR;
773 ilinit(unit);
d4ce9212 774}
9a0b0c74 775#endif