if_fddisubr.c revision 93376
17055Sdg/* 221830Sjoerg * Copyright (c) 1995, 1996 321830Sjoerg * Matt Thomas <matt@3am-software.com>. All rights reserved. 47055Sdg * Copyright (c) 1982, 1989, 1993 57055Sdg * The Regents of the University of California. All rights reserved. 67055Sdg * 77055Sdg * Redistribution and use in source and binary forms, with or without 87055Sdg * modification, are permitted provided that the following conditions 97055Sdg * are met: 107055Sdg * 1. Redistributions of source code must retain the above copyright 117055Sdg * notice, this list of conditions and the following disclaimer. 127055Sdg * 2. Redistributions in binary form must reproduce the above copyright 137055Sdg * notice, this list of conditions and the following disclaimer in the 147055Sdg * documentation and/or other materials provided with the distribution. 157055Sdg * 3. All advertising materials mentioning features or use of this software 167055Sdg * must display the following acknowledgement: 177055Sdg * This product includes software developed by the University of 187055Sdg * California, Berkeley and its contributors. 197055Sdg * 4. Neither the name of the University nor the names of its contributors 207055Sdg * may be used to endorse or promote products derived from this software 217055Sdg * without specific prior written permission. 227055Sdg * 237055Sdg * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 247055Sdg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 257055Sdg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 267055Sdg * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 277055Sdg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 287055Sdg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 297055Sdg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 307055Sdg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 317055Sdg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 327055Sdg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 337055Sdg * SUCH DAMAGE. 347055Sdg * 357061Sdg * from: if_ethersubr.c,v 1.5 1994/12/13 22:31:45 wollman Exp 3650477Speter * $FreeBSD: head/sys/net/if_fddisubr.c 93376 2002-03-29 09:41:03Z mdodd $ 377055Sdg */ 387055Sdg 3932356Seivind#include "opt_atalk.h" 4032350Seivind#include "opt_inet.h" 4154263Sshin#include "opt_inet6.h" 4231742Seivind#include "opt_ipx.h" 4331742Seivind 447055Sdg#include <sys/param.h> 457055Sdg#include <sys/systm.h> 4693375Smdodd#include <sys/kernel.h> 4793375Smdodd#include <sys/malloc.h> 487055Sdg#include <sys/mbuf.h> 4993375Smdodd#include <sys/module.h> 507055Sdg#include <sys/socket.h> 5193375Smdodd#include <sys/sockio.h> 527055Sdg 537055Sdg#include <net/if.h> 547055Sdg#include <net/if_llc.h> 557055Sdg#include <net/if_dl.h> 567055Sdg#include <net/if_types.h> 5793375Smdodd#include <net/netisr.h> 5893375Smdodd#include <net/route.h> 5993375Smdodd#include <net/bpf.h> 6093373Smdodd#include <net/fddi.h> 617055Sdg 6254263Sshin#if defined(INET) || defined(INET6) 637055Sdg#include <netinet/in.h> 647055Sdg#include <netinet/in_var.h> 6532350Seivind#include <netinet/if_ether.h> 667055Sdg#endif 6754263Sshin#ifdef INET6 6854263Sshin#include <netinet6/nd6.h> 6954263Sshin#endif 707055Sdg 7111819Sjulian#ifdef IPX 7221830Sjoerg#include <netipx/ipx.h> 7311819Sjulian#include <netipx/ipx_if.h> 7411819Sjulian#endif 7511819Sjulian 767055Sdg#ifdef NS 777055Sdg#include <netns/ns.h> 787055Sdg#include <netns/ns_if.h> 797055Sdg#endif 807055Sdg 817055Sdg#ifdef DECNET 827055Sdg#include <netdnet/dn.h> 837055Sdg#endif 847055Sdg 8521830Sjoerg#ifdef NETATALK 8621830Sjoerg#include <netatalk/at.h> 8721830Sjoerg#include <netatalk/at_var.h> 8821830Sjoerg#include <netatalk/at_extern.h> 8921830Sjoerg 9021830Sjoergextern u_char at_org_code[ 3 ]; 9121830Sjoergextern u_char aarp_org_code[ 3 ]; 9221830Sjoerg#endif /* NETATALK */ 9321830Sjoerg 9492725Salfredstatic int fddi_resolvemulti(struct ifnet *, struct sockaddr **, 9593084Sbde struct sockaddr *); 9668180Sume 9793369Smdodd#define IFP2AC(IFP) ((struct arpcom *)IFP) 9893369Smdodd#define senderr(e) { error = (e); goto bad; } 9993369Smdodd 1007055Sdg/* 1017055Sdg * FDDI output routine. 1027055Sdg * Encapsulate a packet of type family for the local net. 1037055Sdg * Use trailer local net encapsulation if enough data in first 1047055Sdg * packet leaves a multiple of 512 bytes of data in remainder. 1057055Sdg * Assumes that ifp is actually pointer to arpcom structure. 1067055Sdg */ 1077055Sdgint 10854799Sgreenfddi_output(ifp, m, dst, rt0) 10993367Smdodd struct ifnet *ifp; 11054799Sgreen struct mbuf *m; 1117055Sdg struct sockaddr *dst; 1127055Sdg struct rtentry *rt0; 1137055Sdg{ 11421830Sjoerg u_int16_t type; 11569152Sjlemon int loop_copy = 0, error = 0, hdrcmplt = 0; 11693373Smdodd u_char esrc[FDDI_ADDR_LEN], edst[FDDI_ADDR_LEN]; 11793367Smdodd struct rtentry *rt; 11893367Smdodd struct fddi_header *fh; 11993369Smdodd struct arpcom *ac = IFP2AC(ifp); 1207055Sdg 1217055Sdg if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) 1227055Sdg senderr(ENETDOWN); 12334961Sphk getmicrotime(&ifp->if_lastchange); 12443305Sdillon if ((rt = rt0) != NULL) { 1257055Sdg if ((rt->rt_flags & RTF_UP) == 0) { 12693369Smdodd if ((rt0 = rt = rtalloc1(dst, 1, 0UL)) != NULL) 1277055Sdg rt->rt_refcnt--; 12821830Sjoerg else 1297055Sdg senderr(EHOSTUNREACH); 1307055Sdg } 1317055Sdg if (rt->rt_flags & RTF_GATEWAY) { 1327055Sdg if (rt->rt_gwroute == 0) 1337055Sdg goto lookup; 1347055Sdg if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) { 1357055Sdg rtfree(rt); rt = rt0; 13693369Smdodd lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1, 0UL); 1377055Sdg if ((rt = rt->rt_gwroute) == 0) 1387055Sdg senderr(EHOSTUNREACH); 1397055Sdg } 1407055Sdg } 1417055Sdg if (rt->rt_flags & RTF_REJECT) 1427055Sdg if (rt->rt_rmx.rmx_expire == 0 || 14334961Sphk time_second < rt->rt_rmx.rmx_expire) 1447055Sdg senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH); 1457055Sdg } 1467055Sdg switch (dst->sa_family) { 1477055Sdg 1487055Sdg#ifdef INET 14921830Sjoerg case AF_INET: { 15093369Smdodd if (!arpresolve(ifp, rt, m, dst, edst, rt0)) 1517055Sdg return (0); /* if not yet resolved */ 15221830Sjoerg type = htons(ETHERTYPE_IP); 1537055Sdg break; 15421830Sjoerg } 1557055Sdg#endif 15654263Sshin#ifdef INET6 15754263Sshin case AF_INET6: 15893375Smdodd if (!nd6_storelladdr(ifp, rt, m, dst, (u_char *)edst)) { 15974093Sbmilekic /* Something bad happened */ 16093369Smdodd return (0); 16154263Sshin } 16254263Sshin type = htons(ETHERTYPE_IPV6); 16354263Sshin break; 16454263Sshin#endif 16511819Sjulian#ifdef IPX 16611819Sjulian case AF_IPX: 16721830Sjoerg type = htons(ETHERTYPE_IPX); 16811819Sjulian bcopy((caddr_t)&(((struct sockaddr_ipx *)dst)->sipx_addr.x_host), 16993373Smdodd (caddr_t)edst, FDDI_ADDR_LEN); 17011819Sjulian break; 17111819Sjulian#endif 17221830Sjoerg#ifdef NETATALK 17321830Sjoerg case AF_APPLETALK: { 17421830Sjoerg struct at_ifaddr *aa; 17536908Sjulian if (!aarpresolve(ac, m, (struct sockaddr_at *)dst, edst)) 17621830Sjoerg return (0); 17721830Sjoerg /* 17821830Sjoerg * ifaddr is the first thing in at_ifaddr 17921830Sjoerg */ 18030834Sjulian if ((aa = at_ifawithnet( (struct sockaddr_at *)dst)) == 0) 18121830Sjoerg goto bad; 18221830Sjoerg 18321830Sjoerg /* 18421830Sjoerg * In the phase 2 case, we need to prepend an mbuf for the llc header. 18521830Sjoerg * Since we must preserve the value of m, which is passed to us by 18621830Sjoerg * value, we m_copy() the first mbuf, and use it for our llc header. 18721830Sjoerg */ 18821830Sjoerg if (aa->aa_flags & AFA_PHASE2) { 18921830Sjoerg struct llc llc; 19021830Sjoerg 19193373Smdodd M_PREPEND(m, LLC_SNAPFRAMELEN, M_TRYWAIT); 19221830Sjoerg if (m == 0) 19321830Sjoerg senderr(ENOBUFS); 19421830Sjoerg llc.llc_dsap = llc.llc_ssap = LLC_SNAP_LSAP; 19521830Sjoerg llc.llc_control = LLC_UI; 19693371Smdodd bcopy(at_org_code, llc.llc_snap.org_code, sizeof(at_org_code)); 19793371Smdodd llc.llc_snap.ether_type = htons(ETHERTYPE_AT); 19893373Smdodd bcopy(&llc, mtod(m, caddr_t), LLC_SNAPFRAMELEN); 19921830Sjoerg type = 0; 20021830Sjoerg } else { 20121830Sjoerg type = htons(ETHERTYPE_AT); 20221830Sjoerg } 20321830Sjoerg break; 20421830Sjoerg } 20521830Sjoerg#endif /* NETATALK */ 2067055Sdg#ifdef NS 2077055Sdg case AF_NS: 20821830Sjoerg type = htons(ETHERTYPE_NS); 2097055Sdg bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host), 21093373Smdodd (caddr_t)edst, FDDI_ADDR_LEN); 2117055Sdg break; 2127055Sdg#endif 2137055Sdg 21452248Smsmith case pseudo_AF_HDRCMPLT: 21552248Smsmith { 21693376Smdodd struct ether_header *eh; 21752248Smsmith hdrcmplt = 1; 21893376Smdodd eh = (struct ether_header *)dst->sa_data; 21993376Smdodd bcopy((caddr_t)eh->ether_shost, (caddr_t)esrc, FDDI_ADDR_LEN); 22052248Smsmith /* FALLTHROUGH */ 22152248Smsmith } 22252248Smsmith 2237055Sdg case AF_UNSPEC: 2247055Sdg { 2257055Sdg struct ether_header *eh; 22636992Sjulian loop_copy = -1; 2277055Sdg eh = (struct ether_header *)dst->sa_data; 22893375Smdodd bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, FDDI_ADDR_LEN); 2297055Sdg if (*edst & 1) 2307055Sdg m->m_flags |= (M_BCAST|M_MCAST); 2317055Sdg type = eh->ether_type; 2327055Sdg break; 2337055Sdg } 2347055Sdg 2357055Sdg case AF_IMPLINK: 2367055Sdg { 2377055Sdg fh = mtod(m, struct fddi_header *); 2387055Sdg error = EPROTONOSUPPORT; 2397055Sdg switch (fh->fddi_fc & (FDDIFC_C|FDDIFC_L|FDDIFC_F)) { 2407055Sdg case FDDIFC_LLC_ASYNC: { 2417055Sdg /* legal priorities are 0 through 7 */ 2427055Sdg if ((fh->fddi_fc & FDDIFC_Z) > 7) 2437055Sdg goto bad; 2447055Sdg break; 2457055Sdg } 2467055Sdg case FDDIFC_LLC_SYNC: { 2477055Sdg /* FDDIFC_Z bits reserved, must be zero */ 2487055Sdg if (fh->fddi_fc & FDDIFC_Z) 2497055Sdg goto bad; 2507055Sdg break; 2517055Sdg } 2527055Sdg case FDDIFC_SMT: { 2537055Sdg /* FDDIFC_Z bits must be non zero */ 2547055Sdg if ((fh->fddi_fc & FDDIFC_Z) == 0) 2557055Sdg goto bad; 2567055Sdg break; 2577055Sdg } 2587055Sdg default: { 2597055Sdg /* anything else is too dangerous */ 2607055Sdg goto bad; 2617055Sdg } 2627055Sdg } 2637055Sdg error = 0; 2647055Sdg if (fh->fddi_dhost[0] & 1) 2657055Sdg m->m_flags |= (M_BCAST|M_MCAST); 2667055Sdg goto queue_it; 2677055Sdg } 2687055Sdg default: 2697055Sdg printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit, 2707055Sdg dst->sa_family); 2717055Sdg senderr(EAFNOSUPPORT); 2727055Sdg } 2737055Sdg 2747055Sdg if (type != 0) { 27593367Smdodd struct llc *l; 27693373Smdodd M_PREPEND(m, LLC_SNAPFRAMELEN, M_DONTWAIT); 2777055Sdg if (m == 0) 2787055Sdg senderr(ENOBUFS); 2797055Sdg l = mtod(m, struct llc *); 2807055Sdg l->llc_control = LLC_UI; 2817055Sdg l->llc_dsap = l->llc_ssap = LLC_SNAP_LSAP; 2827055Sdg l->llc_snap.org_code[0] = l->llc_snap.org_code[1] = l->llc_snap.org_code[2] = 0; 28393375Smdodd bcopy((caddr_t)&type, (caddr_t)&l->llc_snap.ether_type, 28421830Sjoerg sizeof(u_int16_t)); 2857055Sdg } 28636908Sjulian 2877055Sdg /* 2887055Sdg * Add local net header. If no space in first mbuf, 2897055Sdg * allocate another. 2907055Sdg */ 29193373Smdodd M_PREPEND(m, FDDI_HDR_LEN, M_DONTWAIT); 2927055Sdg if (m == 0) 2937055Sdg senderr(ENOBUFS); 2947055Sdg fh = mtod(m, struct fddi_header *); 2957055Sdg fh->fddi_fc = FDDIFC_LLC_ASYNC|FDDIFC_LLC_PRIO4; 29693375Smdodd bcopy((caddr_t)edst, (caddr_t)fh->fddi_dhost, FDDI_ADDR_LEN); 2977055Sdg queue_it: 29852248Smsmith if (hdrcmplt) 29993375Smdodd bcopy((caddr_t)esrc, (caddr_t)fh->fddi_shost, FDDI_ADDR_LEN); 30052248Smsmith else 30193375Smdodd bcopy((caddr_t)ac->ac_enaddr, (caddr_t)fh->fddi_shost, 30293373Smdodd FDDI_ADDR_LEN); 30336908Sjulian /* 30436908Sjulian * If a simplex interface, and the packet is being sent to our 30536908Sjulian * Ethernet address or a broadcast address, loopback a copy. 30636908Sjulian * XXX To make a simplex device behave exactly like a duplex 30736908Sjulian * device, we should copy in the case of sending to our own 30836908Sjulian * ethernet address (thus letting the original actually appear 30936908Sjulian * on the wire). However, we don't do that here for security 31036908Sjulian * reasons and compatibility with the original behavior. 31136908Sjulian */ 31236992Sjulian if ((ifp->if_flags & IFF_SIMPLEX) && 31336992Sjulian (loop_copy != -1)) { 31436908Sjulian if ((m->m_flags & M_BCAST) || loop_copy) { 31536908Sjulian struct mbuf *n = m_copy(m, 0, (int)M_COPYALL); 31636908Sjulian 31736908Sjulian (void) if_simloop(ifp, 31893373Smdodd n, dst->sa_family, FDDI_HDR_LEN); 31936908Sjulian } else if (bcmp(fh->fddi_dhost, 32093373Smdodd fh->fddi_shost, FDDI_ADDR_LEN) == 0) { 32136908Sjulian (void) if_simloop(ifp, 32293373Smdodd m, dst->sa_family, FDDI_HDR_LEN); 32393369Smdodd return (0); /* XXX */ 32436908Sjulian } 32536908Sjulian } 32636908Sjulian 32769152Sjlemon if (! IF_HANDOFF(&ifp->if_snd, m, ifp)) 3287055Sdg senderr(ENOBUFS); 3297055Sdg return (error); 3307055Sdg 3317055Sdgbad: 3327055Sdg if (m) 3337055Sdg m_freem(m); 3347055Sdg return (error); 3357055Sdg} 3367055Sdg 3377055Sdg/* 3387055Sdg * Process a received FDDI packet; 3397055Sdg * the packet is in the mbuf chain m without 3407055Sdg * the fddi header, which is provided separately. 3417055Sdg */ 3427055Sdgvoid 3437055Sdgfddi_input(ifp, fh, m) 3447055Sdg struct ifnet *ifp; 34593367Smdodd struct fddi_header *fh; 3467055Sdg struct mbuf *m; 3477055Sdg{ 34893367Smdodd struct ifqueue *inq; 34993367Smdodd struct llc *l; 3507055Sdg 3517055Sdg if ((ifp->if_flags & IFF_UP) == 0) { 3527055Sdg m_freem(m); 3537055Sdg return; 3547055Sdg } 35534961Sphk getmicrotime(&ifp->if_lastchange); 3567055Sdg ifp->if_ibytes += m->m_pkthdr.len + sizeof (*fh); 35721830Sjoerg if (fh->fddi_dhost[0] & 1) { 35821830Sjoerg if (bcmp((caddr_t)fddibroadcastaddr, (caddr_t)fh->fddi_dhost, 35993373Smdodd FDDI_ADDR_LEN) == 0) 36021830Sjoerg m->m_flags |= M_BCAST; 36121830Sjoerg else 36221830Sjoerg m->m_flags |= M_MCAST; 3637055Sdg ifp->if_imcasts++; 36423910Sjoerg } else if ((ifp->if_flags & IFF_PROMISC) 36593369Smdodd && bcmp(IFP2AC(ifp)->ac_enaddr, (caddr_t)fh->fddi_dhost, 36693373Smdodd FDDI_ADDR_LEN) != 0) { 36723910Sjoerg m_freem(m); 36823910Sjoerg return; 36921830Sjoerg } 3707055Sdg 37121830Sjoerg#ifdef M_LINK0 37221830Sjoerg /* 37321830Sjoerg * If this has a LLC priority of 0, then mark it so upper 37421830Sjoerg * layers have a hint that it really came via a FDDI/Ethernet 37521830Sjoerg * bridge. 37621830Sjoerg */ 37721830Sjoerg if ((fh->fddi_fc & FDDIFC_LLC_PRIO7) == FDDIFC_LLC_PRIO0) 37821830Sjoerg m->m_flags |= M_LINK0; 37921830Sjoerg#endif 38021830Sjoerg 3817055Sdg l = mtod(m, struct llc *); 3827055Sdg switch (l->llc_dsap) { 38354263Sshin#if defined(INET) || defined(INET6) || defined(NS) || defined(DECNET) || defined(IPX) || defined(NETATALK) 3847055Sdg case LLC_SNAP_LSAP: 3857055Sdg { 38621830Sjoerg u_int16_t type; 3877055Sdg if (l->llc_control != LLC_UI || l->llc_ssap != LLC_SNAP_LSAP) 3887055Sdg goto dropanyway; 38921830Sjoerg#ifdef NETATALK 39093371Smdodd if (Bcmp(&(l->llc_snap.org_code)[0], at_org_code, 39121830Sjoerg sizeof(at_org_code)) == 0 && 39293371Smdodd ntohs(l->llc_snap.ether_type) == ETHERTYPE_AT) { 39321830Sjoerg inq = &atintrq2; 39493373Smdodd m_adj(m, LLC_SNAPFRAMELEN); 39521830Sjoerg schednetisr(NETISR_ATALK); 39621830Sjoerg break; 39721830Sjoerg } 39821830Sjoerg 39993371Smdodd if (Bcmp(&(l->llc_snap.org_code)[0], aarp_org_code, 40021830Sjoerg sizeof(aarp_org_code)) == 0 && 40193371Smdodd ntohs(l->llc_snap.ether_type) == ETHERTYPE_AARP) { 40293373Smdodd m_adj(m, LLC_SNAPFRAMELEN); 40393369Smdodd aarpinput(IFP2AC(ifp), m); /* XXX */ 40421830Sjoerg return; 40521830Sjoerg } 40621830Sjoerg#endif /* NETATALK */ 4077055Sdg if (l->llc_snap.org_code[0] != 0 || l->llc_snap.org_code[1] != 0|| l->llc_snap.org_code[2] != 0) 4087055Sdg goto dropanyway; 40921830Sjoerg type = ntohs(l->llc_snap.ether_type); 4107055Sdg m_adj(m, 8); 41121830Sjoerg switch (type) { 4127055Sdg#ifdef INET 4137055Sdg case ETHERTYPE_IP: 41436265Sdg if (ipflow_fastforward(m)) 41536192Sdg return; 4167055Sdg schednetisr(NETISR_IP); 4177055Sdg inq = &ipintrq; 4187055Sdg break; 4197055Sdg 4207055Sdg case ETHERTYPE_ARP: 42178295Sjlemon if (ifp->if_flags & IFF_NOARP) 42278295Sjlemon goto dropanyway; 4237055Sdg schednetisr(NETISR_ARP); 4247055Sdg inq = &arpintrq; 4257055Sdg break; 4267055Sdg#endif 42754263Sshin#ifdef INET6 42854263Sshin case ETHERTYPE_IPV6: 42954263Sshin schednetisr(NETISR_IPV6); 43054263Sshin inq = &ip6intrq; 43154263Sshin break; 43254263Sshin#endif 43321830Sjoerg#ifdef IPX 43421830Sjoerg case ETHERTYPE_IPX: 43521830Sjoerg schednetisr(NETISR_IPX); 43621830Sjoerg inq = &ipxintrq; 43721830Sjoerg break; 43821830Sjoerg#endif 4397055Sdg#ifdef NS 4407055Sdg case ETHERTYPE_NS: 4417055Sdg schednetisr(NETISR_NS); 4427055Sdg inq = &nsintrq; 4437055Sdg break; 4447055Sdg#endif 4457055Sdg#ifdef DECNET 44621830Sjoerg case ETHERTYPE_DECNET: 4477055Sdg schednetisr(NETISR_DECNET); 4487055Sdg inq = &decnetintrq; 4497055Sdg break; 4507055Sdg#endif 45121830Sjoerg#ifdef NETATALK 45221830Sjoerg case ETHERTYPE_AT: 45321830Sjoerg schednetisr(NETISR_ATALK); 45421830Sjoerg inq = &atintrq1; 45521830Sjoerg break; 45621830Sjoerg case ETHERTYPE_AARP: 45721830Sjoerg /* probably this should be done with a NETISR as well */ 45893369Smdodd aarpinput(IFP2AC(ifp), m); /* XXX */ 45921830Sjoerg return; 46021830Sjoerg#endif /* NETATALK */ 4617055Sdg default: 46221830Sjoerg /* printf("fddi_input: unknown protocol 0x%x\n", type); */ 4637055Sdg ifp->if_noproto++; 4647055Sdg goto dropanyway; 4657055Sdg } 4667055Sdg break; 4677055Sdg } 4687055Sdg#endif /* INET || NS */ 46921830Sjoerg 4707055Sdg default: 47121830Sjoerg /* printf("fddi_input: unknown dsap 0x%x\n", l->llc_dsap); */ 4727055Sdg ifp->if_noproto++; 4737055Sdg dropanyway: 4747055Sdg m_freem(m); 4757055Sdg return; 4767055Sdg } 4777055Sdg 47869152Sjlemon (void) IF_HANDOFF(inq, m, NULL); 4797055Sdg} 4807055Sdg/* 4817055Sdg * Perform common duties while attaching to interface list 4827055Sdg */ 48321830Sjoerg 4847055Sdgvoid 4857055Sdgfddi_ifattach(ifp) 48693367Smdodd struct ifnet *ifp; 4877055Sdg{ 48893367Smdodd struct ifaddr *ifa; 48993367Smdodd struct sockaddr_dl *sdl; 4907055Sdg 4917055Sdg ifp->if_type = IFT_FDDI; 49293373Smdodd ifp->if_addrlen = FDDI_ADDR_LEN; 4937055Sdg ifp->if_hdrlen = 21; 4947055Sdg ifp->if_mtu = FDDIMTU; 49568180Sume ifp->if_resolvemulti = fddi_resolvemulti; 49616063Sgpalmer ifp->if_baudrate = 100000000; 49721830Sjoerg#ifdef IFF_NOTRAILERS 49821830Sjoerg ifp->if_flags |= IFF_NOTRAILERS; 49921830Sjoerg#endif 50084931Sfjoe ifp->if_broadcastaddr = fddibroadcastaddr; 50183130Sjlemon ifa = ifaddr_byindex(ifp->if_index); 50221831Sjoerg sdl = (struct sockaddr_dl *)ifa->ifa_addr; 50321831Sjoerg sdl->sdl_type = IFT_FDDI; 50421831Sjoerg sdl->sdl_alen = ifp->if_addrlen; 50593369Smdodd bcopy(IFP2AC(ifp)->ac_enaddr, LLADDR(sdl), ifp->if_addrlen); 5067055Sdg} 50768180Sume 50868180Sumestatic int 50968180Sumefddi_resolvemulti(ifp, llsa, sa) 51068180Sume struct ifnet *ifp; 51168180Sume struct sockaddr **llsa; 51268180Sume struct sockaddr *sa; 51368180Sume{ 51468180Sume struct sockaddr_dl *sdl; 51568180Sume struct sockaddr_in *sin; 51668180Sume#ifdef INET6 51768180Sume struct sockaddr_in6 *sin6; 51868180Sume#endif 51968180Sume u_char *e_addr; 52068180Sume 52168180Sume switch(sa->sa_family) { 52268180Sume case AF_LINK: 52368180Sume /* 52468180Sume * No mapping needed. Just check that it's a valid MC address. 52568180Sume */ 52668180Sume sdl = (struct sockaddr_dl *)sa; 52768180Sume e_addr = LLADDR(sdl); 52868180Sume if ((e_addr[0] & 1) != 1) 52993369Smdodd return (EADDRNOTAVAIL); 53068180Sume *llsa = 0; 53193369Smdodd return (0); 53268180Sume 53368180Sume#ifdef INET 53468180Sume case AF_INET: 53568180Sume sin = (struct sockaddr_in *)sa; 53668180Sume if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) 53793369Smdodd return (EADDRNOTAVAIL); 53868180Sume MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR, 53968180Sume M_WAITOK); 54068180Sume sdl->sdl_len = sizeof *sdl; 54168180Sume sdl->sdl_family = AF_LINK; 54268180Sume sdl->sdl_index = ifp->if_index; 54368180Sume sdl->sdl_type = IFT_FDDI; 54468180Sume sdl->sdl_nlen = 0; 54593375Smdodd sdl->sdl_alen = FDDI_ADDR_LEN; 54668180Sume sdl->sdl_slen = 0; 54768180Sume e_addr = LLADDR(sdl); 54868180Sume ETHER_MAP_IP_MULTICAST(&sin->sin_addr, e_addr); 54968180Sume *llsa = (struct sockaddr *)sdl; 55093369Smdodd return (0); 55168180Sume#endif 55268180Sume#ifdef INET6 55368180Sume case AF_INET6: 55468180Sume sin6 = (struct sockaddr_in6 *)sa; 55568180Sume if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 55668180Sume /* 55768180Sume * An IP6 address of 0 means listen to all 55868180Sume * of the Ethernet multicast address used for IP6. 55968180Sume * (This is used for multicast routers.) 56068180Sume */ 56168180Sume ifp->if_flags |= IFF_ALLMULTI; 56268180Sume *llsa = 0; 56393369Smdodd return (0); 56468180Sume } 56568180Sume if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) 56693369Smdodd return (EADDRNOTAVAIL); 56768180Sume MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR, 56868180Sume M_WAITOK); 56968180Sume sdl->sdl_len = sizeof *sdl; 57068180Sume sdl->sdl_family = AF_LINK; 57168180Sume sdl->sdl_index = ifp->if_index; 57268180Sume sdl->sdl_type = IFT_FDDI; 57368180Sume sdl->sdl_nlen = 0; 57493375Smdodd sdl->sdl_alen = FDDI_ADDR_LEN; 57568180Sume sdl->sdl_slen = 0; 57668180Sume e_addr = LLADDR(sdl); 57768180Sume ETHER_MAP_IPV6_MULTICAST(&sin6->sin6_addr, e_addr); 57868180Sume *llsa = (struct sockaddr *)sdl; 57993369Smdodd return (0); 58068180Sume#endif 58168180Sume 58268180Sume default: 58368180Sume /* 58468180Sume * Well, the text isn't quite right, but it's the name 58568180Sume * that counts... 58668180Sume */ 58793369Smdodd return (EAFNOSUPPORT); 58868180Sume } 58993375Smdodd 59093375Smdodd return (0); 59168180Sume} 59293375Smdodd 59393375Smdoddstatic moduledata_t fddi_mod = { 59493375Smdodd "fddi", /* module name */ 59593375Smdodd NULL, /* event handler */ 59693375Smdodd 0 /* extra data */ 59793375Smdodd}; 59893375Smdodd 59993375SmdoddDECLARE_MODULE(fddi, fddi_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 60093375SmdoddMODULE_VERSION(fddi, 1); 601