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