1 /*
2 * Copyright (c) 1998, Larry Lile
3 * All rights reserved.
4 *
5 * For latest sources and information on this driver, please
6 * go to http://anarchy.stdio.com.
7 *
8 * Questions, comments or suggestions should be directed to
9 * Larry Lile <lile@stdio.com>.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice unmodified, this list of conditions, and the following
16 * disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * $FreeBSD: releng/5.1/sys/net/if_iso88025subr.c 112308 2003-03-16 00:17:44Z mdodd $
34 *
35 */
36
37 /*
38 *
39 * General ISO 802.5 (Token Ring) support routines
40 *
41 */
42
43 #include "opt_inet.h"
44 #include "opt_inet6.h"
45 #include "opt_ipx.h"
46 #include "opt_mac.h"
47
48 #include <sys/param.h>
49 #include <sys/systm.h>
50 #include <sys/kernel.h>
51 #include <sys/mac.h>
52 #include <sys/malloc.h>
53 #include <sys/mbuf.h>
54 #include <sys/module.h>
55 #include <sys/socket.h>
56 #include <sys/sockio.h>
57
58 #include <net/if.h>
59 #include <net/if_dl.h>
60 #include <net/if_llc.h>
61 #include <net/if_types.h>
62
63 #include <net/netisr.h>
64 #include <net/route.h>
65 #include <net/bpf.h>
66 #include <net/iso88025.h>
67
68 #if defined(INET) || defined(INET6)
69 #include <netinet/in.h>
70 #include <netinet/in_var.h>
71 #include <netinet/if_ether.h>
72 #endif
73 #ifdef INET6
74 #include <netinet6/nd6.h>
75 #endif
76
77 #ifdef IPX
78 #include <netipx/ipx.h>
79 #include <netipx/ipx_if.h>
80 #endif
81
82 static u_char iso88025_broadcastaddr[ISO88025_ADDR_LEN] =
83 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
84
85 static int iso88025_resolvemulti (struct ifnet *, struct sockaddr **,
86 struct sockaddr *);
87
88 #define IFP2AC(IFP) ((struct arpcom *)IFP)
89 #define senderr(e) do { error = (e); goto bad; } while (0)
90
91 /*
92 * Perform common duties while attaching to interface list
93 */
94 void
95 iso88025_ifattach(struct ifnet *ifp, int bpf)
96 {
97 struct ifaddr *ifa;
98 struct sockaddr_dl *sdl;
99
100 ifa = NULL;
101
102 ifp->if_type = IFT_ISO88025;
103 ifp->if_addrlen = ISO88025_ADDR_LEN;
104 ifp->if_hdrlen = ISO88025_HDR_LEN;
105
106 if_attach(ifp); /* Must be called before additional assignments */
107
108 ifp->if_output = iso88025_output;
109 ifp->if_input = iso88025_input;
110 ifp->if_resolvemulti = iso88025_resolvemulti;
111 ifp->if_broadcastaddr = iso88025_broadcastaddr;
112
113 if (ifp->if_baudrate == 0)
114 ifp->if_baudrate = TR_16MBPS; /* 16Mbit should be a safe default */
115 if (ifp->if_mtu == 0)
116 ifp->if_mtu = ISO88025_DEFAULT_MTU;
117
118 ifa = ifaddr_byindex(ifp->if_index);
119 if (ifa == 0) {
120 if_printf(ifp, "%s() no lladdr!\n", __func__);
121 return;
122 }
123
124 sdl = (struct sockaddr_dl *)ifa->ifa_addr;
125 sdl->sdl_type = IFT_ISO88025;
126 sdl->sdl_alen = ifp->if_addrlen;
127 bcopy(IFP2AC(ifp)->ac_enaddr, LLADDR(sdl), ifp->if_addrlen);
128
129 if (bpf)
130 bpfattach(ifp, DLT_IEEE802, ISO88025_HDR_LEN);
131
132 return;
133 }
134
135 /*
136 * Perform common duties while detaching a Token Ring interface
137 */
138 void
139 iso88025_ifdetach(ifp, bpf)
140 struct ifnet *ifp;
141 int bpf;
142 {
143
144 if (bpf)
145 bpfdetach(ifp);
146
147 if_detach(ifp);
148
149 return;
150 }
151
152 int
153 iso88025_ioctl(struct ifnet *ifp, int command, caddr_t data)
154 {
155 struct ifaddr *ifa;
156 struct ifreq *ifr;
157 int error;
158
159 ifa = (struct ifaddr *) data;
160 ifr = (struct ifreq *) data;
161 error = 0;
162
163 switch (command) {
164 case SIOCSIFADDR:
165 ifp->if_flags |= IFF_UP;
166
167 switch (ifa->ifa_addr->sa_family) {
168 #ifdef INET
169 case AF_INET:
170 ifp->if_init(ifp->if_softc); /* before arpwhohas */
171 arp_ifinit(ifp, ifa);
172 break;
173 #endif /* INET */
174 #ifdef IPX
175 /*
176 * XXX - This code is probably wrong
177 */
178 case AF_IPX:
179 {
180 struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr);
181 struct arpcom *ac = IFP2AC(ifp);
182
183 if (ipx_nullhost(*ina))
184 ina->x_host = *(union ipx_host *)ac->ac_enaddr;
185 else {
186 bcopy((caddr_t) ina->x_host.c_host,
187 (caddr_t) ac->ac_enaddr,
188 ISO88025_ADDR_LEN);
189 }
190
191 /*
192 * Set new address
193 */
194 ifp->if_init(ifp->if_softc);
195 break;
196 }
197 #endif /* IPX */
198 default:
199 ifp->if_init(ifp->if_softc);
200 break;
201 }
202 break;
203
204 case SIOCGIFADDR:
205 {
206 struct sockaddr *sa;
207
208 sa = (struct sockaddr *) & ifr->ifr_data;
209 bcopy(IFP2AC(ifp)->ac_enaddr,
210 (caddr_t) sa->sa_data, ISO88025_ADDR_LEN);
211 }
212 break;
213
214 case SIOCSIFMTU:
215 /*
216 * Set the interface MTU.
217 */
218 if (ifr->ifr_mtu > ISO88025_MAX_MTU) {
219 error = EINVAL;
220 } else {
221 ifp->if_mtu = ifr->ifr_mtu;
222 }
223 break;
224 default:
225 error = EINVAL; /* XXX netbsd has ENOTTY??? */
226 break;
227 }
228
229 return (error);
230 }
231
232 /*
233 * ISO88025 encapsulation
234 */
235 int
236 iso88025_output(ifp, m, dst, rt0)
237 struct ifnet *ifp;
238 struct mbuf *m;
239 struct sockaddr *dst;
240 struct rtentry *rt0;
241 {
242 u_int16_t snap_type = 0;
243 int loop_copy = 0, error = 0, rif_len = 0;
244 u_char edst[ISO88025_ADDR_LEN];
245 struct iso88025_header *th;
246 struct iso88025_header gen_th;
247 struct sockaddr_dl *sdl = NULL;
248 struct rtentry *rt;
249 struct arpcom *ac = IFP2AC(ifp);
250
251 #ifdef MAC
252 error = mac_check_ifnet_transmit(ifp, m);
253 if (error)
254 senderr(error);
255 #endif
256
257 if (ifp->if_flags & IFF_MONITOR)
258 senderr(ENETDOWN);
259 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
260 senderr(ENETDOWN);
261 getmicrotime(&ifp->if_lastchange);
262
263 error = rt_check(&rt, &rt0, dst);
264 if (error)
265 goto bad;
266
267 /* Calculate routing info length based on arp table entry */
268 if (rt && (sdl = (struct sockaddr_dl *)rt->rt_gateway))
269 if (SDL_ISO88025(sdl)->trld_rcf != 0)
270 rif_len = TR_RCF_RIFLEN(SDL_ISO88025(sdl)->trld_rcf);
271
272 /* Generate a generic 802.5 header for the packet */
273 gen_th.ac = TR_AC;
274 gen_th.fc = TR_LLC_FRAME;
275 (void)memcpy((caddr_t)gen_th.iso88025_shost, (caddr_t)ac->ac_enaddr,
276 ISO88025_ADDR_LEN);
277 if (rif_len) {
278 gen_th.iso88025_shost[0] |= TR_RII;
279 if (rif_len > 2) {
280 gen_th.rcf = SDL_ISO88025(sdl)->trld_rcf;
281 (void)memcpy((caddr_t)gen_th.rd,
282 (caddr_t)SDL_ISO88025(sdl)->trld_route,
283 rif_len - 2);
284 }
285 }
286
287 switch (dst->sa_family) {
288 #ifdef INET
289 case AF_INET:
290 if (!arpresolve(ifp, rt, m, dst, edst, rt0))
291 return (0); /* if not yet resolved */
292 snap_type = ETHERTYPE_IP;
293 break;
294 #endif /* INET */
295 #ifdef NOT_YET
296 #ifdef INET6
297 case AF_INET6:
298 if (!nd6_storelladdr(&ac->ac_if, rt, m, dst, (u_char *)edst)) {
299 /* Something bad happened */
300 return(0);
301 }
302 snap_type = ETHERTYPE_IPV6;
303 break;
304 #endif /* INET6 */
305 #endif /* NOT_YET */
306 #ifdef IPX
307 case AF_IPX:
308 {
309 u_int8_t *cp;
310
311 bcopy((caddr_t)&(satoipx_addr(dst).x_host), (caddr_t)edst,
312 ISO88025_ADDR_LEN);
313
314 M_PREPEND(m, 3, M_TRYWAIT);
315 if (m == 0)
316 senderr(ENOBUFS);
317 m = m_pullup(m, 3);
318 if (m == 0)
319 senderr(ENOBUFS);
320 cp = mtod(m, u_int8_t *);
321 *cp++ = ETHERTYPE_IPX_8022;
322 *cp++ = ETHERTYPE_IPX_8022;
323 *cp++ = LLC_UI;
324 }
325 break;
326 #endif /* IPX */
327 case AF_UNSPEC:
328 {
329 struct iso88025_sockaddr_data *sd;
330 /*
331 * For AF_UNSPEC sockaddr.sa_data must contain all of the
332 * mac information needed to send the packet. This allows
333 * full mac, llc, and source routing function to be controlled.
334 * llc and source routing information must already be in the
335 * mbuf provided, ac/fc are set in sa_data. sockaddr.sa_data
336 * should be an iso88025_sockaddr_data structure see iso88025.h
337 */
338 loop_copy = -1;
339 sd = (struct iso88025_sockaddr_data *)dst->sa_data;
340 gen_th.ac = sd->ac;
341 gen_th.fc = sd->fc;
342 (void)memcpy((caddr_t)edst, (caddr_t)sd->ether_dhost,
343 ISO88025_ADDR_LEN);
344 (void)memcpy((caddr_t)gen_th.iso88025_shost,
345 (caddr_t)sd->ether_shost, ISO88025_ADDR_LEN);
346 rif_len = 0;
347 break;
348 }
349 default:
350 if_printf(ifp, "can't handle af%d\n", dst->sa_family);
351 senderr(EAFNOSUPPORT);
352 break;
353 }
354
355 /*
356 * Add LLC header.
357 */
358 if (snap_type != 0) {
359 struct llc *l;
360 M_PREPEND(m, LLC_SNAPFRAMELEN, M_DONTWAIT);
361 if (m == 0)
362 senderr(ENOBUFS);
363 l = mtod(m, struct llc *);
364 l->llc_control = LLC_UI;
365 l->llc_dsap = l->llc_ssap = LLC_SNAP_LSAP;
366 l->llc_snap.org_code[0] =
367 l->llc_snap.org_code[1] =
368 l->llc_snap.org_code[2] = 0;
369 l->llc_snap.ether_type = htons(snap_type);
370 }
371
372 /*
373 * Add local net header. If no space in first mbuf,
374 * allocate another.
375 */
376 M_PREPEND(m, ISO88025_HDR_LEN + rif_len, M_DONTWAIT);
377 if (m == 0)
378 senderr(ENOBUFS);
379 th = mtod(m, struct iso88025_header *);
380 bcopy((caddr_t)edst, (caddr_t)&gen_th.iso88025_dhost, ISO88025_ADDR_LEN);
381
382 /* Copy as much of the generic header as is needed into the mbuf */
383 memcpy(th, &gen_th, ISO88025_HDR_LEN + rif_len);
384
385 /*
386 * If a simplex interface, and the packet is being sent to our
387 * Ethernet address or a broadcast address, loopback a copy.
388 * XXX To make a simplex device behave exactly like a duplex
389 * device, we should copy in the case of sending to our own
390 * ethernet address (thus letting the original actually appear
391 * on the wire). However, we don't do that here for security
392 * reasons and compatibility with the original behavior.
393 */
394 if ((ifp->if_flags & IFF_SIMPLEX) && (loop_copy != -1)) {
395 if ((m->m_flags & M_BCAST) || (loop_copy > 0)) {
396 struct mbuf *n;
397 n = m_copy(m, 0, (int)M_COPYALL);
398 (void) if_simloop(ifp, n, dst->sa_family,
399 ISO88025_HDR_LEN);
400 } else if (bcmp(th->iso88025_dhost, th->iso88025_shost,
401 ETHER_ADDR_LEN) == 0) {
402 (void) if_simloop(ifp, m, dst->sa_family,
403 ISO88025_HDR_LEN);
404 return(0); /* XXX */
405 }
406 }
407
408 if (! IF_HANDOFF_ADJ(&ifp->if_snd, m, ifp, ISO88025_HDR_LEN + LLC_SNAPFRAMELEN) ) {
409 printf("iso88025_output: packet dropped QFULL.\n");
410 senderr(ENOBUFS);
411 }
412 return (error);
413
414 bad:
415 ifp->if_oerrors++;
416 if (m)
417 m_freem(m);
418 return (error);
419 }
420
421 /*
422 * ISO 88025 de-encapsulation
423 */
424 void
425 iso88025_input(ifp, m)
426 struct ifnet *ifp;
427 struct mbuf *m;
428 {
429 struct iso88025_header *th;
430 struct llc *l;
431 int isr;
432 int mac_hdr_len;
433
434 /*
435 * Do consistency checks to verify assumptions
436 * made by code past this point.
437 */
438 if ((m->m_flags & M_PKTHDR) == 0) {
439 if_printf(ifp, "discard frame w/o packet header\n");
440 ifp->if_ierrors++;
441 m_freem(m);
442 return;
443 }
444 if (m->m_pkthdr.rcvif == NULL) {
445 if_printf(ifp, "discard frame w/o interface pointer\n");
446 ifp->if_ierrors++;
447 m_freem(m);
448 return;
449 }
450
451 m = m_pullup(m, ISO88025_HDR_LEN);
452 if (m == NULL) {
453 ifp->if_ierrors++;
454 goto dropanyway;
455 }
456 th = mtod(m, struct iso88025_header *);
457 m->m_pkthdr.header = (void *)th;
458
459 /*
460 * Discard packet if interface is not up.
461 */
462 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
463 goto dropanyway;
464
465 /*
466 * Give bpf a chance at the packet.
467 */
468 BPF_MTAP(ifp, m);
469
470 /*
471 * Interface marked for monitoring; discard packet.
472 */
473 if (ifp->if_flags & IFF_MONITOR) {
474 m_freem(m);
475 return;
476 }
477
478 #ifdef MAC
479 mac_create_mbuf_from_ifnet(ifp, m);
480 #endif
481
482 /*
483 * Update interface statistics.
484 */
485 ifp->if_ibytes += m->m_pkthdr.len;
486 getmicrotime(&ifp->if_lastchange);
487
488 /*
489 * Discard non local unicast packets when interface
490 * is in promiscuous mode.
491 */
492 if ((ifp->if_flags & IFF_PROMISC) &&
493 ((th->iso88025_dhost[0] & 1) == 0) &&
494 (bcmp(IFP2AC(ifp)->ac_enaddr, (caddr_t) th->iso88025_dhost,
495 ISO88025_ADDR_LEN) != 0))
496 goto dropanyway;
497
498 /*
499 * Set mbuf flags for bcast/mcast.
500 */
501 if (th->iso88025_dhost[0] & 1) {
502 if (bcmp((caddr_t)iso88025_broadcastaddr,
503 (caddr_t)th->iso88025_dhost, ISO88025_ADDR_LEN) == 0)
504 m->m_flags |= M_BCAST;
505 else
506 m->m_flags |= M_MCAST;
507 ifp->if_imcasts++;
508 }
509
510 mac_hdr_len = ISO88025_HDR_LEN;
511 /* Check for source routing info */
512 if (th->iso88025_shost[0] & TR_RII)
513 mac_hdr_len += TR_RCF_RIFLEN(th->rcf);
514
515 /* Strip off ISO88025 header. */
516 m_adj(m, mac_hdr_len);
517
518 m = m_pullup(m, LLC_SNAPFRAMELEN);
519 if (m == 0) {
520 ifp->if_ierrors++;
521 goto dropanyway;
522 }
523 l = mtod(m, struct llc *);
524
525 switch (l->llc_dsap) {
526 #ifdef IPX
527 case ETHERTYPE_IPX_8022: /* Thanks a bunch Novell */
528 if ((l->llc_control != LLC_UI) ||
529 (l->llc_ssap != ETHERTYPE_IPX_8022)) {
530 ifp->if_noproto++;
531 goto dropanyway;
532 }
533
534 th->iso88025_shost[0] &= ~(TR_RII);
535 m_adj(m, 3);
536 isr = NETISR_IPX;
537 break;
538 #endif /* IPX */
539 case LLC_SNAP_LSAP: {
540 u_int16_t type;
541 if ((l->llc_control != LLC_UI) ||
542 (l->llc_ssap != LLC_SNAP_LSAP)) {
543 ifp->if_noproto++;
544 goto dropanyway;
545 }
546
547 if (l->llc_snap.org_code[0] != 0 ||
548 l->llc_snap.org_code[1] != 0 ||
549 l->llc_snap.org_code[2] != 0) {
550 ifp->if_noproto++;
551 goto dropanyway;
552 }
553
554 type = ntohs(l->llc_snap.ether_type);
555 m_adj(m, LLC_SNAPFRAMELEN);
556 switch (type) {
557 #ifdef INET
558 case ETHERTYPE_IP:
559 th->iso88025_shost[0] &= ~(TR_RII);
560 if (ipflow_fastforward(m))
561 return;
562 isr = NETISR_IP;
563 break;
564
565 case ETHERTYPE_ARP:
566 if (ifp->if_flags & IFF_NOARP)
567 goto dropanyway;
568 isr = NETISR_ARP;
569 break;
570 #endif /* INET */
571 #ifdef IPX_SNAP /* XXX: Not supported! */
572 case ETHERTYPE_IPX:
573 th->iso88025_shost[0] &= ~(TR_RII);
574 isr = NETISR_IPX;
575 break;
576 #endif /* IPX_SNAP */
577 #ifdef NOT_YET
578 #ifdef INET6
579 case ETHERTYPE_IPV6:
580 th->iso88025_shost[0] &= ~(TR_RII);
581 isr = NETISR_IPV6;
582 break;
583 #endif /* INET6 */
584 #endif /* NOT_YET */
585 default:
586 printf("iso88025_input: unexpected llc_snap ether_type 0x%02x\n", type);
587 ifp->if_noproto++;
588 goto dropanyway;
589 }
590 break;
591 }
592 #ifdef ISO
593 case LLC_ISO_LSAP:
594 switch (l->llc_control) {
595 case LLC_UI:
596 ifp->if_noproto++;
597 goto dropanyway;
598 break;
599 case LLC_XID:
600 case LLC_XID_P:
601 if(m->m_len < ISO88025_ADDR_LEN)
602 goto dropanyway;
603 l->llc_window = 0;
604 l->llc_fid = 9;
605 l->llc_class = 1;
606 l->llc_dsap = l->llc_ssap = 0;
607 /* Fall through to */
608 case LLC_TEST:
609 case LLC_TEST_P:
610 {
611 struct sockaddr sa;
612 struct arpcom *ac;
613 struct iso88025_sockaddr_data *th2;
614 int i;
615 u_char c;
616
617 ac = IFP2AC(ifp);
618 c = l->llc_dsap;
619
620 if (th->iso88025_shost[0] & TR_RII) { /* XXX */
621 printf("iso88025_input: dropping source routed LLC_TEST\n");
622 goto dropanyway;
623 }
624 l->llc_dsap = l->llc_ssap;
625 l->llc_ssap = c;
626 if (m->m_flags & (M_BCAST | M_MCAST))
627 bcopy((caddr_t)ac->ac_enaddr,
628 (caddr_t)th->iso88025_dhost,
629 ISO88025_ADDR_LEN);
630 sa.sa_family = AF_UNSPEC;
631 sa.sa_len = sizeof(sa);
632 th2 = (struct iso88025_sockaddr_data *)sa.sa_data;
633 for (i = 0; i < ISO88025_ADDR_LEN; i++) {
634 th2->ether_shost[i] = c = th->iso88025_dhost[i];
635 th2->ether_dhost[i] = th->iso88025_dhost[i] =
636 th->iso88025_shost[i];
637 th->iso88025_shost[i] = c;
638 }
639 th2->ac = TR_AC;
640 th2->fc = TR_LLC_FRAME;
641 ifp->if_output(ifp, m, &sa, NULL);
642 return;
643 }
644 default:
645 printf("iso88025_input: unexpected llc control 0x%02x\n", l->llc_control);
646 ifp->if_noproto++;
647 goto dropanyway;
648 break;
649 }
650 break;
651 #endif /* ISO */
652 default:
653 printf("iso88025_input: unknown dsap 0x%x\n", l->llc_dsap);
654 ifp->if_noproto++;
655 goto dropanyway;
656 break;
657 }
658
659 netisr_dispatch(isr, m);
660 return;
661
662 dropanyway:
663 ifp->if_iqdrops++;
664 if (m)
665 m_freem(m);
666 return;
667 }
668
669 static int
670 iso88025_resolvemulti (ifp, llsa, sa)
671 struct ifnet *ifp;
672 struct sockaddr **llsa;
673 struct sockaddr *sa;
674 {
675 struct sockaddr_dl *sdl;
676 struct sockaddr_in *sin;
677 #ifdef INET6
678 struct sockaddr_in6 *sin6;
679 #endif
680 u_char *e_addr;
681
682 switch(sa->sa_family) {
683 case AF_LINK:
684 /*
685 * No mapping needed. Just check that it's a valid MC address.
686 */
687 sdl = (struct sockaddr_dl *)sa;
688 e_addr = LLADDR(sdl);
689 if ((e_addr[0] & 1) != 1) {
690 return (EADDRNOTAVAIL);
691 }
692 *llsa = 0;
693 return (0);
694
695 #ifdef INET
696 case AF_INET:
697 sin = (struct sockaddr_in *)sa;
698 if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) {
699 return (EADDRNOTAVAIL);
700 }
701 MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR,
702 M_WAITOK|M_ZERO);
703 sdl->sdl_len = sizeof *sdl;
704 sdl->sdl_family = AF_LINK;
705 sdl->sdl_index = ifp->if_index;
706 sdl->sdl_type = IFT_ISO88025;
707 sdl->sdl_alen = ISO88025_ADDR_LEN;
708 e_addr = LLADDR(sdl);
709 ETHER_MAP_IP_MULTICAST(&sin->sin_addr, e_addr);
710 *llsa = (struct sockaddr *)sdl;
711 return (0);
712 #endif
713 #ifdef INET6
714 case AF_INET6:
715 sin6 = (struct sockaddr_in6 *)sa;
716 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
717 /*
718 * An IP6 address of 0 means listen to all
719 * of the Ethernet multicast address used for IP6.
720 * (This is used for multicast routers.)
721 */
722 ifp->if_flags |= IFF_ALLMULTI;
723 *llsa = 0;
724 return (0);
725 }
726 if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
727 return (EADDRNOTAVAIL);
728 }
729 MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR,
730 M_WAITOK|M_ZERO);
731 sdl->sdl_len = sizeof *sdl;
732 sdl->sdl_family = AF_LINK;
733 sdl->sdl_index = ifp->if_index;
734 sdl->sdl_type = IFT_ISO88025;
735 sdl->sdl_alen = ISO88025_ADDR_LEN;
736 e_addr = LLADDR(sdl);
737 ETHER_MAP_IPV6_MULTICAST(&sin6->sin6_addr, e_addr);
738 *llsa = (struct sockaddr *)sdl;
739 return (0);
740 #endif
741
742 default:
743 /*
744 * Well, the text isn't quite right, but it's the name
745 * that counts...
746 */
747 return (EAFNOSUPPORT);
748 }
749
750 return (0);
751 }
752
753 static moduledata_t iso88025_mod = {
754 "iso88025",
755 NULL,
756 0
757 };
758
759 DECLARE_MODULE(iso88025, iso88025_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
760 MODULE_VERSION(iso88025, 1);
Cache object: b1f9db58a8649eff3ec362c0b5f8f94d
|