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