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