]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - sys/net/if_iso88025subr.c
MFC r368207,368607:
[FreeBSD/stable/10.git] / sys / net / if_iso88025subr.c
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
47 #include <sys/param.h>
48 #include <sys/systm.h>
49 #include <sys/kernel.h>
50 #include <sys/malloc.h>
51 #include <sys/mbuf.h>
52 #include <sys/module.h>
53 #include <sys/socket.h>
54 #include <sys/sockio.h> 
55
56 #include <net/if.h>
57 #include <net/if_arp.h>
58 #include <net/if_dl.h>
59 #include <net/if_llc.h>
60 #include <net/if_types.h>
61 #include <net/if_llatbl.h>
62
63 #include <net/ethernet.h>
64 #include <net/netisr.h>
65 #include <net/route.h>
66 #include <net/bpf.h>
67 #include <net/iso88025.h>
68
69 #if defined(INET) || defined(INET6)
70 #include <netinet/in.h>
71 #include <netinet/in_var.h>
72 #include <netinet/if_ether.h>
73 #endif
74 #ifdef INET6
75 #include <netinet6/nd6.h>
76 #endif
77
78 #ifdef IPX
79 #include <netipx/ipx.h>
80 #include <netipx/ipx_if.h>
81 #endif
82
83 #include <security/mac/mac_framework.h>
84
85 static const u_char iso88025_broadcastaddr[ISO88025_ADDR_LEN] =
86                         { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
87
88 static int iso88025_resolvemulti (struct ifnet *, struct sockaddr **,
89                                   struct sockaddr *);
90
91 #define senderr(e)      do { error = (e); goto bad; } while (0)
92
93 /*
94  * Perform common duties while attaching to interface list
95  */
96 void
97 iso88025_ifattach(struct ifnet *ifp, const u_int8_t *lla, int bpf)
98 {
99     struct ifaddr *ifa;
100     struct sockaddr_dl *sdl;
101
102     ifa = NULL;
103
104     ifp->if_type = IFT_ISO88025;
105     ifp->if_addrlen = ISO88025_ADDR_LEN;
106     ifp->if_hdrlen = ISO88025_HDR_LEN;
107
108     if_attach(ifp);     /* Must be called before additional assignments */
109
110     ifp->if_output = iso88025_output;
111     ifp->if_input = iso88025_input;
112     ifp->if_resolvemulti = iso88025_resolvemulti;
113     ifp->if_broadcastaddr = iso88025_broadcastaddr;
114
115     if (ifp->if_baudrate == 0)
116         ifp->if_baudrate = TR_16MBPS; /* 16Mbit should be a safe default */
117     if (ifp->if_mtu == 0)
118         ifp->if_mtu = ISO88025_DEFAULT_MTU;
119
120     ifa = ifp->if_addr;
121     KASSERT(ifa != NULL, ("%s: no lladdr!\n", __func__));
122
123     sdl = (struct sockaddr_dl *)ifa->ifa_addr;
124     sdl->sdl_type = IFT_ISO88025;
125     sdl->sdl_alen = ifp->if_addrlen;
126     bcopy(lla, 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, u_long 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
180                                 ina = &(IA_SIPX(ifa)->sipx_addr);
181
182                                 if (ipx_nullhost(*ina))
183                                         ina->x_host = *(union ipx_host *)
184                                                         IF_LLADDR(ifp);
185                                 else
186                                         bcopy((caddr_t) ina->x_host.c_host,
187                                               (caddr_t) IF_LLADDR(ifp),
188                                               ISO88025_ADDR_LEN);
189
190                                 /*
191                                  * Set new address
192                                  */
193                                 ifp->if_init(ifp->if_softc);
194                         }
195                         break;
196 #endif  /* IPX */
197                 default:
198                         ifp->if_init(ifp->if_softc);
199                         break;
200                 }
201                 break;
202
203         case SIOCGIFADDR:
204                 bcopy(IF_LLADDR(ifp), &ifr->ifr_addr.sa_data[0],
205                     ISO88025_ADDR_LEN);
206                 break;
207
208         case SIOCSIFMTU:
209                 /*
210                  * Set the interface MTU.
211                  */
212                 if (ifr->ifr_mtu > ISO88025_MAX_MTU) {
213                         error = EINVAL;
214                 } else {
215                         ifp->if_mtu = ifr->ifr_mtu;
216                 }
217                 break;
218         default:
219                 error = EINVAL;                 /* XXX netbsd has ENOTTY??? */
220                 break;
221         }
222
223         return (error);
224 }
225
226 /*
227  * ISO88025 encapsulation
228  */
229 int
230 iso88025_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
231         struct route *ro)
232 {
233         u_int16_t snap_type = 0;
234         int loop_copy = 0, error = 0, rif_len = 0;
235         u_char edst[ISO88025_ADDR_LEN];
236         struct iso88025_header *th;
237         struct iso88025_header gen_th;
238         struct sockaddr_dl *sdl = NULL;
239         struct rtentry *rt0 = NULL;
240 #if defined(INET) || defined(INET6)
241         struct llentry *lle;
242 #endif
243
244         if (ro != NULL)
245                 rt0 = ro->ro_rt;
246
247 #ifdef MAC
248         error = mac_ifnet_check_transmit(ifp, m);
249         if (error)
250                 senderr(error);
251 #endif
252
253         if (ifp->if_flags & IFF_MONITOR)
254                 senderr(ENETDOWN);
255         if (!((ifp->if_flags & IFF_UP) &&
256             (ifp->if_drv_flags & IFF_DRV_RUNNING)))
257                 senderr(ENETDOWN);
258         getmicrotime(&ifp->if_lastchange);
259
260         /* Calculate routing info length based on arp table entry */
261         /* XXX any better way to do this ? */
262
263         if (rt0 && (sdl = (struct sockaddr_dl *)rt0->rt_gateway))
264                 if (SDL_ISO88025(sdl)->trld_rcf != 0)
265                         rif_len = TR_RCF_RIFLEN(SDL_ISO88025(sdl)->trld_rcf);
266
267         /* Generate a generic 802.5 header for the packet */
268         gen_th.ac = TR_AC;
269         gen_th.fc = TR_LLC_FRAME;
270         (void)memcpy((caddr_t)gen_th.iso88025_shost, IF_LLADDR(ifp),
271                      ISO88025_ADDR_LEN);
272         if (rif_len) {
273                 gen_th.iso88025_shost[0] |= TR_RII;
274                 if (rif_len > 2) {
275                         gen_th.rcf = SDL_ISO88025(sdl)->trld_rcf;
276                         (void)memcpy((caddr_t)gen_th.rd,
277                                 (caddr_t)SDL_ISO88025(sdl)->trld_route,
278                                 rif_len - 2);
279                 }
280         }
281         
282         switch (dst->sa_family) {
283 #ifdef INET
284         case AF_INET:
285                 error = arpresolve(ifp, rt0, m, dst, edst, &lle);
286                 if (error)
287                         return (error == EWOULDBLOCK ? 0 : error);
288                 snap_type = ETHERTYPE_IP;
289                 break;
290         case AF_ARP:
291         {
292                 struct arphdr *ah;
293                 ah = mtod(m, struct arphdr *);
294                 ah->ar_hrd = htons(ARPHRD_IEEE802);
295
296                 loop_copy = -1; /* if this is for us, don't do it */
297
298                 switch(ntohs(ah->ar_op)) {
299                 case ARPOP_REVREQUEST:
300                 case ARPOP_REVREPLY:
301                         snap_type = ETHERTYPE_REVARP;
302                         break;
303                 case ARPOP_REQUEST:
304                 case ARPOP_REPLY:
305                 default:
306                         snap_type = ETHERTYPE_ARP;
307                         break;
308                 }
309
310                 if (m->m_flags & M_BCAST)
311                         bcopy(ifp->if_broadcastaddr, edst, ISO88025_ADDR_LEN);
312                 else
313                         bcopy(ar_tha(ah), edst, ISO88025_ADDR_LEN);
314
315         }
316         break;
317 #endif  /* INET */
318 #ifdef INET6
319         case AF_INET6:
320                 error = nd6_storelladdr(ifp, m, dst, (u_char *)edst, &lle);
321                 if (error)
322                         return (error);
323                 snap_type = ETHERTYPE_IPV6;
324                 break;
325 #endif  /* INET6 */
326 #ifdef IPX
327         case AF_IPX:
328         {
329                 u_int8_t        *cp;
330
331                 bcopy((caddr_t)&(satoipx_addr(dst).x_host), (caddr_t)edst,
332                       ISO88025_ADDR_LEN);
333
334                 M_PREPEND(m, 3, M_WAITOK);
335                 m = m_pullup(m, 3);
336                 if (m == 0)
337                         senderr(ENOBUFS);
338                 cp = mtod(m, u_int8_t *);
339                 *cp++ = ETHERTYPE_IPX_8022;
340                 *cp++ = ETHERTYPE_IPX_8022;
341                 *cp++ = LLC_UI;
342         }
343         break;
344 #endif  /* IPX */
345         case AF_UNSPEC:
346         {
347                 const struct iso88025_sockaddr_data *sd;
348                 /*
349                  * For AF_UNSPEC sockaddr.sa_data must contain all of the
350                  * mac information needed to send the packet.  This allows
351                  * full mac, llc, and source routing function to be controlled.
352                  * llc and source routing information must already be in the
353                  * mbuf provided, ac/fc are set in sa_data.  sockaddr.sa_data
354                  * should be an iso88025_sockaddr_data structure see iso88025.h
355                  */
356                 loop_copy = -1;
357                 sd = (const struct iso88025_sockaddr_data *)dst->sa_data;
358                 gen_th.ac = sd->ac;
359                 gen_th.fc = sd->fc;
360                 (void)memcpy(edst, sd->ether_dhost, ISO88025_ADDR_LEN);
361                 (void)memcpy(gen_th.iso88025_shost, sd->ether_shost,
362                     ISO88025_ADDR_LEN);
363                 rif_len = 0;
364                 break;
365         }
366         default:
367                 if_printf(ifp, "can't handle af%d\n", dst->sa_family);
368                 senderr(EAFNOSUPPORT);
369                 break;
370         }
371
372         /*
373          * Add LLC header.
374          */
375         if (snap_type != 0) {
376                 struct llc *l;
377                 M_PREPEND(m, LLC_SNAPFRAMELEN, M_NOWAIT);
378                 if (m == 0)
379                         senderr(ENOBUFS);
380                 l = mtod(m, struct llc *);
381                 l->llc_control = LLC_UI;
382                 l->llc_dsap = l->llc_ssap = LLC_SNAP_LSAP;
383                 l->llc_snap.org_code[0] =
384                         l->llc_snap.org_code[1] =
385                         l->llc_snap.org_code[2] = 0;
386                 l->llc_snap.ether_type = htons(snap_type);
387         }
388
389         /*
390          * Add local net header.  If no space in first mbuf,
391          * allocate another.
392          */
393         M_PREPEND(m, ISO88025_HDR_LEN + rif_len, M_NOWAIT);
394         if (m == 0)
395                 senderr(ENOBUFS);
396         th = mtod(m, struct iso88025_header *);
397         bcopy((caddr_t)edst, (caddr_t)&gen_th.iso88025_dhost, ISO88025_ADDR_LEN);
398
399         /* Copy as much of the generic header as is needed into the mbuf */
400         memcpy(th, &gen_th, ISO88025_HDR_LEN + rif_len);
401
402         /*
403          * If a simplex interface, and the packet is being sent to our
404          * Ethernet address or a broadcast address, loopback a copy.
405          * XXX To make a simplex device behave exactly like a duplex
406          * device, we should copy in the case of sending to our own
407          * ethernet address (thus letting the original actually appear
408          * on the wire). However, we don't do that here for security
409          * reasons and compatibility with the original behavior.
410          */     
411         if ((ifp->if_flags & IFF_SIMPLEX) && (loop_copy != -1)) {
412                 if ((m->m_flags & M_BCAST) || (loop_copy > 0)) { 
413                         struct mbuf *n;
414                         n = m_copy(m, 0, (int)M_COPYALL);
415                         (void) if_simloop(ifp, n, dst->sa_family,
416                                           ISO88025_HDR_LEN);
417                 } else if (bcmp(th->iso88025_dhost, th->iso88025_shost,
418                                  ETHER_ADDR_LEN) == 0) {
419                         (void) if_simloop(ifp, m, dst->sa_family,
420                                           ISO88025_HDR_LEN);
421                         return(0);      /* XXX */
422                 }       
423         }      
424
425         IFQ_HANDOFF_ADJ(ifp, m, ISO88025_HDR_LEN + LLC_SNAPFRAMELEN, error);
426         if (error) {
427                 printf("iso88025_output: packet dropped QFULL.\n");
428                 ifp->if_oerrors++;
429         }
430         return (error);
431
432 bad:
433         ifp->if_oerrors++;
434         if (m)
435                 m_freem(m);
436         return (error);
437 }
438
439 /*
440  * ISO 88025 de-encapsulation
441  */
442 void
443 iso88025_input(ifp, m)
444         struct ifnet *ifp;
445         struct mbuf *m;
446 {
447         struct iso88025_header *th;
448         struct llc *l;
449         int isr;
450         int mac_hdr_len;
451
452         /*
453          * Do consistency checks to verify assumptions
454          * made by code past this point.
455          */
456         if ((m->m_flags & M_PKTHDR) == 0) {
457                 if_printf(ifp, "discard frame w/o packet header\n");
458                 ifp->if_ierrors++;
459                 m_freem(m);
460                 return;
461         }
462         if (m->m_pkthdr.rcvif == NULL) {
463                 if_printf(ifp, "discard frame w/o interface pointer\n");
464                 ifp->if_ierrors++;
465                 m_freem(m);
466                 return;
467         }
468
469         m = m_pullup(m, ISO88025_HDR_LEN);
470         if (m == NULL) {
471                 ifp->if_ierrors++;
472                 goto dropanyway;
473         }
474         th = mtod(m, struct iso88025_header *);
475
476         /*
477          * Discard packet if interface is not up.
478          */
479         if (!((ifp->if_flags & IFF_UP) &&
480             (ifp->if_drv_flags & IFF_DRV_RUNNING)))
481                 goto dropanyway;
482
483         /*
484          * Give bpf a chance at the packet.
485          */
486         BPF_MTAP(ifp, m);
487
488         /*
489          * Interface marked for monitoring; discard packet.
490          */
491         if (ifp->if_flags & IFF_MONITOR) {
492                 m_freem(m);
493                 return;
494         }
495
496 #ifdef MAC
497         mac_ifnet_create_mbuf(ifp, m);
498 #endif
499
500         /*
501          * Update interface statistics.
502          */
503         ifp->if_ibytes += m->m_pkthdr.len;
504         getmicrotime(&ifp->if_lastchange);
505
506         /*
507          * Discard non local unicast packets when interface
508          * is in promiscuous mode.
509          */
510         if ((ifp->if_flags & IFF_PROMISC) &&
511             ((th->iso88025_dhost[0] & 1) == 0) &&
512              (bcmp(IF_LLADDR(ifp), (caddr_t) th->iso88025_dhost,
513              ISO88025_ADDR_LEN) != 0))
514                 goto dropanyway;
515
516         /*
517          * Set mbuf flags for bcast/mcast.
518          */
519         if (th->iso88025_dhost[0] & 1) {
520                 if (bcmp(iso88025_broadcastaddr, th->iso88025_dhost,
521                     ISO88025_ADDR_LEN) == 0)
522                         m->m_flags |= M_BCAST;
523                 else
524                         m->m_flags |= M_MCAST;
525                 ifp->if_imcasts++;
526         }
527
528         mac_hdr_len = ISO88025_HDR_LEN;
529         /* Check for source routing info */
530         if (th->iso88025_shost[0] & TR_RII)
531                 mac_hdr_len += TR_RCF_RIFLEN(th->rcf);
532
533         /* Strip off ISO88025 header. */
534         m_adj(m, mac_hdr_len);
535
536         m = m_pullup(m, LLC_SNAPFRAMELEN);
537         if (m == 0) {
538                 ifp->if_ierrors++;
539                 goto dropanyway;
540         }
541         l = mtod(m, struct llc *);
542
543         switch (l->llc_dsap) {
544 #ifdef IPX
545         case ETHERTYPE_IPX_8022:        /* Thanks a bunch Novell */
546                 if ((l->llc_control != LLC_UI) ||
547                     (l->llc_ssap != ETHERTYPE_IPX_8022)) {
548                         ifp->if_noproto++;
549                         goto dropanyway;
550                 }
551
552                 th->iso88025_shost[0] &= ~(TR_RII); 
553                 m_adj(m, 3);
554                 isr = NETISR_IPX;
555                 break;
556 #endif  /* IPX */
557         case LLC_SNAP_LSAP: {
558                 u_int16_t type;
559                 if ((l->llc_control != LLC_UI) ||
560                     (l->llc_ssap != LLC_SNAP_LSAP)) {
561                         ifp->if_noproto++;
562                         goto dropanyway;
563                 }
564
565                 if (l->llc_snap.org_code[0] != 0 ||
566                     l->llc_snap.org_code[1] != 0 ||
567                     l->llc_snap.org_code[2] != 0) {
568                         ifp->if_noproto++;
569                         goto dropanyway;
570                 }
571
572                 type = ntohs(l->llc_snap.ether_type);
573                 m_adj(m, LLC_SNAPFRAMELEN);
574                 switch (type) {
575 #ifdef INET
576                 case ETHERTYPE_IP:
577                         th->iso88025_shost[0] &= ~(TR_RII); 
578                         if ((m = ip_fastforward(m)) == NULL)
579                                 return;
580                         isr = NETISR_IP;
581                         break;
582
583                 case ETHERTYPE_ARP:
584                         if (ifp->if_flags & IFF_NOARP)
585                                 goto dropanyway;
586                         isr = NETISR_ARP;
587                         break;
588 #endif  /* INET */
589 #ifdef IPX_SNAP /* XXX: Not supported! */
590                 case ETHERTYPE_IPX:
591                         th->iso88025_shost[0] &= ~(TR_RII); 
592                         isr = NETISR_IPX;
593                         break;
594 #endif  /* IPX_SNAP */
595 #ifdef INET6
596                 case ETHERTYPE_IPV6:
597                         th->iso88025_shost[0] &= ~(TR_RII); 
598                         isr = NETISR_IPV6;
599                         break;
600 #endif  /* INET6 */
601                 default:
602                         printf("iso88025_input: unexpected llc_snap ether_type  0x%02x\n", type);
603                         ifp->if_noproto++;
604                         goto dropanyway;
605                 }
606                 break;
607         }
608 #ifdef ISO
609         case LLC_ISO_LSAP:
610                 switch (l->llc_control) {
611                 case LLC_UI:
612                         ifp->if_noproto++;
613                         goto dropanyway;
614                         break;
615                 case LLC_XID:
616                 case LLC_XID_P:
617                         if(m->m_len < ISO88025_ADDR_LEN)
618                                 goto dropanyway;
619                         l->llc_window = 0;
620                         l->llc_fid = 9;  
621                         l->llc_class = 1;
622                         l->llc_dsap = l->llc_ssap = 0;
623                         /* Fall through to */  
624                 case LLC_TEST:
625                 case LLC_TEST_P:
626                 {
627                         struct sockaddr sa;
628                         struct arpcom *ac;
629                         struct iso88025_sockaddr_data *th2;
630                         int i;
631                         u_char c;
632
633                         c = l->llc_dsap;
634
635                         if (th->iso88025_shost[0] & TR_RII) { /* XXX */
636                                 printf("iso88025_input: dropping source routed LLC_TEST\n");
637                                 goto dropanyway;
638                         }
639                         l->llc_dsap = l->llc_ssap;
640                         l->llc_ssap = c;
641                         if (m->m_flags & (M_BCAST | M_MCAST))
642                                 bcopy((caddr_t)IF_LLADDR(ifp),
643                                       (caddr_t)th->iso88025_dhost,
644                                         ISO88025_ADDR_LEN);
645                         sa.sa_family = AF_UNSPEC;
646                         sa.sa_len = sizeof(sa);
647                         th2 = (struct iso88025_sockaddr_data *)sa.sa_data;
648                         for (i = 0; i < ISO88025_ADDR_LEN; i++) {
649                                 th2->ether_shost[i] = c = th->iso88025_dhost[i];
650                                 th2->ether_dhost[i] = th->iso88025_dhost[i] =
651                                         th->iso88025_shost[i];
652                                 th->iso88025_shost[i] = c;
653                         }
654                         th2->ac = TR_AC;
655                         th2->fc = TR_LLC_FRAME;
656                         ifp->if_output(ifp, m, &sa, NULL);
657                         return;
658                 }
659                 default:
660                         printf("iso88025_input: unexpected llc control 0x%02x\n", l->llc_control);
661                         ifp->if_noproto++;
662                         goto dropanyway;
663                         break;
664                 }
665                 break;
666 #endif  /* ISO */
667         default:
668                 printf("iso88025_input: unknown dsap 0x%x\n", l->llc_dsap);
669                 ifp->if_noproto++;
670                 goto dropanyway;
671                 break;
672         }
673
674         M_SETFIB(m, ifp->if_fib);
675         netisr_dispatch(isr, m);
676         return;
677
678 dropanyway:
679         ifp->if_iqdrops++;
680         if (m)
681                 m_freem(m);
682         return;
683 }
684
685 static int
686 iso88025_resolvemulti (ifp, llsa, sa)
687         struct ifnet *ifp;
688         struct sockaddr **llsa;
689         struct sockaddr *sa;
690 {
691         struct sockaddr_dl *sdl;
692 #ifdef INET
693         struct sockaddr_in *sin;
694 #endif
695 #ifdef INET6
696         struct sockaddr_in6 *sin6;
697 #endif
698         u_char *e_addr;
699
700         switch(sa->sa_family) {
701         case AF_LINK:
702                 /*
703                  * No mapping needed. Just check that it's a valid MC address.
704                  */
705                 sdl = (struct sockaddr_dl *)sa;
706                 e_addr = LLADDR(sdl);
707                 if ((e_addr[0] & 1) != 1) {
708                         return (EADDRNOTAVAIL);
709                 }
710                 *llsa = 0;
711                 return (0);
712
713 #ifdef INET
714         case AF_INET:
715                 sin = (struct sockaddr_in *)sa;
716                 if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) {
717                         return (EADDRNOTAVAIL);
718                 }
719                 sdl = malloc(sizeof *sdl, M_IFMADDR,
720                        M_NOWAIT|M_ZERO);
721                 if (sdl == NULL)
722                         return (ENOMEM);
723                 sdl->sdl_len = sizeof *sdl;
724                 sdl->sdl_family = AF_LINK;
725                 sdl->sdl_index = ifp->if_index;
726                 sdl->sdl_type = IFT_ISO88025;
727                 sdl->sdl_alen = ISO88025_ADDR_LEN;
728                 e_addr = LLADDR(sdl);
729                 ETHER_MAP_IP_MULTICAST(&sin->sin_addr, e_addr);
730                 *llsa = (struct sockaddr *)sdl;
731                 return (0);
732 #endif
733 #ifdef INET6
734         case AF_INET6:
735                 sin6 = (struct sockaddr_in6 *)sa;
736                 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
737                         /*
738                          * An IP6 address of 0 means listen to all
739                          * of the Ethernet multicast address used for IP6.
740                          * (This is used for multicast routers.)
741                          */
742                         ifp->if_flags |= IFF_ALLMULTI;
743                         *llsa = 0;
744                         return (0);
745                 }
746                 if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
747                         return (EADDRNOTAVAIL);
748                 }
749                 sdl = malloc(sizeof *sdl, M_IFMADDR,
750                        M_NOWAIT|M_ZERO);
751                 if (sdl == NULL)
752                         return (ENOMEM);
753                 sdl->sdl_len = sizeof *sdl;
754                 sdl->sdl_family = AF_LINK;
755                 sdl->sdl_index = ifp->if_index;
756                 sdl->sdl_type = IFT_ISO88025;
757                 sdl->sdl_alen = ISO88025_ADDR_LEN;
758                 e_addr = LLADDR(sdl);
759                 ETHER_MAP_IPV6_MULTICAST(&sin6->sin6_addr, e_addr);
760                 *llsa = (struct sockaddr *)sdl;
761                 return (0);
762 #endif
763
764         default:
765                 /*
766                  * Well, the text isn't quite right, but it's the name
767                  * that counts...
768                  */
769                 return (EAFNOSUPPORT);
770         }
771
772         return (0);
773 }
774
775 static MALLOC_DEFINE(M_ISO88025, "arpcom", "802.5 interface internals");
776
777 static void*
778 iso88025_alloc(u_char type, struct ifnet *ifp)
779 {
780         struct arpcom   *ac;
781  
782         ac = malloc(sizeof(struct arpcom), M_ISO88025, M_WAITOK | M_ZERO);
783         ac->ac_ifp = ifp;
784
785         return (ac);
786
787
788 static void
789 iso88025_free(void *com, u_char type)
790 {
791  
792         free(com, M_ISO88025);
793 }
794  
795 static int
796 iso88025_modevent(module_t mod, int type, void *data)
797 {
798   
799         switch (type) {
800         case MOD_LOAD:
801                 if_register_com_alloc(IFT_ISO88025, iso88025_alloc,
802                     iso88025_free);
803                 break;
804         case MOD_UNLOAD:
805                 if_deregister_com_alloc(IFT_ISO88025);
806                 break;
807         default:
808                 return EOPNOTSUPP;
809         }
810
811         return (0);
812 }
813
814 static moduledata_t iso88025_mod = {
815         "iso88025",
816         iso88025_modevent,
817         0
818 };
819
820 DECLARE_MODULE(iso88025, iso88025_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
821 MODULE_VERSION(iso88025, 1);