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