The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/net/if_arcsubr.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: if_arcsubr.c,v 1.36 2001/06/14 05:44:23 itojun Exp $   */
    2 /*      $FreeBSD$ */
    3 
    4 /*
    5  * Copyright (c) 1994, 1995 Ignatios Souvatzis
    6  * Copyright (c) 1982, 1989, 1993
    7  *      The Regents of the University of California.  All rights reserved.
    8  *
    9  * Redistribution and use in source and binary forms, with or without
   10  * modification, are permitted provided that the following conditions
   11  * are met:
   12  * 1. Redistributions of source code must retain the above copyright
   13  *    notice, this list of conditions and the following disclaimer.
   14  * 2. Redistributions in binary form must reproduce the above copyright
   15  *    notice, this list of conditions and the following disclaimer in the
   16  *    documentation and/or other materials provided with the distribution.
   17  * 3. All advertising materials mentioning features or use of this software
   18  *    must display the following acknowledgement:
   19  *      This product includes software developed by the University of
   20  *      California, Berkeley and its contributors.
   21  * 4. Neither the name of the University nor the names of its contributors
   22  *    may be used to endorse or promote products derived from this software
   23  *    without specific prior written permission.
   24  *
   25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   35  * SUCH DAMAGE.
   36  *
   37  * from: NetBSD: if_ethersubr.c,v 1.9 1994/06/29 06:36:11 cgd Exp
   38  *       @(#)if_ethersubr.c     8.1 (Berkeley) 6/10/93
   39  *
   40  */
   41 #include "opt_inet.h"
   42 #include "opt_inet6.h"
   43 #include "opt_ipx.h"
   44 
   45 #include <sys/param.h>
   46 #include <sys/systm.h>
   47 #include <sys/kernel.h>
   48 #include <sys/malloc.h>
   49 #include <sys/mbuf.h>
   50 #include <sys/protosw.h>
   51 #include <sys/socket.h>
   52 #include <sys/sockio.h>
   53 #include <sys/errno.h>
   54 #include <sys/syslog.h>
   55 
   56 #include <machine/cpu.h>
   57 
   58 #include <net/if.h>
   59 #include <net/netisr.h>
   60 #include <net/route.h>
   61 #include <net/if_dl.h>
   62 #include <net/if_types.h>
   63 #include <net/if_arc.h>
   64 #include <net/if_arp.h>
   65 #include <net/bpf.h>
   66 
   67 #if defined(INET) || defined(INET6)
   68 #include <netinet/in.h>
   69 #include <netinet/in_var.h>
   70 #include <netinet/if_ether.h>
   71 #endif
   72 
   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 MODULE_VERSION(arcnet, 1);
   83 
   84 #define ARCNET_ALLOW_BROKEN_ARP
   85 
   86 static struct mbuf *arc_defrag __P((struct ifnet *, struct mbuf *));
   87 static int arc_resolvemulti __P((struct ifnet *, struct sockaddr **,
   88                                  struct sockaddr *));
   89 
   90 #define ARC_LLADDR(ifp) (*(u_int8_t *)IF_LLADDR(ifp))
   91 
   92 #define senderr(e) { error = (e); goto bad;}
   93 #define SIN(s)  ((struct sockaddr_in *)s)
   94 #define SIPX(s) ((struct sockaddr_ipx *)s)
   95 
   96 /*
   97  * ARCnet output routine.
   98  * Encapsulate a packet of type family for the local net.
   99  * Assumes that ifp is actually pointer to arccom structure.
  100  */
  101 int
  102 arc_output(ifp, m, dst, rt0)
  103         struct ifnet *ifp;
  104         struct mbuf *m;
  105         struct sockaddr *dst;
  106         struct rtentry *rt0;
  107 {
  108         struct rtentry          *rt;
  109         struct arccom           *ac;
  110         struct arc_header       *ah;
  111         int                     error;
  112         u_int8_t                atype, adst;
  113         int                     loop_copy = 0;
  114         int                     isphds;
  115 
  116         if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
  117                 return(ENETDOWN); /* m, m1 aren't initialized yet */
  118 
  119         error = 0;
  120         ac = (struct arccom *)ifp;
  121 
  122         if ((rt = rt0)) {
  123                 if ((rt->rt_flags & RTF_UP) == 0) {
  124                         if ((rt0 = rt = rtalloc1(dst, 1, 0UL)))
  125                                 rt->rt_refcnt--;
  126                         else
  127                                 senderr(EHOSTUNREACH);
  128                 }
  129                 if (rt->rt_flags & RTF_GATEWAY) {
  130                         if (rt->rt_gwroute == 0)
  131                                 goto lookup;
  132                         if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) {
  133                                 rtfree(rt); rt = rt0;
  134                         lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1, 0UL);
  135                                 if ((rt = rt->rt_gwroute) == 0)
  136                                         senderr(EHOSTUNREACH);
  137                         }
  138                 }
  139                 if (rt->rt_flags & RTF_REJECT)
  140                         if (rt->rt_rmx.rmx_expire == 0 ||
  141                             time_second < rt->rt_rmx.rmx_expire)
  142                                 senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH);
  143         }
  144 
  145         switch (dst->sa_family) {
  146 #ifdef INET
  147         case AF_INET:
  148 
  149                 /*
  150                  * For now, use the simple IP addr -> ARCnet addr mapping
  151                  */
  152                 if (m->m_flags & (M_BCAST|M_MCAST))
  153                         adst = arcbroadcastaddr; /* ARCnet broadcast address */
  154                 else if (ifp->if_flags & IFF_NOARP)
  155                         adst = ntohl(SIN(dst)->sin_addr.s_addr) & 0xFF;
  156                 else if (!arpresolve(ifp, rt, m, dst, &adst, rt0))
  157                         return 0;       /* not resolved yet */
  158 
  159                 atype = (ifp->if_flags & IFF_LINK0) ?
  160                         ARCTYPE_IP_OLD : ARCTYPE_IP;
  161                 break;
  162 #endif
  163 #ifdef INET6
  164         case AF_INET6:
  165 #ifdef OLDIP6OUTPUT
  166                 if (!nd6_resolve(ifp, rt, m, dst, (u_char *)&adst))
  167                         return(0);      /* if not yet resolves */
  168 #else
  169                 if (!nd6_storelladdr(ifp, rt, m, dst, (u_char *)&adst))
  170                         return(0); /* it must be impossible, but... */
  171 #endif /* OLDIP6OUTPUT */
  172                 atype = ARCTYPE_INET6;
  173                 break;
  174 #endif
  175 #ifdef IPX
  176         case AF_IPX:
  177                 adst = SIPX(dst)->sipx_addr.x_host.c_host[5];
  178                 atype = ARCTYPE_IPX;
  179                 if (adst == 0xff)
  180                         adst = arcbroadcastaddr;
  181                 break;
  182 #endif
  183 
  184         case AF_UNSPEC:
  185                 loop_copy = -1;
  186                 ah = (struct arc_header *)dst->sa_data;
  187                 adst = ah->arc_dhost;
  188                 atype = ah->arc_type;
  189 
  190                 if (atype == ARCTYPE_ARP) {
  191                         atype = (ifp->if_flags & IFF_LINK0) ?
  192                             ARCTYPE_ARP_OLD: ARCTYPE_ARP;
  193 
  194 #ifdef ARCNET_ALLOW_BROKEN_ARP
  195                         /*
  196                          * XXX It's not clear per RFC826 if this is needed, but
  197                          * "assigned numbers" say this is wrong.
  198                          * However, e.g., AmiTCP 3.0Beta used it... we make this
  199                          * switchable for emergency cases. Not perfect, but...
  200                          */
  201                         if (ifp->if_flags & IFF_LINK2)
  202                                 mtod(m, struct arphdr *)->ar_pro = atype - 1;
  203 #endif
  204                 }
  205                 break;
  206 
  207         default:
  208                 printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit,
  209                     dst->sa_family);
  210                 senderr(EAFNOSUPPORT);
  211         }
  212 
  213         isphds = arc_isphds(atype);
  214         M_PREPEND(m, isphds ? ARC_HDRNEWLEN : ARC_HDRLEN, M_DONTWAIT);
  215         if (m == 0)
  216                 senderr(ENOBUFS);
  217         ah = mtod(m, struct arc_header *);
  218         ah->arc_type = atype;
  219         ah->arc_dhost = adst;
  220         ah->arc_shost = *IF_LLADDR(ifp);
  221         ah->arc_shost = ARC_LLADDR(ifp);
  222         if (isphds) {
  223                 ah->arc_flag = 0;
  224                 ah->arc_seqid = 0;
  225         }
  226 
  227         if ((ifp->if_flags & IFF_SIMPLEX) && (loop_copy != -1)) {
  228                 if ((m->m_flags & M_BCAST) || (loop_copy > 0)) {
  229                         struct mbuf *n = m_copy(m, 0, (int)M_COPYALL);
  230 
  231                         (void) if_simloop(ifp, n, dst->sa_family, ARC_HDRLEN);
  232                 } else if (ah->arc_dhost == ah->arc_shost) {
  233                         (void) if_simloop(ifp, m, dst->sa_family, ARC_HDRLEN);
  234                         return (0);     /* XXX */
  235                 }
  236         }
  237 
  238         if (ifp->if_bpf)
  239                 bpf_mtap(ifp, m);
  240 
  241         if (!IF_HANDOFF(&ifp->if_snd, m, ifp)) {
  242                 m = 0;
  243                 senderr(ENOBUFS);
  244         }
  245 
  246         return (error);
  247 
  248 bad:
  249         if (m)
  250                 m_freem(m);
  251         return (error);
  252 }
  253 
  254 void
  255 arc_frag_init(ifp)
  256         struct ifnet *ifp;
  257 {
  258         struct arccom *ac;
  259 
  260         ac = (struct arccom *)ifp;
  261         ac->curr_frag = 0;
  262 }
  263 
  264 struct mbuf *
  265 arc_frag_next(ifp)
  266         struct ifnet *ifp;
  267 {
  268         struct arccom *ac;
  269         struct mbuf *m;
  270         struct arc_header *ah;
  271 
  272         ac = (struct arccom *)ifp;
  273         if ((m = ac->curr_frag) == 0) {
  274                 int tfrags;
  275 
  276                 /* dequeue new packet */
  277                 IF_DEQUEUE(&ifp->if_snd, m);
  278                 if (m == 0)
  279                         return 0;
  280 
  281                 ah = mtod(m, struct arc_header *);
  282                 if (!arc_isphds(ah->arc_type))
  283                         return m;
  284 
  285                 ++ac->ac_seqid;         /* make the seqid unique */
  286                 tfrags = (m->m_pkthdr.len + ARC_MAX_DATA - 1) / ARC_MAX_DATA;
  287                 ac->fsflag = 2 * tfrags - 3;
  288                 ac->sflag = 0;
  289                 ac->rsflag = ac->fsflag;
  290                 ac->arc_dhost = ah->arc_dhost;
  291                 ac->arc_shost = ah->arc_shost;
  292                 ac->arc_type = ah->arc_type;
  293 
  294                 m_adj(m, ARC_HDRNEWLEN);
  295                 ac->curr_frag = m;
  296         }
  297 
  298         /* split out next fragment and return it */
  299         if (ac->sflag < ac->fsflag) {
  300                 /* we CAN'T have short packets here */
  301                 ac->curr_frag = m_split(m, ARC_MAX_DATA, M_DONTWAIT);
  302                 if (ac->curr_frag == 0) {
  303                         m_freem(m);
  304                         return 0;
  305                 }
  306 
  307                 M_PREPEND(m, ARC_HDRNEWLEN, M_DONTWAIT);
  308                 if (m == 0) {
  309                         m_freem(ac->curr_frag);
  310                         ac->curr_frag = 0;
  311                         return 0;
  312                 }
  313 
  314                 ah = mtod(m, struct arc_header *);
  315                 ah->arc_flag = ac->rsflag;
  316                 ah->arc_seqid = ac->ac_seqid;
  317 
  318                 ac->sflag += 2;
  319                 ac->rsflag = ac->sflag;
  320         } else if ((m->m_pkthdr.len >=
  321             ARC_MIN_FORBID_LEN - ARC_HDRNEWLEN + 2) &&
  322             (m->m_pkthdr.len <=
  323             ARC_MAX_FORBID_LEN - ARC_HDRNEWLEN + 2)) {
  324                 ac->curr_frag = 0;
  325 
  326                 M_PREPEND(m, ARC_HDRNEWLEN_EXC, M_DONTWAIT);
  327                 if (m == 0)
  328                         return 0;
  329 
  330                 ah = mtod(m, struct arc_header *);
  331                 ah->arc_flag = 0xFF;
  332                 ah->arc_seqid = 0xFFFF;
  333                 ah->arc_type2 = ac->arc_type;
  334                 ah->arc_flag2 = ac->sflag;
  335                 ah->arc_seqid2 = ac->ac_seqid;
  336         } else {
  337                 ac->curr_frag = 0;
  338 
  339                 M_PREPEND(m, ARC_HDRNEWLEN, M_DONTWAIT);
  340                 if (m == 0)
  341                         return 0;
  342 
  343                 ah = mtod(m, struct arc_header *);
  344                 ah->arc_flag = ac->sflag;
  345                 ah->arc_seqid = ac->ac_seqid;
  346         }
  347 
  348         ah->arc_dhost = ac->arc_dhost;
  349         ah->arc_shost = ac->arc_shost;
  350         ah->arc_type = ac->arc_type;
  351 
  352         return m;
  353 }
  354 
  355 /*
  356  * Defragmenter. Returns mbuf if last packet found, else
  357  * NULL. frees imcoming mbuf as necessary.
  358  */
  359 
  360 __inline struct mbuf *
  361 arc_defrag(ifp, m)
  362         struct ifnet *ifp;
  363         struct mbuf *m;
  364 {
  365         struct arc_header *ah, *ah1;
  366         struct arccom *ac;
  367         struct ac_frag *af;
  368         struct mbuf *m1;
  369         char *s;
  370         int newflen;
  371         u_char src,dst,typ;
  372 
  373         ac = (struct arccom *)ifp;
  374 
  375         if (m->m_len < ARC_HDRNEWLEN) {
  376                 m = m_pullup(m, ARC_HDRNEWLEN);
  377                 if (m == NULL) {
  378                         ++ifp->if_ierrors;
  379                         return NULL;
  380                 }
  381         }
  382 
  383         ah = mtod(m, struct arc_header *);
  384         typ = ah->arc_type;
  385 
  386         if (!arc_isphds(typ))
  387                 return m;
  388 
  389         src = ah->arc_shost;
  390         dst = ah->arc_dhost;
  391 
  392         if (ah->arc_flag == 0xff) {
  393                 m_adj(m, 4);
  394 
  395                 if (m->m_len < ARC_HDRNEWLEN) {
  396                         m = m_pullup(m, ARC_HDRNEWLEN);
  397                         if (m == NULL) {
  398                                 ++ifp->if_ierrors;
  399                                 return NULL;
  400                         }
  401                 }
  402 
  403                 ah = mtod(m, struct arc_header *);
  404         }
  405 
  406         af = &ac->ac_fragtab[src];
  407         m1 = af->af_packet;
  408         s = "debug code error";
  409 
  410         if (ah->arc_flag & 1) {
  411                 /*
  412                  * first fragment. We always initialize, which is
  413                  * about the right thing to do, as we only want to
  414                  * accept one fragmented packet per src at a time.
  415                  */
  416                 if (m1 != NULL)
  417                         m_freem(m1);
  418 
  419                 af->af_packet = m;
  420                 m1 = m;
  421                 af->af_maxflag = ah->arc_flag;
  422                 af->af_lastseen = 0;
  423                 af->af_seqid = ah->arc_seqid;
  424 
  425                 return NULL;
  426                 /* notreached */
  427         } else {
  428                 /* check for unfragmented packet */
  429                 if (ah->arc_flag == 0)
  430                         return m;
  431 
  432                 /* do we have a first packet from that src? */
  433                 if (m1 == NULL) {
  434                         s = "no first frag";
  435                         goto outofseq;
  436                 }
  437 
  438                 ah1 = mtod(m1, struct arc_header *);
  439 
  440                 if (ah->arc_seqid != ah1->arc_seqid) {
  441                         s = "seqid differs";
  442                         goto outofseq;
  443                 }
  444 
  445                 if (typ != ah1->arc_type) {
  446                         s = "type differs";
  447                         goto outofseq;
  448                 }
  449 
  450                 if (dst != ah1->arc_dhost) {
  451                         s = "dest host differs";
  452                         goto outofseq;
  453                 }
  454 
  455                 /* typ, seqid and dst are ok here. */
  456 
  457                 if (ah->arc_flag == af->af_lastseen) {
  458                         m_freem(m);
  459                         return NULL;
  460                 }
  461 
  462                 if (ah->arc_flag == af->af_lastseen + 2) {
  463                         /* ok, this is next fragment */
  464                         af->af_lastseen = ah->arc_flag;
  465                         m_adj(m,ARC_HDRNEWLEN);
  466 
  467                         /*
  468                          * m_cat might free the first mbuf (with pkthdr)
  469                          * in 2nd chain; therefore:
  470                          */
  471 
  472                         newflen = m->m_pkthdr.len;
  473 
  474                         m_cat(m1,m);
  475 
  476                         m1->m_pkthdr.len += newflen;
  477 
  478                         /* is it the last one? */
  479                         if (af->af_lastseen > af->af_maxflag) {
  480                                 af->af_packet = NULL;
  481                                 return(m1);
  482                         } else
  483                                 return NULL;
  484                 }
  485                 s = "other reason";
  486                 /* if all else fails, it is out of sequence, too */
  487         }
  488 outofseq:
  489         if (m1) {
  490                 m_freem(m1);
  491                 af->af_packet = NULL;
  492         }
  493 
  494         if (m)
  495                 m_freem(m);
  496 
  497         log(LOG_INFO,"%s%d: got out of seq. packet: %s\n",
  498             ifp->if_name, ifp->if_unit, s);
  499 
  500         return NULL;
  501 }
  502 
  503 /*
  504  * return 1 if Packet Header Definition Standard, else 0.
  505  * For now: old IP, old ARP aren't obviously. Lacking correct information,
  506  * we guess that besides new IP and new ARP also IPX and APPLETALK are PHDS.
  507  * (Apple and Novell corporations were involved, among others, in PHDS work).
  508  * Easiest is to assume that everybody else uses that, too.
  509  */
  510 int
  511 arc_isphds(type)
  512         u_int8_t type;
  513 {
  514         return (type != ARCTYPE_IP_OLD &&
  515                 type != ARCTYPE_ARP_OLD &&
  516                 type != ARCTYPE_DIAGNOSE);
  517 }
  518 
  519 /*
  520  * Process a received Arcnet packet;
  521  * the packet is in the mbuf chain m with
  522  * the ARCnet header.
  523  */
  524 void
  525 arc_input(ifp, m)
  526         struct ifnet *ifp;
  527         struct mbuf *m;
  528 {
  529         struct arc_header *ah;
  530         struct ifqueue *inq;
  531         u_int8_t atype;
  532 
  533         if ((ifp->if_flags & IFF_UP) == 0) {
  534                 m_freem(m);
  535                 return;
  536         }
  537 
  538         /* possibly defragment: */
  539         m = arc_defrag(ifp, m);
  540         if (m == NULL)
  541                 return;
  542 
  543         if (ifp->if_bpf)
  544                 bpf_mtap(ifp, m);
  545 
  546         ah = mtod(m, struct arc_header *);
  547         /* does this belong to us? */
  548         if ((ifp->if_flags & IFF_PROMISC) == 0
  549             && ah->arc_dhost != arcbroadcastaddr
  550             && ah->arc_dhost != ARC_LLADDR(ifp)) {
  551                 m_freem(m);
  552                 return;
  553         }
  554 
  555         ifp->if_ibytes += m->m_pkthdr.len;
  556 
  557         if (ah->arc_dhost == arcbroadcastaddr) {
  558                 m->m_flags |= M_BCAST|M_MCAST;
  559                 ifp->if_imcasts++;
  560         }
  561 
  562         atype = ah->arc_type;
  563         switch (atype) {
  564 #ifdef INET
  565         case ARCTYPE_IP:
  566                 m_adj(m, ARC_HDRNEWLEN);
  567                 if (ipflow_fastforward(m))
  568                         return;
  569                 schednetisr(NETISR_IP);
  570                 inq = &ipintrq;
  571                 break;
  572 
  573         case ARCTYPE_IP_OLD:
  574                 m_adj(m, ARC_HDRLEN);
  575                 if (ipflow_fastforward(m))
  576                         return;
  577                 schednetisr(NETISR_IP);
  578                 inq = &ipintrq;
  579                 break;
  580 
  581         case ARCTYPE_ARP:
  582                 if (ifp->if_flags & IFF_NOARP) {
  583                         /* Discard packet if ARP is disabled on interface */
  584                         m_freem(m);
  585                         return;
  586                 }
  587                 m_adj(m, ARC_HDRNEWLEN);
  588                 schednetisr(NETISR_ARP);
  589                 inq = &arpintrq;
  590 #ifdef ARCNET_ALLOW_BROKEN_ARP
  591                 mtod(m, struct arphdr *)->ar_pro = htons(ETHERTYPE_IP);
  592 #endif
  593                 break;
  594 
  595         case ARCTYPE_ARP_OLD:
  596                 if (ifp->if_flags & IFF_NOARP) {
  597                         /* Discard packet if ARP is disabled on interface */
  598                         m_freem(m);
  599                         return;
  600                 }
  601                 m_adj(m, ARC_HDRLEN);
  602                 schednetisr(NETISR_ARP);
  603                 inq = &arpintrq;
  604 #ifdef ARCNET_ALLOW_BROKEN_ARP
  605                 mtod(m, struct arphdr *)->ar_pro = htons(ETHERTYPE_IP);
  606 #endif
  607                 break;
  608 #endif
  609 #ifdef INET6
  610         case ARCTYPE_INET6:
  611                 m_adj(m, ARC_HDRNEWLEN);
  612                 schednetisr(NETISR_IPV6);
  613                 inq = &ip6intrq;
  614                 break;
  615 #endif
  616 #ifdef IPX
  617         case ARCTYPE_IPX:
  618                 m_adj(m, ARC_HDRNEWLEN);
  619                 schednetisr(NETISR_IPX);
  620                 inq = &ipxintrq;
  621                 break;
  622 #endif
  623         default:
  624                 m_freem(m);
  625                 return;
  626         }
  627 
  628         IF_HANDOFF(inq, m, NULL);
  629 }
  630 
  631 /*
  632  * Register (new) link level address.
  633  */
  634 void
  635 arc_storelladdr(ifp, lla)
  636         struct ifnet *ifp;
  637         u_int8_t lla;
  638 {
  639         ARC_LLADDR(ifp) = lla;
  640 }
  641 
  642 /*
  643  * Perform common duties while attaching to interface list
  644  */
  645 void
  646 arc_ifattach(ifp, lla)
  647         struct ifnet *ifp;
  648         u_int8_t lla;
  649 {
  650         struct ifaddr *ifa;
  651         struct sockaddr_dl *sdl;
  652         struct arccom *ac;
  653 
  654         if_attach(ifp);
  655         ifp->if_type = IFT_ARCNET;
  656         ifp->if_addrlen = 1;
  657         ifp->if_hdrlen = ARC_HDRLEN;
  658         ifp->if_mtu = 1500;
  659         ifp->if_resolvemulti = arc_resolvemulti;
  660         if (ifp->if_baudrate == 0)
  661                 ifp->if_baudrate = 2500000;
  662 #if __FreeBSD_version < 500000
  663         ifa = ifnet_addrs[ifp->if_index - 1];
  664 #else
  665         ifa = ifaddr_byindex(ifp->if_index);
  666 #endif
  667         KASSERT(ifa != NULL, ("%s: no lladdr!\n", __FUNCTION__));
  668         sdl = (struct sockaddr_dl *)ifa->ifa_addr;
  669         sdl->sdl_type = IFT_ARCNET;
  670         sdl->sdl_alen = ifp->if_addrlen;
  671 
  672         if (ifp->if_flags & IFF_BROADCAST)
  673                 ifp->if_flags |= IFF_MULTICAST|IFF_ALLMULTI;
  674 
  675         ac = (struct arccom *)ifp;
  676         ac->ac_seqid = (time_second) & 0xFFFF; /* try to make seqid unique */
  677         if (lla == 0) {
  678                 /* XXX this message isn't entirely clear, to me -- cgd */
  679                 log(LOG_ERR,"%s%d: link address 0 reserved for broadcasts.  Please change it and ifconfig %s%d down up\n",
  680                    ifp->if_name, ifp->if_unit, ifp->if_name, ifp->if_unit);
  681         }
  682         arc_storelladdr(ifp, lla);
  683 
  684         bpfattach(ifp, DLT_ARCNET, ARC_HDRLEN);
  685 }
  686 
  687 void
  688 arc_ifdetach(ifp)
  689         struct ifnet *ifp;
  690 {
  691         bpfdetach(ifp);
  692         if_detach(ifp);
  693 }
  694 
  695 int
  696 arc_ioctl(ifp, command, data)
  697         struct ifnet *ifp;
  698         int command;
  699         caddr_t data;
  700 {
  701         struct ifaddr *ifa = (struct ifaddr *) data;
  702         struct ifreq *ifr = (struct ifreq *) data;
  703         int error = 0;
  704 
  705         switch (command) {
  706         case SIOCSIFADDR:
  707                 ifp->if_flags |= IFF_UP;
  708                 switch (ifa->ifa_addr->sa_family) {
  709 #ifdef INET
  710                 case AF_INET:
  711                         ifp->if_init(ifp->if_softc);    /* before arpwhohas */
  712                         arp_ifinit(ifp, ifa);
  713                         break;
  714 #endif
  715 #ifdef IPX
  716                 /*
  717                  * XXX This code is probably wrong
  718                  */
  719                 case AF_IPX:
  720                 {
  721                         struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr);
  722 
  723                         if (ipx_nullhost(*ina))
  724                                 ina->x_host.c_host[5] = ARC_LLADDR(ifp);
  725                         else
  726                                 arc_storelladdr(ifp, ina->x_host.c_host[5]);
  727 
  728                         /*
  729                          * Set new address
  730                          */
  731                         ifp->if_init(ifp->if_softc);
  732                         break;
  733                 }
  734 #endif
  735                 default:
  736                         ifp->if_init(ifp->if_softc);
  737                         break;
  738                 }
  739                 break;
  740 
  741         case SIOCGIFADDR:
  742                 {
  743                         struct sockaddr *sa;
  744 
  745                         sa = (struct sockaddr *) &ifr->ifr_data;
  746                         *(u_int8_t *)sa->sa_data = ARC_LLADDR(ifp);
  747                 }
  748                 break;
  749 
  750         case SIOCADDMULTI:
  751         case SIOCDELMULTI:
  752                 if (ifr == NULL)
  753                         error = EAFNOSUPPORT;
  754                 else {
  755                         switch (ifr->ifr_addr.sa_family) {
  756                         case AF_INET:
  757                         case AF_INET6:
  758                                 error = 0;
  759                                 break;
  760                         default:
  761                                 error = EAFNOSUPPORT;
  762                                 break;
  763                         }
  764                 }
  765                 break;
  766 
  767         case SIOCSIFMTU:
  768                 /*
  769                  * Set the interface MTU.
  770                  * mtu can't be larger than ARCMTU for RFC1051
  771                  * and can't be larger than ARC_PHDS_MTU
  772                  */
  773                 if (((ifp->if_flags & IFF_LINK0) && ifr->ifr_mtu > ARCMTU) ||
  774                     ifr->ifr_mtu > ARC_PHDS_MAXMTU)
  775                         error = EINVAL;
  776                 else
  777                         ifp->if_mtu = ifr->ifr_mtu;
  778                 break;
  779         }
  780 
  781         return (error);
  782 }
  783 
  784 /* based on ether_resolvemulti() */
  785 int
  786 arc_resolvemulti(ifp, llsa, sa)
  787         struct ifnet *ifp;
  788         struct sockaddr **llsa;
  789         struct sockaddr *sa;
  790 {
  791         struct sockaddr_dl *sdl;
  792         struct sockaddr_in *sin;
  793 #ifdef INET6
  794         struct sockaddr_in6 *sin6;
  795 #endif
  796 
  797         switch(sa->sa_family) {
  798         case AF_LINK:
  799                 /*
  800                 * No mapping needed. Just check that it's a valid MC address.
  801                 */
  802                 sdl = (struct sockaddr_dl *)sa;
  803                 if (*LLADDR(sdl) != arcbroadcastaddr)
  804                         return EADDRNOTAVAIL;
  805                 *llsa = 0;
  806                 return 0;
  807 #ifdef INET
  808         case AF_INET:
  809                 sin = (struct sockaddr_in *)sa;
  810                 if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr)))
  811                         return EADDRNOTAVAIL;
  812                 MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR,
  813                        M_WAITOK|M_ZERO);
  814                 sdl->sdl_len = sizeof *sdl;
  815                 sdl->sdl_family = AF_LINK;
  816                 sdl->sdl_index = ifp->if_index;
  817                 sdl->sdl_type = IFT_ARCNET;
  818                 sdl->sdl_alen = ARC_ADDR_LEN;
  819                 *LLADDR(sdl) = 0;
  820                 *llsa = (struct sockaddr *)sdl;
  821                 return 0;
  822 #endif
  823 #ifdef INET6
  824         case AF_INET6:
  825                 sin6 = (struct sockaddr_in6 *)sa;
  826                 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
  827                         /*
  828                          * An IP6 address of 0 means listen to all
  829                          * of the Ethernet multicast address used for IP6.
  830                          * (This is used for multicast routers.)
  831                          */
  832                         ifp->if_flags |= IFF_ALLMULTI;
  833                         *llsa = 0;
  834                         return 0;
  835                 }
  836                 if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
  837                         return EADDRNOTAVAIL;
  838                 MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR,
  839                        M_WAITOK|M_ZERO);
  840                 sdl->sdl_len = sizeof *sdl;
  841                 sdl->sdl_family = AF_LINK;
  842                 sdl->sdl_index = ifp->if_index;
  843                 sdl->sdl_type = IFT_ARCNET;
  844                 sdl->sdl_alen = ARC_ADDR_LEN;
  845                 *LLADDR(sdl) = 0;
  846                 *llsa = (struct sockaddr *)sdl;
  847                 return 0;
  848 #endif
  849 
  850         default:
  851                 /*
  852                  * Well, the text isn't quite right, but it's the name
  853                  * that counts...
  854                  */
  855                 return EAFNOSUPPORT;
  856         }
  857 }

Cache object: fe080746fae3730e571b6e1438397995


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.