xref: /trueos/sys/net/if_fddisubr.c (revision 9394ef331eb7d0ba7f22583970cc84b62ad9f19a)
1 /*-
2  * Copyright (c) 1995, 1996
3  *	Matt Thomas <matt@3am-software.com>.  All rights reserved.
4  * Copyright (c) 1982, 1989, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed by the University of
18  *	California, Berkeley and its contributors.
19  * 4. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  *
35  *	from: if_ethersubr.c,v 1.5 1994/12/13 22:31:45 wollman Exp
36  * $FreeBSD$
37  */
38 
39 #include "opt_atalk.h"
40 #include "opt_inet.h"
41 #include "opt_inet6.h"
42 #include "opt_ipx.h"
43 
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/kernel.h>
47 #include <sys/malloc.h>
48 #include <sys/mbuf.h>
49 #include <sys/module.h>
50 #include <sys/socket.h>
51 #include <sys/sockio.h>
52 
53 #include <net/if.h>
54 #include <net/if_dl.h>
55 #include <net/if_llc.h>
56 #include <net/if_types.h>
57 #include <net/if_llatbl.h>
58 
59 #include <net/ethernet.h>
60 #include <net/netisr.h>
61 #include <net/route.h>
62 #include <net/bpf.h>
63 #include <net/fddi.h>
64 
65 #if defined(INET) || defined(INET6)
66 #include <netinet/in.h>
67 #include <netinet/in_var.h>
68 #include <netinet/if_ether.h>
69 #endif
70 #ifdef INET6
71 #include <netinet6/nd6.h>
72 #endif
73 
74 #ifdef IPX
75 #include <netipx/ipx.h>
76 #include <netipx/ipx_if.h>
77 #endif
78 
79 #ifdef DECNET
80 #include <netdnet/dn.h>
81 #endif
82 
83 #ifdef NETATALK
84 #include <netatalk/at.h>
85 #include <netatalk/at_var.h>
86 #include <netatalk/at_extern.h>
87 
88 extern u_char	at_org_code[ 3 ];
89 extern u_char	aarp_org_code[ 3 ];
90 #endif /* NETATALK */
91 
92 #include <security/mac/mac_framework.h>
93 
94 static const u_char fddibroadcastaddr[FDDI_ADDR_LEN] =
95 			{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
96 
97 static int fddi_resolvemulti(struct ifnet *, struct sockaddr **,
98 			      struct sockaddr *);
99 static int fddi_output(struct ifnet *, struct mbuf *, const struct sockaddr *,
100 		       struct route *);
101 static void fddi_input(struct ifnet *ifp, struct mbuf *m);
102 
103 #define	senderr(e)	do { error = (e); goto bad; } while (0)
104 
105 /*
106  * FDDI output routine.
107  * Encapsulate a packet of type family for the local net.
108  * Use trailer local net encapsulation if enough data in first
109  * packet leaves a multiple of 512 bytes of data in remainder.
110  * Assumes that ifp is actually pointer to arpcom structure.
111  */
112 static int
fddi_output(struct ifnet * ifp,struct mbuf * m,const struct sockaddr * dst,struct route * ro)113 fddi_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
114 	struct route *ro)
115 {
116 	u_int16_t type;
117 	int loop_copy = 0, error = 0, hdrcmplt = 0;
118  	u_char esrc[FDDI_ADDR_LEN], edst[FDDI_ADDR_LEN];
119 	struct fddi_header *fh;
120 #if defined(INET) || defined(INET6)
121 	struct llentry *lle;
122 #endif
123 
124 #ifdef MAC
125 	error = mac_ifnet_check_transmit(ifp, m);
126 	if (error)
127 		senderr(error);
128 #endif
129 
130 	if (ifp->if_flags & IFF_MONITOR)
131 		senderr(ENETDOWN);
132 	if (!((ifp->if_flags & IFF_UP) &&
133 	    (ifp->if_drv_flags & IFF_DRV_RUNNING)))
134 		senderr(ENETDOWN);
135 	getmicrotime(&ifp->if_lastchange);
136 
137 	switch (dst->sa_family) {
138 #ifdef INET
139 	case AF_INET: {
140 		struct rtentry *rt0 = NULL;
141 
142 		if (ro != NULL)
143 			rt0 = ro->ro_rt;
144 		error = arpresolve(ifp, rt0, m, dst, edst, &lle);
145 		if (error)
146 			return (error == EWOULDBLOCK ? 0 : error);
147 		type = htons(ETHERTYPE_IP);
148 		break;
149 	}
150 	case AF_ARP:
151 	{
152 		struct arphdr *ah;
153 		ah = mtod(m, struct arphdr *);
154 		ah->ar_hrd = htons(ARPHRD_ETHER);
155 
156 		loop_copy = -1; /* if this is for us, don't do it */
157 
158 		switch (ntohs(ah->ar_op)) {
159 		case ARPOP_REVREQUEST:
160 		case ARPOP_REVREPLY:
161 			type = htons(ETHERTYPE_REVARP);
162 			break;
163 		case ARPOP_REQUEST:
164 		case ARPOP_REPLY:
165 		default:
166 			type = htons(ETHERTYPE_ARP);
167 			break;
168 		}
169 
170 		if (m->m_flags & M_BCAST)
171 			bcopy(ifp->if_broadcastaddr, edst, FDDI_ADDR_LEN);
172                 else
173 			bcopy(ar_tha(ah), edst, FDDI_ADDR_LEN);
174 
175 	}
176 	break;
177 #endif /* INET */
178 #ifdef INET6
179 	case AF_INET6:
180 		error = nd6_storelladdr(ifp, m, dst, (u_char *)edst, &lle);
181 		if (error)
182 			return (error); /* Something bad happened */
183 		type = htons(ETHERTYPE_IPV6);
184 		break;
185 #endif /* INET6 */
186 #ifdef IPX
187 	case AF_IPX:
188 		type = htons(ETHERTYPE_IPX);
189  		bcopy(&((const struct sockaddr_ipx *)dst)->sipx_addr.x_host,
190 		    edst, FDDI_ADDR_LEN);
191 		break;
192 #endif /* IPX */
193 #ifdef NETATALK
194 	case AF_APPLETALK: {
195 	    struct at_ifaddr *aa;
196             if (!aarpresolve(ifp, m, (const struct sockaddr_at *)dst, edst))
197                 return (0);
198 	    /*
199 	     * ifaddr is the first thing in at_ifaddr
200 	     */
201 	    if ((aa = at_ifawithnet((const struct sockaddr_at *)dst)) == 0)
202 		goto bad;
203 
204 	    /*
205 	     * In the phase 2 case, we need to prepend an mbuf for the llc header.
206 	     * Since we must preserve the value of m, which is passed to us by
207 	     * value, we m_copy() the first mbuf, and use it for our llc header.
208 	     */
209 	    if (aa->aa_flags & AFA_PHASE2) {
210 		struct llc llc;
211 
212 		M_PREPEND(m, LLC_SNAPFRAMELEN, M_WAITOK);
213 		llc.llc_dsap = llc.llc_ssap = LLC_SNAP_LSAP;
214 		llc.llc_control = LLC_UI;
215 		bcopy(at_org_code, llc.llc_snap.org_code, sizeof(at_org_code));
216 		llc.llc_snap.ether_type = htons(ETHERTYPE_AT);
217 		bcopy(&llc, mtod(m, caddr_t), LLC_SNAPFRAMELEN);
218 		type = 0;
219 	    } else {
220 		type = htons(ETHERTYPE_AT);
221 	    }
222 	    ifa_free(&aa->aa_ifa);
223 	    break;
224 	}
225 #endif /* NETATALK */
226 
227 	case pseudo_AF_HDRCMPLT:
228 	{
229 		const struct ether_header *eh;
230 
231 		hdrcmplt = 1;
232 		eh = (const struct ether_header *)dst->sa_data;
233 		bcopy(eh->ether_shost, esrc, FDDI_ADDR_LEN);
234 		/* FALLTHROUGH */
235 	}
236 
237 	case AF_UNSPEC:
238 	{
239 		const struct ether_header *eh;
240 
241 		loop_copy = -1;
242 		eh = (const struct ether_header *)dst->sa_data;
243 		bcopy(eh->ether_dhost, edst, FDDI_ADDR_LEN);
244 		if (*edst & 1)
245 			m->m_flags |= (M_BCAST|M_MCAST);
246 		type = eh->ether_type;
247 		break;
248 	}
249 
250 	case AF_IMPLINK:
251 	{
252 		fh = mtod(m, struct fddi_header *);
253 		error = EPROTONOSUPPORT;
254 		switch (fh->fddi_fc & (FDDIFC_C|FDDIFC_L|FDDIFC_F)) {
255 			case FDDIFC_LLC_ASYNC: {
256 				/* legal priorities are 0 through 7 */
257 				if ((fh->fddi_fc & FDDIFC_Z) > 7)
258 			        	goto bad;
259 				break;
260 			}
261 			case FDDIFC_LLC_SYNC: {
262 				/* FDDIFC_Z bits reserved, must be zero */
263 				if (fh->fddi_fc & FDDIFC_Z)
264 					goto bad;
265 				break;
266 			}
267 			case FDDIFC_SMT: {
268 				/* FDDIFC_Z bits must be non zero */
269 				if ((fh->fddi_fc & FDDIFC_Z) == 0)
270 					goto bad;
271 				break;
272 			}
273 			default: {
274 				/* anything else is too dangerous */
275                	 		goto bad;
276 			}
277 		}
278 		error = 0;
279 		if (fh->fddi_dhost[0] & 1)
280 			m->m_flags |= (M_BCAST|M_MCAST);
281 		goto queue_it;
282 	}
283 	default:
284 		if_printf(ifp, "can't handle af%d\n", dst->sa_family);
285 		senderr(EAFNOSUPPORT);
286 	}
287 
288 	/*
289 	 * Add LLC header.
290 	 */
291 	if (type != 0) {
292 		struct llc *l;
293 		M_PREPEND(m, LLC_SNAPFRAMELEN, M_NOWAIT);
294 		if (m == 0)
295 			senderr(ENOBUFS);
296 		l = mtod(m, struct llc *);
297 		l->llc_control = LLC_UI;
298 		l->llc_dsap = l->llc_ssap = LLC_SNAP_LSAP;
299 		l->llc_snap.org_code[0] =
300 			l->llc_snap.org_code[1] =
301 			l->llc_snap.org_code[2] = 0;
302 		l->llc_snap.ether_type = htons(type);
303 	}
304 
305 	/*
306 	 * Add local net header.  If no space in first mbuf,
307 	 * allocate another.
308 	 */
309 	M_PREPEND(m, FDDI_HDR_LEN, M_NOWAIT);
310 	if (m == 0)
311 		senderr(ENOBUFS);
312 	fh = mtod(m, struct fddi_header *);
313 	fh->fddi_fc = FDDIFC_LLC_ASYNC|FDDIFC_LLC_PRIO4;
314 	bcopy((caddr_t)edst, (caddr_t)fh->fddi_dhost, FDDI_ADDR_LEN);
315   queue_it:
316 	if (hdrcmplt)
317 		bcopy((caddr_t)esrc, (caddr_t)fh->fddi_shost, FDDI_ADDR_LEN);
318 	else
319 		bcopy(IF_LLADDR(ifp), (caddr_t)fh->fddi_shost,
320 			FDDI_ADDR_LEN);
321 
322 	/*
323 	 * If a simplex interface, and the packet is being sent to our
324 	 * Ethernet address or a broadcast address, loopback a copy.
325 	 * XXX To make a simplex device behave exactly like a duplex
326 	 * device, we should copy in the case of sending to our own
327 	 * ethernet address (thus letting the original actually appear
328 	 * on the wire). However, we don't do that here for security
329 	 * reasons and compatibility with the original behavior.
330 	 */
331 	if ((ifp->if_flags & IFF_SIMPLEX) && (loop_copy != -1)) {
332 		if ((m->m_flags & M_BCAST) || (loop_copy > 0)) {
333 			struct mbuf *n;
334 			n = m_copy(m, 0, (int)M_COPYALL);
335 			(void) if_simloop(ifp, n, dst->sa_family,
336 					  FDDI_HDR_LEN);
337 	     	} else if (bcmp(fh->fddi_dhost, fh->fddi_shost,
338 				FDDI_ADDR_LEN) == 0) {
339 			(void) if_simloop(ifp, m, dst->sa_family,
340 					  FDDI_HDR_LEN);
341 			return (0);	/* XXX */
342 		}
343 	}
344 
345 	error = (ifp->if_transmit)(ifp, m);
346 	if (error)
347 		ifp->if_oerrors++;
348 
349 	return (error);
350 
351 bad:
352 	ifp->if_oerrors++;
353 	if (m)
354 		m_freem(m);
355 	return (error);
356 }
357 
358 /*
359  * Process a received FDDI packet.
360  */
361 static void
fddi_input(ifp,m)362 fddi_input(ifp, m)
363 	struct ifnet *ifp;
364 	struct mbuf *m;
365 {
366 	int isr;
367 	struct llc *l;
368 	struct fddi_header *fh;
369 
370 	/*
371 	 * Do consistency checks to verify assumptions
372 	 * made by code past this point.
373 	 */
374 	if ((m->m_flags & M_PKTHDR) == 0) {
375 		if_printf(ifp, "discard frame w/o packet header\n");
376 		ifp->if_ierrors++;
377 		m_freem(m);
378 		return;
379 	}
380 	if (m->m_pkthdr.rcvif == NULL) {
381 		if_printf(ifp, "discard frame w/o interface pointer\n");
382 		ifp->if_ierrors++;
383 		m_freem(m);
384 		return;
385         }
386 
387 	m = m_pullup(m, FDDI_HDR_LEN);
388 	if (m == NULL) {
389 		ifp->if_ierrors++;
390 		goto dropanyway;
391 	}
392 	fh = mtod(m, struct fddi_header *);
393 
394 	/*
395 	 * Discard packet if interface is not up.
396 	 */
397 	if (!((ifp->if_flags & IFF_UP) &&
398 	    (ifp->if_drv_flags & IFF_DRV_RUNNING)))
399 		goto dropanyway;
400 
401 	/*
402 	 * Give bpf a chance at the packet.
403 	 */
404 	BPF_MTAP(ifp, m);
405 
406 	/*
407 	 * Interface marked for monitoring; discard packet.
408 	 */
409 	if (ifp->if_flags & IFF_MONITOR) {
410 		m_freem(m);
411 		return;
412 	}
413 
414 #ifdef MAC
415 	mac_ifnet_create_mbuf(ifp, m);
416 #endif
417 
418 	/*
419 	 * Update interface statistics.
420 	 */
421 	ifp->if_ibytes += m->m_pkthdr.len;
422 	getmicrotime(&ifp->if_lastchange);
423 
424 	/*
425 	 * Discard non local unicast packets when interface
426 	 * is in promiscuous mode.
427 	 */
428 	if ((ifp->if_flags & IFF_PROMISC) && ((fh->fddi_dhost[0] & 1) == 0) &&
429 	    (bcmp(IF_LLADDR(ifp), (caddr_t)fh->fddi_dhost,
430 	     FDDI_ADDR_LEN) != 0))
431 		goto dropanyway;
432 
433 	/*
434 	 * Set mbuf flags for bcast/mcast.
435 	 */
436 	if (fh->fddi_dhost[0] & 1) {
437 		if (bcmp(ifp->if_broadcastaddr, fh->fddi_dhost,
438 		    FDDI_ADDR_LEN) == 0)
439 			m->m_flags |= M_BCAST;
440 		else
441 			m->m_flags |= M_MCAST;
442 		ifp->if_imcasts++;
443 	}
444 
445 #ifdef M_LINK0
446 	/*
447 	 * If this has a LLC priority of 0, then mark it so upper
448 	 * layers have a hint that it really came via a FDDI/Ethernet
449 	 * bridge.
450 	 */
451 	if ((fh->fddi_fc & FDDIFC_LLC_PRIO7) == FDDIFC_LLC_PRIO0)
452 		m->m_flags |= M_LINK0;
453 #endif
454 
455 	/* Strip off FDDI header. */
456 	m_adj(m, FDDI_HDR_LEN);
457 
458 	m = m_pullup(m, LLC_SNAPFRAMELEN);
459 	if (m == 0) {
460 		ifp->if_ierrors++;
461 		goto dropanyway;
462 	}
463 	l = mtod(m, struct llc *);
464 
465 	switch (l->llc_dsap) {
466 	case LLC_SNAP_LSAP:
467 	{
468 		u_int16_t type;
469 		if ((l->llc_control != LLC_UI) ||
470 		    (l->llc_ssap != LLC_SNAP_LSAP)) {
471 			ifp->if_noproto++;
472 			goto dropanyway;
473 		}
474 #ifdef NETATALK
475 		if (bcmp(&(l->llc_snap.org_code)[0], at_org_code,
476 		    sizeof(at_org_code)) == 0 &&
477 		    ntohs(l->llc_snap.ether_type) == ETHERTYPE_AT) {
478 			isr = NETISR_ATALK2;
479 			m_adj(m, LLC_SNAPFRAMELEN);
480 			break;
481 		}
482 
483 		if (bcmp(&(l->llc_snap.org_code)[0], aarp_org_code,
484 		    sizeof(aarp_org_code)) == 0 &&
485 		    ntohs(l->llc_snap.ether_type) == ETHERTYPE_AARP) {
486 			m_adj(m, LLC_SNAPFRAMELEN);
487 			isr = NETISR_AARP;
488 			break;
489 		}
490 #endif /* NETATALK */
491 		if (l->llc_snap.org_code[0] != 0 ||
492 		    l->llc_snap.org_code[1] != 0 ||
493 		    l->llc_snap.org_code[2] != 0) {
494 			ifp->if_noproto++;
495 			goto dropanyway;
496 		}
497 
498 		type = ntohs(l->llc_snap.ether_type);
499 		m_adj(m, LLC_SNAPFRAMELEN);
500 
501 		switch (type) {
502 #ifdef INET
503 		case ETHERTYPE_IP:
504 			if ((m = ip_fastforward(m)) == NULL)
505 				return;
506 			isr = NETISR_IP;
507 			break;
508 
509 		case ETHERTYPE_ARP:
510 			if (ifp->if_flags & IFF_NOARP)
511 				goto dropanyway;
512 			isr = NETISR_ARP;
513 			break;
514 #endif
515 #ifdef INET6
516 		case ETHERTYPE_IPV6:
517 			isr = NETISR_IPV6;
518 			break;
519 #endif
520 #ifdef IPX
521 		case ETHERTYPE_IPX:
522 			isr = NETISR_IPX;
523 			break;
524 #endif
525 #ifdef DECNET
526 		case ETHERTYPE_DECNET:
527 			isr = NETISR_DECNET;
528 			break;
529 #endif
530 #ifdef NETATALK
531 		case ETHERTYPE_AT:
532 	                isr = NETISR_ATALK1;
533 			break;
534 	        case ETHERTYPE_AARP:
535 			isr = NETISR_AARP;
536 			break;
537 #endif /* NETATALK */
538 		default:
539 			/* printf("fddi_input: unknown protocol 0x%x\n", type); */
540 			ifp->if_noproto++;
541 			goto dropanyway;
542 		}
543 		break;
544 	}
545 
546 	default:
547 		/* printf("fddi_input: unknown dsap 0x%x\n", l->llc_dsap); */
548 		ifp->if_noproto++;
549 		goto dropanyway;
550 	}
551 	M_SETFIB(m, ifp->if_fib);
552 	netisr_dispatch(isr, m);
553 	return;
554 
555 dropanyway:
556 	ifp->if_iqdrops++;
557 	if (m)
558 		m_freem(m);
559 	return;
560 }
561 
562 /*
563  * Perform common duties while attaching to interface list
564  */
565 void
fddi_ifattach(ifp,lla,bpf)566 fddi_ifattach(ifp, lla, bpf)
567 	struct ifnet *ifp;
568 	const u_int8_t *lla;
569 	int bpf;
570 {
571 	struct ifaddr *ifa;
572 	struct sockaddr_dl *sdl;
573 
574 	ifp->if_type = IFT_FDDI;
575 	ifp->if_addrlen = FDDI_ADDR_LEN;
576 	ifp->if_hdrlen = 21;
577 
578 	if_attach(ifp);         /* Must be called before additional assignments */
579 
580 	ifp->if_mtu = FDDIMTU;
581 	ifp->if_output = fddi_output;
582 	ifp->if_input = fddi_input;
583 	ifp->if_resolvemulti = fddi_resolvemulti;
584 	ifp->if_broadcastaddr = fddibroadcastaddr;
585 	ifp->if_baudrate = 100000000;
586 #ifdef IFF_NOTRAILERS
587 	ifp->if_flags |= IFF_NOTRAILERS;
588 #endif
589 	ifa = ifp->if_addr;
590 	KASSERT(ifa != NULL, ("%s: no lladdr!\n", __func__));
591 
592 	sdl = (struct sockaddr_dl *)ifa->ifa_addr;
593 	sdl->sdl_type = IFT_FDDI;
594 	sdl->sdl_alen = ifp->if_addrlen;
595 	bcopy(lla, LLADDR(sdl), ifp->if_addrlen);
596 
597 	if (bpf)
598 		bpfattach(ifp, DLT_FDDI, FDDI_HDR_LEN);
599 
600 	return;
601 }
602 
603 void
fddi_ifdetach(ifp,bpf)604 fddi_ifdetach(ifp, bpf)
605 	struct ifnet *ifp;
606 	int bpf;
607 {
608 
609 	if (bpf)
610 		bpfdetach(ifp);
611 
612 	if_detach(ifp);
613 
614 	return;
615 }
616 
617 int
fddi_ioctl(ifp,command,data)618 fddi_ioctl (ifp, command, data)
619 	struct ifnet *ifp;
620 	u_long command;
621 	caddr_t data;
622 {
623 	struct ifaddr *ifa;
624 	struct ifreq *ifr;
625 	int error;
626 
627 	ifa = (struct ifaddr *) data;
628 	ifr = (struct ifreq *) data;
629 	error = 0;
630 
631 	switch (command) {
632 	case SIOCSIFADDR:
633 		ifp->if_flags |= IFF_UP;
634 
635 		switch (ifa->ifa_addr->sa_family) {
636 #ifdef INET
637 		case AF_INET:	/* before arpwhohas */
638 			ifp->if_init(ifp->if_softc);
639 			arp_ifinit(ifp, ifa);
640 			break;
641 #endif
642 #ifdef IPX
643 		/*
644 		 * XXX - This code is probably wrong
645 		 */
646 		case AF_IPX: {
647 				struct ipx_addr *ina;
648 
649 				ina = &(IA_SIPX(ifa)->sipx_addr);
650 
651 				if (ipx_nullhost(*ina)) {
652 					ina->x_host = *(union ipx_host *)
653 							IF_LLADDR(ifp);
654 				} else {
655 					bcopy((caddr_t) ina->x_host.c_host,
656 					      (caddr_t) IF_LLADDR(ifp),
657 					      ETHER_ADDR_LEN);
658 				}
659 
660 				/*
661 				 * Set new address
662 				 */
663 				ifp->if_init(ifp->if_softc);
664 			}
665 			break;
666 #endif
667 		default:
668 			ifp->if_init(ifp->if_softc);
669 			break;
670 		}
671 		break;
672 	case SIOCGIFADDR: {
673 			struct sockaddr *sa;
674 
675 			sa = (struct sockaddr *) & ifr->ifr_data;
676 			bcopy(IF_LLADDR(ifp),
677 			      (caddr_t) sa->sa_data, FDDI_ADDR_LEN);
678 
679 		}
680 		break;
681 	case SIOCSIFMTU:
682 		/*
683 		 * Set the interface MTU.
684 		 */
685 		if (ifr->ifr_mtu > FDDIMTU) {
686 			error = EINVAL;
687 		} else {
688 			ifp->if_mtu = ifr->ifr_mtu;
689 		}
690 		break;
691 	default:
692 		error = EINVAL;
693 		break;
694 	}
695 
696 	return (error);
697 }
698 
699 static int
fddi_resolvemulti(ifp,llsa,sa)700 fddi_resolvemulti(ifp, llsa, sa)
701 	struct ifnet *ifp;
702 	struct sockaddr **llsa;
703 	struct sockaddr *sa;
704 {
705 	struct sockaddr_dl *sdl;
706 #ifdef INET
707 	struct sockaddr_in *sin;
708 #endif
709 #ifdef INET6
710 	struct sockaddr_in6 *sin6;
711 #endif
712 	u_char *e_addr;
713 
714 	switch(sa->sa_family) {
715 	case AF_LINK:
716 		/*
717 		 * No mapping needed. Just check that it's a valid MC address.
718 		 */
719 		sdl = (struct sockaddr_dl *)sa;
720 		e_addr = LLADDR(sdl);
721 		if ((e_addr[0] & 1) != 1)
722 			return (EADDRNOTAVAIL);
723 		*llsa = 0;
724 		return (0);
725 
726 #ifdef INET
727 	case AF_INET:
728 		sin = (struct sockaddr_in *)sa;
729 		if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr)))
730 			return (EADDRNOTAVAIL);
731 		sdl = malloc(sizeof *sdl, M_IFMADDR,
732 		       M_NOWAIT | M_ZERO);
733 		if (sdl == NULL)
734 			return (ENOMEM);
735 		sdl->sdl_len = sizeof *sdl;
736 		sdl->sdl_family = AF_LINK;
737 		sdl->sdl_index = ifp->if_index;
738 		sdl->sdl_type = IFT_FDDI;
739 		sdl->sdl_nlen = 0;
740 		sdl->sdl_alen = FDDI_ADDR_LEN;
741 		sdl->sdl_slen = 0;
742 		e_addr = LLADDR(sdl);
743 		ETHER_MAP_IP_MULTICAST(&sin->sin_addr, e_addr);
744 		*llsa = (struct sockaddr *)sdl;
745 		return (0);
746 #endif
747 #ifdef INET6
748 	case AF_INET6:
749 		sin6 = (struct sockaddr_in6 *)sa;
750 		if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
751 			/*
752 			 * An IP6 address of 0 means listen to all
753 			 * of the Ethernet multicast address used for IP6.
754 			 * (This is used for multicast routers.)
755 			 */
756 			ifp->if_flags |= IFF_ALLMULTI;
757 			*llsa = 0;
758 			return (0);
759 		}
760 		if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
761 			return (EADDRNOTAVAIL);
762 		sdl = malloc(sizeof *sdl, M_IFMADDR,
763 		       M_NOWAIT | M_ZERO);
764 		if (sdl == NULL)
765 			return (ENOMEM);
766 		sdl->sdl_len = sizeof *sdl;
767 		sdl->sdl_family = AF_LINK;
768 		sdl->sdl_index = ifp->if_index;
769 		sdl->sdl_type = IFT_FDDI;
770 		sdl->sdl_nlen = 0;
771 		sdl->sdl_alen = FDDI_ADDR_LEN;
772 		sdl->sdl_slen = 0;
773 		e_addr = LLADDR(sdl);
774 		ETHER_MAP_IPV6_MULTICAST(&sin6->sin6_addr, e_addr);
775 		*llsa = (struct sockaddr *)sdl;
776 		return (0);
777 #endif
778 
779 	default:
780 		/*
781 		 * Well, the text isn't quite right, but it's the name
782 		 * that counts...
783 		 */
784 		return (EAFNOSUPPORT);
785 	}
786 
787 	return (0);
788 }
789 
790 static moduledata_t fddi_mod = {
791 	"fddi",	/* module name */
792 	NULL,	/* event handler */
793 	0	/* extra data */
794 };
795 
796 DECLARE_MODULE(fddi, fddi_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
797 MODULE_VERSION(fddi, 1);
798