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$
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 const 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 senderr(e) do { error = (e); goto bad; } while (0)
89
90 /*
91 * Perform common duties while attaching to interface list
92 */
93 void
94 iso88025_ifattach(struct ifnet *ifp, int bpf)
95 {
96 struct ifaddr *ifa;
97 struct sockaddr_dl *sdl;
98
99 ifa = NULL;
100
101 ifp->if_type = IFT_ISO88025;
102 ifp->if_addrlen = ISO88025_ADDR_LEN;
103 ifp->if_hdrlen = ISO88025_HDR_LEN;
104
105 if_attach(ifp); /* Must be called before additional assignments */
106
107 ifp->if_output = iso88025_output;
108 ifp->if_input = iso88025_input;
109 ifp->if_resolvemulti = iso88025_resolvemulti;
110 ifp->if_broadcastaddr = iso88025_broadcastaddr;
111
112 if (ifp->if_baudrate == 0)
113 ifp->if_baudrate = TR_16MBPS; /* 16Mbit should be a safe default */
114 if (ifp->if_mtu == 0)
115 ifp->if_mtu = ISO88025_DEFAULT_MTU;
116
117 ifa = ifaddr_byindex(ifp->if_index);
118 if (ifa == 0) {
119 if_printf(ifp, "%s() no lladdr!\n", __func__);
120 return;
121 }
122
123 sdl = (struct sockaddr_dl *)ifa->ifa_addr;
124 sdl->sdl_type = IFT_ISO88025;
125 sdl->sdl_alen = ifp->if_addrlen;
126 bcopy(IFP2AC(ifp)->ac_enaddr, LLADDR(sdl), ifp->if_addrlen);
127
128 if (bpf)
129 bpfattach(ifp, DLT_IEEE802, ISO88025_HDR_LEN);
130
131 return;
132 }
133
134 /*
135 * Perform common duties while detaching a Token Ring interface
136 */
137 void
138 iso88025_ifdetach(ifp, bpf)
139 struct ifnet *ifp;
140 int bpf;
141 {
142
143 if (bpf)
144 bpfdetach(ifp);
145
146 if_detach(ifp);
147
148 return;
149 }
150
151 int
152 iso88025_ioctl(struct ifnet *ifp, int command, caddr_t data)
153 {
154 struct ifaddr *ifa;
155 struct ifreq *ifr;
156 int error;
157
158 ifa = (struct ifaddr *) data;
159 ifr = (struct ifreq *) data;
160 error = 0;
161
162 switch (command) {
163 case SIOCSIFADDR:
164 ifp->if_flags |= IFF_UP;
165
166 switch (ifa->ifa_addr->sa_family) {
167 #ifdef INET
168 case AF_INET:
169 ifp->if_init(ifp->if_softc); /* before arpwhohas */
170 arp_ifinit(ifp, ifa);
171 break;
172 #endif /* INET */
173 #ifdef IPX
174 /*
175 * XXX - This code is probably wrong
176 */
177 case AF_IPX: {
178 struct ipx_addr *ina;
179 struct arpcom *ac;
180
181 ina = &(IA_SIPX(ifa)->sipx_addr);
182 ac = IFP2AC(ifp);
183
184 if (ipx_nullhost(*ina))
185 ina->x_host = *(union ipx_host *)
186 ac->ac_enaddr;
187 else
188 bcopy((caddr_t) ina->x_host.c_host,
189 (caddr_t) ac->ac_enaddr,
190 ISO88025_ADDR_LEN);
191
192 /*
193 * Set new address
194 */
195 ifp->if_init(ifp->if_softc);
196 }
197 break;
198 #endif /* IPX */
199 default:
200 ifp->if_init(ifp->if_softc);
201 break;
202 }
203 break;
204
205 case SIOCGIFADDR: {
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 = NULL;
249
250 #ifdef MAC
251 error = mac_check_ifnet_transmit(ifp, m);
252 if (error)
253 senderr(error);
254 #endif
255
256 if (ifp->if_flags & IFF_MONITOR)
257 senderr(ENETDOWN);
258 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
259 senderr(ENETDOWN);
260 getmicrotime(&ifp->if_lastchange);
261
262 /* Calculate routing info length based on arp table entry */
263 /* XXX any better way to do this ? */
264 if (rt0 != NULL) {
265 error = rt_check(&rt, &rt0, dst);
266 if (error)
267 goto bad;
268 RT_UNLOCK(rt);
269 }
270
271 if (rt && (sdl = (struct sockaddr_dl *)rt->rt_gateway))
272 if (SDL_ISO88025(sdl)->trld_rcf != 0)
273 rif_len = TR_RCF_RIFLEN(SDL_ISO88025(sdl)->trld_rcf);
274
275 /* Generate a generic 802.5 header for the packet */
276 gen_th.ac = TR_AC;
277 gen_th.fc = TR_LLC_FRAME;
278 (void)memcpy((caddr_t)gen_th.iso88025_shost, IFP2AC(ifp)->ac_enaddr,
279 ISO88025_ADDR_LEN);
280 if (rif_len) {
281 gen_th.iso88025_shost[0] |= TR_RII;
282 if (rif_len > 2) {
283 gen_th.rcf = SDL_ISO88025(sdl)->trld_rcf;
284 (void)memcpy((caddr_t)gen_th.rd,
285 (caddr_t)SDL_ISO88025(sdl)->trld_route,
286 rif_len - 2);
287 }
288 }
289
290 switch (dst->sa_family) {
291 #ifdef INET
292 case AF_INET:
293 error = arpresolve(ifp, rt0, m, dst, edst);
294 if (error)
295 return (error == EWOULDBLOCK ? 0 : error);
296 snap_type = ETHERTYPE_IP;
297 break;
298 case AF_ARP:
299 {
300 struct arphdr *ah;
301 ah = mtod(m, struct arphdr *);
302 ah->ar_hrd = htons(ARPHRD_IEEE802);
303
304 loop_copy = -1; /* if this is for us, don't do it */
305
306 switch(ntohs(ah->ar_op)) {
307 case ARPOP_REVREQUEST:
308 case ARPOP_REVREPLY:
309 snap_type = ETHERTYPE_REVARP;
310 break;
311 case ARPOP_REQUEST:
312 case ARPOP_REPLY:
313 default:
314 snap_type = ETHERTYPE_ARP;
315 break;
316 }
317
318 if (m->m_flags & M_BCAST)
319 bcopy(ifp->if_broadcastaddr, edst, ISO88025_ADDR_LEN);
320 else
321 bcopy(ar_tha(ah), edst, ISO88025_ADDR_LEN);
322
323 }
324 break;
325 #endif /* INET */
326 #ifdef INET6
327 case AF_INET6:
328 error = nd6_storelladdr(ifp, rt0, m, dst, (u_char *)edst);
329 if (error)
330 return (error);
331 snap_type = ETHERTYPE_IPV6;
332 break;
333 #endif /* INET6 */
334 #ifdef IPX
335 case AF_IPX:
336 {
337 u_int8_t *cp;
338
339 bcopy((caddr_t)&(satoipx_addr(dst).x_host), (caddr_t)edst,
340 ISO88025_ADDR_LEN);
341
342 M_PREPEND(m, 3, M_TRYWAIT);
343 if (m == 0)
344 senderr(ENOBUFS);
345 m = m_pullup(m, 3);
346 if (m == 0)
347 senderr(ENOBUFS);
348 cp = mtod(m, u_int8_t *);
349 *cp++ = ETHERTYPE_IPX_8022;
350 *cp++ = ETHERTYPE_IPX_8022;
351 *cp++ = LLC_UI;
352 }
353 break;
354 #endif /* IPX */
355 case AF_UNSPEC:
356 {
357 struct iso88025_sockaddr_data *sd;
358 /*
359 * For AF_UNSPEC sockaddr.sa_data must contain all of the
360 * mac information needed to send the packet. This allows
361 * full mac, llc, and source routing function to be controlled.
362 * llc and source routing information must already be in the
363 * mbuf provided, ac/fc are set in sa_data. sockaddr.sa_data
364 * should be an iso88025_sockaddr_data structure see iso88025.h
365 */
366 loop_copy = -1;
367 sd = (struct iso88025_sockaddr_data *)dst->sa_data;
368 gen_th.ac = sd->ac;
369 gen_th.fc = sd->fc;
370 (void)memcpy((caddr_t)edst, (caddr_t)sd->ether_dhost,
371 ISO88025_ADDR_LEN);
372 (void)memcpy((caddr_t)gen_th.iso88025_shost,
373 (caddr_t)sd->ether_shost, ISO88025_ADDR_LEN);
374 rif_len = 0;
375 break;
376 }
377 default:
378 if_printf(ifp, "can't handle af%d\n", dst->sa_family);
379 senderr(EAFNOSUPPORT);
380 break;
381 }
382
383 /*
384 * Add LLC header.
385 */
386 if (snap_type != 0) {
387 struct llc *l;
388 M_PREPEND(m, LLC_SNAPFRAMELEN, M_DONTWAIT);
389 if (m == 0)
390 senderr(ENOBUFS);
391 l = mtod(m, struct llc *);
392 l->llc_control = LLC_UI;
393 l->llc_dsap = l->llc_ssap = LLC_SNAP_LSAP;
394 l->llc_snap.org_code[0] =
395 l->llc_snap.org_code[1] =
396 l->llc_snap.org_code[2] = 0;
397 l->llc_snap.ether_type = htons(snap_type);
398 }
399
400 /*
401 * Add local net header. If no space in first mbuf,
402 * allocate another.
403 */
404 M_PREPEND(m, ISO88025_HDR_LEN + rif_len, M_DONTWAIT);
405 if (m == 0)
406 senderr(ENOBUFS);
407 th = mtod(m, struct iso88025_header *);
408 bcopy((caddr_t)edst, (caddr_t)&gen_th.iso88025_dhost, ISO88025_ADDR_LEN);
409
410 /* Copy as much of the generic header as is needed into the mbuf */
411 memcpy(th, &gen_th, ISO88025_HDR_LEN + rif_len);
412
413 /*
414 * If a simplex interface, and the packet is being sent to our
415 * Ethernet address or a broadcast address, loopback a copy.
416 * XXX To make a simplex device behave exactly like a duplex
417 * device, we should copy in the case of sending to our own
418 * ethernet address (thus letting the original actually appear
419 * on the wire). However, we don't do that here for security
420 * reasons and compatibility with the original behavior.
421 */
422 if ((ifp->if_flags & IFF_SIMPLEX) && (loop_copy != -1)) {
423 if ((m->m_flags & M_BCAST) || (loop_copy > 0)) {
424 struct mbuf *n;
425 n = m_copy(m, 0, (int)M_COPYALL);
426 (void) if_simloop(ifp, n, dst->sa_family,
427 ISO88025_HDR_LEN);
428 } else if (bcmp(th->iso88025_dhost, th->iso88025_shost,
429 ETHER_ADDR_LEN) == 0) {
430 (void) if_simloop(ifp, m, dst->sa_family,
431 ISO88025_HDR_LEN);
432 return(0); /* XXX */
433 }
434 }
435
436 IFQ_HANDOFF_ADJ(ifp, m, ISO88025_HDR_LEN + LLC_SNAPFRAMELEN, error);
437 if (error) {
438 printf("iso88025_output: packet dropped QFULL.\n");
439 ifp->if_oerrors++;
440 }
441 return (error);
442
443 bad:
444 ifp->if_oerrors++;
445 if (m)
446 m_freem(m);
447 return (error);
448 }
449
450 /*
451 * ISO 88025 de-encapsulation
452 */
453 void
454 iso88025_input(ifp, m)
455 struct ifnet *ifp;
456 struct mbuf *m;
457 {
458 struct iso88025_header *th;
459 struct llc *l;
460 int isr;
461 int mac_hdr_len;
462
463 /*
464 * Do consistency checks to verify assumptions
465 * made by code past this point.
466 */
467 if ((m->m_flags & M_PKTHDR) == 0) {
468 if_printf(ifp, "discard frame w/o packet header\n");
469 ifp->if_ierrors++;
470 m_freem(m);
471 return;
472 }
473 if (m->m_pkthdr.rcvif == NULL) {
474 if_printf(ifp, "discard frame w/o interface pointer\n");
475 ifp->if_ierrors++;
476 m_freem(m);
477 return;
478 }
479
480 m = m_pullup(m, ISO88025_HDR_LEN);
481 if (m == NULL) {
482 ifp->if_ierrors++;
483 goto dropanyway;
484 }
485 th = mtod(m, struct iso88025_header *);
486 m->m_pkthdr.header = (void *)th;
487
488 /*
489 * Discard packet if interface is not up.
490 */
491 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
492 goto dropanyway;
493
494 /*
495 * Give bpf a chance at the packet.
496 */
497 BPF_MTAP(ifp, m);
498
499 /*
500 * Interface marked for monitoring; discard packet.
501 */
502 if (ifp->if_flags & IFF_MONITOR) {
503 m_freem(m);
504 return;
505 }
506
507 #ifdef MAC
508 mac_create_mbuf_from_ifnet(ifp, m);
509 #endif
510
511 /*
512 * Update interface statistics.
513 */
514 ifp->if_ibytes += m->m_pkthdr.len;
515 getmicrotime(&ifp->if_lastchange);
516
517 /*
518 * Discard non local unicast packets when interface
519 * is in promiscuous mode.
520 */
521 if ((ifp->if_flags & IFF_PROMISC) &&
522 ((th->iso88025_dhost[0] & 1) == 0) &&
523 (bcmp(IFP2AC(ifp)->ac_enaddr, (caddr_t) th->iso88025_dhost,
524 ISO88025_ADDR_LEN) != 0))
525 goto dropanyway;
526
527 /*
528 * Set mbuf flags for bcast/mcast.
529 */
530 if (th->iso88025_dhost[0] & 1) {
531 if (bcmp(iso88025_broadcastaddr, th->iso88025_dhost,
532 ISO88025_ADDR_LEN) == 0)
533 m->m_flags |= M_BCAST;
534 else
535 m->m_flags |= M_MCAST;
536 ifp->if_imcasts++;
537 }
538
539 mac_hdr_len = ISO88025_HDR_LEN;
540 /* Check for source routing info */
541 if (th->iso88025_shost[0] & TR_RII)
542 mac_hdr_len += TR_RCF_RIFLEN(th->rcf);
543
544 /* Strip off ISO88025 header. */
545 m_adj(m, mac_hdr_len);
546
547 m = m_pullup(m, LLC_SNAPFRAMELEN);
548 if (m == 0) {
549 ifp->if_ierrors++;
550 goto dropanyway;
551 }
552 l = mtod(m, struct llc *);
553
554 switch (l->llc_dsap) {
555 #ifdef IPX
556 case ETHERTYPE_IPX_8022: /* Thanks a bunch Novell */
557 if ((l->llc_control != LLC_UI) ||
558 (l->llc_ssap != ETHERTYPE_IPX_8022)) {
559 ifp->if_noproto++;
560 goto dropanyway;
561 }
562
563 th->iso88025_shost[0] &= ~(TR_RII);
564 m_adj(m, 3);
565 isr = NETISR_IPX;
566 break;
567 #endif /* IPX */
568 case LLC_SNAP_LSAP: {
569 u_int16_t type;
570 if ((l->llc_control != LLC_UI) ||
571 (l->llc_ssap != LLC_SNAP_LSAP)) {
572 ifp->if_noproto++;
573 goto dropanyway;
574 }
575
576 if (l->llc_snap.org_code[0] != 0 ||
577 l->llc_snap.org_code[1] != 0 ||
578 l->llc_snap.org_code[2] != 0) {
579 ifp->if_noproto++;
580 goto dropanyway;
581 }
582
583 type = ntohs(l->llc_snap.ether_type);
584 m_adj(m, LLC_SNAPFRAMELEN);
585 switch (type) {
586 #ifdef INET
587 case ETHERTYPE_IP:
588 th->iso88025_shost[0] &= ~(TR_RII);
589 if (ip_fastforward(m))
590 return;
591 isr = NETISR_IP;
592 break;
593
594 case ETHERTYPE_ARP:
595 if (ifp->if_flags & IFF_NOARP)
596 goto dropanyway;
597 isr = NETISR_ARP;
598 break;
599 #endif /* INET */
600 #ifdef IPX_SNAP /* XXX: Not supported! */
601 case ETHERTYPE_IPX:
602 th->iso88025_shost[0] &= ~(TR_RII);
603 isr = NETISR_IPX;
604 break;
605 #endif /* IPX_SNAP */
606 #ifdef INET6
607 case ETHERTYPE_IPV6:
608 th->iso88025_shost[0] &= ~(TR_RII);
609 isr = NETISR_IPV6;
610 break;
611 #endif /* INET6 */
612 default:
613 printf("iso88025_input: unexpected llc_snap ether_type 0x%02x\n", type);
614 ifp->if_noproto++;
615 goto dropanyway;
616 }
617 break;
618 }
619 #ifdef ISO
620 case LLC_ISO_LSAP:
621 switch (l->llc_control) {
622 case LLC_UI:
623 ifp->if_noproto++;
624 goto dropanyway;
625 break;
626 case LLC_XID:
627 case LLC_XID_P:
628 if(m->m_len < ISO88025_ADDR_LEN)
629 goto dropanyway;
630 l->llc_window = 0;
631 l->llc_fid = 9;
632 l->llc_class = 1;
633 l->llc_dsap = l->llc_ssap = 0;
634 /* Fall through to */
635 case LLC_TEST:
636 case LLC_TEST_P:
637 {
638 struct sockaddr sa;
639 struct arpcom *ac;
640 struct iso88025_sockaddr_data *th2;
641 int i;
642 u_char c;
643
644 ac = IFP2AC(ifp);
645 c = l->llc_dsap;
646
647 if (th->iso88025_shost[0] & TR_RII) { /* XXX */
648 printf("iso88025_input: dropping source routed LLC_TEST\n");
649 goto dropanyway;
650 }
651 l->llc_dsap = l->llc_ssap;
652 l->llc_ssap = c;
653 if (m->m_flags & (M_BCAST | M_MCAST))
654 bcopy((caddr_t)ac->ac_enaddr,
655 (caddr_t)th->iso88025_dhost,
656 ISO88025_ADDR_LEN);
657 sa.sa_family = AF_UNSPEC;
658 sa.sa_len = sizeof(sa);
659 th2 = (struct iso88025_sockaddr_data *)sa.sa_data;
660 for (i = 0; i < ISO88025_ADDR_LEN; i++) {
661 th2->ether_shost[i] = c = th->iso88025_dhost[i];
662 th2->ether_dhost[i] = th->iso88025_dhost[i] =
663 th->iso88025_shost[i];
664 th->iso88025_shost[i] = c;
665 }
666 th2->ac = TR_AC;
667 th2->fc = TR_LLC_FRAME;
668 ifp->if_output(ifp, m, &sa, NULL);
669 return;
670 }
671 default:
672 printf("iso88025_input: unexpected llc control 0x%02x\n", l->llc_control);
673 ifp->if_noproto++;
674 goto dropanyway;
675 break;
676 }
677 break;
678 #endif /* ISO */
679 default:
680 printf("iso88025_input: unknown dsap 0x%x\n", l->llc_dsap);
681 ifp->if_noproto++;
682 goto dropanyway;
683 break;
684 }
685
686 netisr_dispatch(isr, m);
687 return;
688
689 dropanyway:
690 ifp->if_iqdrops++;
691 if (m)
692 m_freem(m);
693 return;
694 }
695
696 static int
697 iso88025_resolvemulti (ifp, llsa, sa)
698 struct ifnet *ifp;
699 struct sockaddr **llsa;
700 struct sockaddr *sa;
701 {
702 struct sockaddr_dl *sdl;
703 struct sockaddr_in *sin;
704 #ifdef INET6
705 struct sockaddr_in6 *sin6;
706 #endif
707 u_char *e_addr;
708
709 switch(sa->sa_family) {
710 case AF_LINK:
711 /*
712 * No mapping needed. Just check that it's a valid MC address.
713 */
714 sdl = (struct sockaddr_dl *)sa;
715 e_addr = LLADDR(sdl);
716 if ((e_addr[0] & 1) != 1) {
717 return (EADDRNOTAVAIL);
718 }
719 *llsa = 0;
720 return (0);
721
722 #ifdef INET
723 case AF_INET:
724 sin = (struct sockaddr_in *)sa;
725 if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) {
726 return (EADDRNOTAVAIL);
727 }
728 MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR,
729 M_NOWAIT|M_ZERO);
730 if (sdl == NULL)
731 return (ENOMEM);
732 sdl->sdl_len = sizeof *sdl;
733 sdl->sdl_family = AF_LINK;
734 sdl->sdl_index = ifp->if_index;
735 sdl->sdl_type = IFT_ISO88025;
736 sdl->sdl_alen = ISO88025_ADDR_LEN;
737 e_addr = LLADDR(sdl);
738 ETHER_MAP_IP_MULTICAST(&sin->sin_addr, e_addr);
739 *llsa = (struct sockaddr *)sdl;
740 return (0);
741 #endif
742 #ifdef INET6
743 case AF_INET6:
744 sin6 = (struct sockaddr_in6 *)sa;
745 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
746 /*
747 * An IP6 address of 0 means listen to all
748 * of the Ethernet multicast address used for IP6.
749 * (This is used for multicast routers.)
750 */
751 ifp->if_flags |= IFF_ALLMULTI;
752 *llsa = 0;
753 return (0);
754 }
755 if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
756 return (EADDRNOTAVAIL);
757 }
758 MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR,
759 M_NOWAIT|M_ZERO);
760 if (sdl == NULL)
761 return (ENOMEM);
762 sdl->sdl_len = sizeof *sdl;
763 sdl->sdl_family = AF_LINK;
764 sdl->sdl_index = ifp->if_index;
765 sdl->sdl_type = IFT_ISO88025;
766 sdl->sdl_alen = ISO88025_ADDR_LEN;
767 e_addr = LLADDR(sdl);
768 ETHER_MAP_IPV6_MULTICAST(&sin6->sin6_addr, e_addr);
769 *llsa = (struct sockaddr *)sdl;
770 return (0);
771 #endif
772
773 default:
774 /*
775 * Well, the text isn't quite right, but it's the name
776 * that counts...
777 */
778 return (EAFNOSUPPORT);
779 }
780
781 return (0);
782 }
783
784 static moduledata_t iso88025_mod = {
785 "iso88025",
786 NULL,
787 0
788 };
789
790 DECLARE_MODULE(iso88025, iso88025_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
791 MODULE_VERSION(iso88025, 1);
Cache object: 6e92a56924d6f1472a3863f7904c028d
|