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_ieee1394subr.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_ieee1394subr.c,v 1.40 2008/04/28 20:24:09 martin Exp $      */
    2 
    3 /*
    4  * Copyright (c) 2000 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Atsushi Onoe.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   29  * POSSIBILITY OF SUCH DAMAGE.
   30  */
   31 
   32 #include <sys/cdefs.h>
   33 __KERNEL_RCSID(0, "$NetBSD: if_ieee1394subr.c,v 1.40 2008/04/28 20:24:09 martin Exp $");
   34 
   35 #include "opt_inet.h"
   36 #include "bpfilter.h"
   37 
   38 #include <sys/param.h>
   39 #include <sys/systm.h>
   40 #include <sys/socket.h>
   41 #include <sys/sockio.h>
   42 #include <sys/kernel.h>
   43 #include <sys/mbuf.h>
   44 #include <sys/device.h>
   45 
   46 #include <net/if.h>
   47 #include <net/if_dl.h>
   48 #include <net/if_ieee1394.h>
   49 #include <net/if_types.h>
   50 #include <net/if_media.h>
   51 #include <net/ethertypes.h>
   52 #include <net/netisr.h>
   53 #include <net/route.h>
   54 
   55 #if NBPFILTER > 0
   56 #include <net/bpf.h>
   57 #endif
   58 
   59 #ifdef INET
   60 #include <netinet/in.h>
   61 #include <netinet/in_var.h>
   62 #include <netinet/if_inarp.h>
   63 #endif /* INET */
   64 #ifdef INET6
   65 #include <netinet/in.h>
   66 #include <netinet6/in6_var.h>
   67 #include <netinet6/nd6.h>
   68 #endif /* INET6 */
   69 
   70 #include <dev/ieee1394/fw_port.h>
   71 #include <dev/ieee1394/firewire.h>
   72 
   73 #include <dev/ieee1394/firewirereg.h>
   74 #include <dev/ieee1394/iec13213.h>
   75 #include <dev/ieee1394/if_fwipvar.h>
   76 
   77 #define IEEE1394_REASS_TIMEOUT  3       /* 3 sec */
   78 
   79 #define senderr(e)      do { error = (e); goto bad; } while(0/*CONSTCOND*/)
   80 
   81 static int  ieee1394_output(struct ifnet *, struct mbuf *,
   82                 const struct sockaddr *, struct rtentry *);
   83 static struct mbuf *ieee1394_reass(struct ifnet *, struct mbuf *, uint16_t);
   84 
   85 static int
   86 ieee1394_output(struct ifnet *ifp, struct mbuf *m0, const struct sockaddr *dst,
   87     struct rtentry *rt0)
   88 {
   89         uint16_t etype = 0;
   90         struct mbuf *m;
   91         int s, hdrlen, error = 0;
   92         struct rtentry *rt;
   93         struct mbuf *mcopy = NULL;
   94         struct ieee1394_hwaddr *hwdst, baddr;
   95         const struct ieee1394_hwaddr *myaddr;
   96         ALTQ_DECL(struct altq_pktattr pktattr;)
   97 #ifdef INET
   98         struct arphdr *ah;
   99 #endif /* INET */
  100         struct m_tag *mtag;
  101         int unicast;
  102 
  103         if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
  104                 senderr(ENETDOWN);
  105         if ((rt = rt0) != NULL) {
  106                 if ((rt->rt_flags & RTF_UP) == 0) {
  107                         if ((rt0 = rt = rtalloc1(dst, 1)) != NULL) {
  108                                 rt->rt_refcnt--;
  109                                 if (rt->rt_ifp != ifp)
  110                                         return (*rt->rt_ifp->if_output)
  111                                                         (ifp, m0, dst, rt);
  112                         } else
  113                                 senderr(EHOSTUNREACH);
  114                 }
  115                 if (rt->rt_flags & RTF_GATEWAY) {
  116                         if (rt->rt_gwroute == NULL)
  117                                 goto lookup;
  118                         if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) {
  119                                 rtfree(rt);
  120                                 rt = rt0;
  121   lookup:
  122                                 rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1);
  123                                 if ((rt = rt->rt_gwroute) == NULL)
  124                                         senderr(EHOSTUNREACH);
  125                                 /* the "G" test below also prevents rt == rt0 */
  126                                 if ((rt->rt_flags & RTF_GATEWAY) ||
  127                                     (rt->rt_ifp != ifp)) {
  128                                         rt->rt_refcnt--;
  129                                         rt0->rt_gwroute = NULL;
  130                                         senderr(EHOSTUNREACH);
  131                                 }
  132                         }
  133                 }
  134                 if (rt->rt_flags & RTF_REJECT)
  135                         if (rt->rt_rmx.rmx_expire == 0 ||
  136                             time_second < rt->rt_rmx.rmx_expire)
  137                                 senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH);
  138         }
  139 
  140         /*
  141          * If the queueing discipline needs packet classification,
  142          * do it before prepending link headers.
  143          */
  144         IFQ_CLASSIFY(&ifp->if_snd, m0, dst->sa_family, &pktattr);
  145 
  146         /*
  147          * For unicast, we make a tag to store the lladdr of the
  148          * destination. This might not be the first time we have seen
  149          * the packet (for instance, the arp code might be trying to
  150          * re-send it after receiving an arp reply) so we only
  151          * allocate a tag if there isn't one there already. For
  152          * multicast, we will eventually use a different tag to store
  153          * the channel number.
  154          */
  155         unicast = !(m0->m_flags & (M_BCAST | M_MCAST));
  156         if (unicast) {
  157                 mtag =
  158                     m_tag_locate(m0, MTAG_FIREWIRE, MTAG_FIREWIRE_HWADDR, NULL);
  159                 if (!mtag) {
  160                         mtag = m_tag_alloc(MTAG_FIREWIRE, MTAG_FIREWIRE_HWADDR,
  161                             sizeof (struct ieee1394_hwaddr), M_NOWAIT);
  162                         if (!mtag) {
  163                                 error = ENOMEM;
  164                                 goto bad;
  165                         }
  166                         m_tag_prepend(m0, mtag);
  167                 }
  168                 hwdst = (struct ieee1394_hwaddr *)(mtag + 1);
  169         } else {
  170                 hwdst = &baddr;
  171         }
  172 
  173         switch (dst->sa_family) {
  174 #ifdef INET
  175         case AF_INET:
  176                 if (unicast && (!arpresolve(ifp, rt, m0, dst, (u_char *)hwdst)))
  177                         return 0;       /* if not yet resolved */
  178                 /* if broadcasting on a simplex interface, loopback a copy */
  179                 if ((m0->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX))
  180                         mcopy = m_copy(m0, 0, M_COPYALL);
  181                 etype = htons(ETHERTYPE_IP);
  182                 break;
  183         case AF_ARP:
  184                 ah = mtod(m0, struct arphdr *);
  185                 ah->ar_hrd = htons(ARPHRD_IEEE1394);
  186                 etype = htons(ETHERTYPE_ARP);
  187                 break;
  188 #endif /* INET */
  189 #ifdef INET6
  190         case AF_INET6:
  191                 if (unicast && (!nd6_storelladdr(ifp, rt, m0, dst,
  192                     hwdst->iha_uid, IEEE1394_ADDR_LEN))) {
  193                         /* something bad happened */
  194                         return 0;
  195                 }
  196                 etype = htons(ETHERTYPE_IPV6);
  197                 break;
  198 #endif /* INET6 */
  199 
  200         case pseudo_AF_HDRCMPLT:
  201         case AF_UNSPEC:
  202                 /* TODO? */
  203         default:
  204                 printf("%s: can't handle af%d\n", ifp->if_xname,
  205                     dst->sa_family);
  206                 senderr(EAFNOSUPPORT);
  207                 break;
  208         }
  209 
  210         if (mcopy)
  211                 looutput(ifp, mcopy, dst, rt);
  212         myaddr = (const struct ieee1394_hwaddr *)CLLADDR(ifp->if_sadl);
  213 #if NBPFILTER > 0
  214         if (ifp->if_bpf) {
  215                 struct ieee1394_bpfhdr h;
  216                 if (unicast)
  217                         memcpy(h.ibh_dhost, hwdst->iha_uid, 8);
  218                 else
  219                         memcpy(h.ibh_dhost,
  220                             ((const struct ieee1394_hwaddr *)
  221                             ifp->if_broadcastaddr)->iha_uid, 8);
  222                 memcpy(h.ibh_shost, myaddr->iha_uid, 8);
  223                 h.ibh_type = etype;
  224                 bpf_mtap2(ifp->if_bpf, &h, sizeof(h), m0);
  225         }
  226 #endif
  227         if ((ifp->if_flags & IFF_SIMPLEX) &&
  228             unicast &&
  229             memcmp(hwdst, myaddr, IEEE1394_ADDR_LEN) == 0)
  230                 return looutput(ifp, m0, dst, rt);
  231 
  232         /*
  233          * XXX:
  234          * The maximum possible rate depends on the topology.
  235          * So the determination of maxrec and fragmentation should be
  236          * called from the driver after probing the topology map.
  237          */
  238         if (unicast) {
  239                 hdrlen = IEEE1394_GASP_LEN;
  240                 hwdst->iha_speed = 0;   /* XXX */
  241         } else
  242                 hdrlen = 0;
  243 
  244         if (hwdst->iha_speed > myaddr->iha_speed)
  245                 hwdst->iha_speed = myaddr->iha_speed;
  246         if (hwdst->iha_maxrec > myaddr->iha_maxrec)
  247                 hwdst->iha_maxrec = myaddr->iha_maxrec;
  248         if (hwdst->iha_maxrec > (8 + hwdst->iha_speed))
  249                 hwdst->iha_maxrec = 8 + hwdst->iha_speed;
  250         if (hwdst->iha_maxrec < 8)
  251                         hwdst->iha_maxrec = 8;
  252 
  253         m0 = ieee1394_fragment(ifp, m0, (2<<hwdst->iha_maxrec) - hdrlen, etype);
  254         if (m0 == NULL)
  255                 senderr(ENOBUFS);
  256 
  257         s = splnet();
  258         ifp->if_obytes += m0->m_pkthdr.len;
  259         if (m0->m_flags & M_MCAST)
  260                 ifp->if_omcasts++;
  261         while ((m = m0) != NULL) {
  262                 m0 = m->m_nextpkt;
  263                 if (m == NULL) {
  264                         splx(s);
  265                         senderr(ENOBUFS);
  266                 }
  267                 IFQ_ENQUEUE(&ifp->if_snd, m, &pktattr, error);
  268                 if (error) {
  269                         /* mbuf is already freed */
  270                         splx(s);
  271                         goto bad;
  272                 }
  273         }
  274         if ((ifp->if_flags & IFF_OACTIVE) == 0)
  275                 (*ifp->if_start)(ifp);
  276         splx(s);
  277         return 0;
  278 
  279   bad:
  280         while (m0 != NULL) {
  281                 m = m0->m_nextpkt;
  282                 m_freem(m0);
  283                 m0 = m;
  284         }
  285 
  286         return error;
  287 }
  288 
  289 struct mbuf *
  290 ieee1394_fragment(struct ifnet *ifp, struct mbuf *m0, int maxsize,
  291     uint16_t etype)
  292 {
  293         struct ieee1394com *ic = (struct ieee1394com *)ifp;
  294         int totlen, fraglen, off;
  295         struct mbuf *m, **mp;
  296         struct ieee1394_fraghdr *ifh;
  297         struct ieee1394_unfraghdr *iuh;
  298 
  299         totlen = m0->m_pkthdr.len;
  300         if (totlen + sizeof(struct ieee1394_unfraghdr) <= maxsize) {
  301                 M_PREPEND(m0, sizeof(struct ieee1394_unfraghdr), M_DONTWAIT);
  302                 if (m0 == NULL)
  303                         goto bad;
  304                 iuh = mtod(m0, struct ieee1394_unfraghdr *);
  305                 iuh->iuh_ft = 0;
  306                 iuh->iuh_etype = etype;
  307                 return m0;
  308         }
  309 
  310         fraglen = maxsize - sizeof(struct ieee1394_fraghdr);
  311 
  312         M_PREPEND(m0, sizeof(struct ieee1394_fraghdr), M_DONTWAIT);
  313         if (m0 == NULL)
  314                 goto bad;
  315         ifh = mtod(m0, struct ieee1394_fraghdr *);
  316         ifh->ifh_ft_size = htons(IEEE1394_FT_MORE | (totlen - 1));
  317         ifh->ifh_etype_off = etype;
  318         ifh->ifh_dgl = htons(ic->ic_dgl);
  319         ifh->ifh_reserved = 0;
  320         off = fraglen;
  321         mp = &m0->m_nextpkt;
  322         while (off < totlen) {
  323                 if (off + fraglen > totlen)
  324                         fraglen = totlen - off;
  325                 MGETHDR(m, M_DONTWAIT, MT_HEADER);
  326                 if (m == NULL)
  327                         goto bad;
  328                 m->m_flags |= m0->m_flags & (M_BCAST|M_MCAST);  /* copy bcast */
  329                 MH_ALIGN(m, sizeof(struct ieee1394_fraghdr));
  330                 m->m_len = sizeof(struct ieee1394_fraghdr);
  331                 ifh = mtod(m, struct ieee1394_fraghdr *);
  332                 ifh->ifh_ft_size =
  333                     htons(IEEE1394_FT_SUBSEQ | IEEE1394_FT_MORE | (totlen - 1));
  334                 ifh->ifh_etype_off = htons(off);
  335                 ifh->ifh_dgl = htons(ic->ic_dgl);
  336                 ifh->ifh_reserved = 0;
  337                 m->m_next = m_copy(m0, sizeof(*ifh) + off, fraglen);
  338                 if (m->m_next == NULL)
  339                         goto bad;
  340                 m->m_pkthdr.len = sizeof(*ifh) + fraglen;
  341                 off += fraglen;
  342                 *mp = m;
  343                 mp = &m->m_nextpkt;
  344         }
  345         ifh->ifh_ft_size &= ~htons(IEEE1394_FT_MORE);   /* last fragment */
  346         m_adj(m0, -(m0->m_pkthdr.len - maxsize));
  347 
  348         ic->ic_dgl++;
  349         return m0;
  350 
  351   bad:
  352         while ((m = m0) != NULL) {
  353                 m0 = m->m_nextpkt;
  354                 m->m_nextpkt = NULL;
  355                 m_freem(m);
  356         }
  357         return NULL;
  358 }
  359 
  360 void
  361 ieee1394_input(struct ifnet *ifp, struct mbuf *m, uint16_t src)
  362 {
  363         struct ifqueue *inq;
  364         uint16_t etype;
  365         int s;
  366         struct ieee1394_unfraghdr *iuh;
  367 
  368         if ((ifp->if_flags & IFF_UP) == 0) {
  369                 m_freem(m);
  370                 return;
  371         }
  372         if (m->m_len < sizeof(*iuh)) {
  373                 if ((m = m_pullup(m, sizeof(*iuh))) == NULL)
  374                         return;
  375         }
  376 
  377         iuh = mtod(m, struct ieee1394_unfraghdr *);
  378 
  379         if (ntohs(iuh->iuh_ft) & (IEEE1394_FT_SUBSEQ | IEEE1394_FT_MORE)) {
  380                 if ((m = ieee1394_reass(ifp, m, src)) == NULL)
  381                         return;
  382                 iuh = mtod(m, struct ieee1394_unfraghdr *);
  383         }
  384         etype = ntohs(iuh->iuh_etype);
  385 
  386         /* strip off the ieee1394 header */
  387         m_adj(m, sizeof(*iuh));
  388 #if NBPFILTER > 0
  389         if (ifp->if_bpf) {
  390                 struct ieee1394_bpfhdr h;
  391                 struct m_tag *mtag;
  392                 const struct ieee1394_hwaddr *myaddr;
  393 
  394                 mtag = m_tag_locate(m,
  395                     MTAG_FIREWIRE, MTAG_FIREWIRE_SENDER_EUID, 0);
  396                 if (mtag)
  397                         memcpy(h.ibh_shost, mtag + 1, 8);
  398                 else
  399                         memset(h.ibh_shost, 0, 8);
  400                 if (m->m_flags & M_BCAST)
  401                         memcpy(h.ibh_dhost,
  402                             ((const struct ieee1394_hwaddr *)
  403                             ifp->if_broadcastaddr)->iha_uid, 8);
  404                 else {
  405                         myaddr =
  406                           (const struct ieee1394_hwaddr *)CLLADDR(ifp->if_sadl);
  407                         memcpy(h.ibh_dhost, myaddr->iha_uid, 8);
  408                 }
  409                 h.ibh_type = htons(etype);
  410                 bpf_mtap2(ifp->if_bpf, &h, sizeof(h), m);
  411         }
  412 #endif
  413 
  414         switch (etype) {
  415 #ifdef INET
  416         case ETHERTYPE_IP:
  417                 schednetisr(NETISR_IP);
  418                 inq = &ipintrq;
  419                 break;
  420 
  421         case ETHERTYPE_ARP:
  422                 schednetisr(NETISR_ARP);
  423                 inq = &arpintrq;
  424                 break;
  425 #endif /* INET */
  426 
  427 #ifdef INET6
  428         case ETHERTYPE_IPV6:
  429                 schednetisr(NETISR_IPV6);
  430                 inq = &ip6intrq;
  431                 break;
  432 #endif /* INET6 */
  433 
  434         default:
  435                 m_freem(m);
  436                 return;
  437         }
  438 
  439         s = splnet();
  440         if (IF_QFULL(inq)) {
  441                 IF_DROP(inq);
  442                 m_freem(m);
  443         } else
  444                 IF_ENQUEUE(inq, m);
  445         splx(s);
  446 }
  447 
  448 static struct mbuf *
  449 ieee1394_reass(struct ifnet *ifp, struct mbuf *m0, uint16_t src)
  450 {
  451         struct ieee1394com *ic = (struct ieee1394com *)ifp;
  452         struct ieee1394_fraghdr *ifh;
  453         struct ieee1394_unfraghdr *iuh;
  454         struct ieee1394_reassq *rq;
  455         struct ieee1394_reass_pkt *rp, *trp, *nrp = NULL;
  456         int len;
  457         uint16_t etype, off, ftype, size, dgl;
  458         uint32_t id;
  459 
  460         if (m0->m_len < sizeof(*ifh)) {
  461                 if ((m0 = m_pullup(m0, sizeof(*ifh))) == NULL)
  462                         return NULL;
  463         }
  464         ifh = mtod(m0, struct ieee1394_fraghdr *);
  465         m_adj(m0, sizeof(*ifh));
  466         size = ntohs(ifh->ifh_ft_size);
  467         ftype = size & (IEEE1394_FT_SUBSEQ | IEEE1394_FT_MORE);
  468         size = (size & ~ftype) + 1;
  469         dgl = ntohs(ifh->ifh_dgl);
  470         len = m0->m_pkthdr.len;
  471         id = dgl | (src << 16);
  472         if (ftype & IEEE1394_FT_SUBSEQ) {
  473                 m_tag_delete_chain(m0, NULL);
  474                 m0->m_flags &= ~M_PKTHDR;
  475                 etype = 0;
  476                 off = ntohs(ifh->ifh_etype_off);
  477         } else {
  478                 etype = ifh->ifh_etype_off;
  479                 off = 0;
  480         }
  481 
  482         for (rq = LIST_FIRST(&ic->ic_reassq); ; rq = LIST_NEXT(rq, rq_node)) {
  483                 if (rq == NULL) {
  484                         /*
  485                          * Create a new reassemble queue head for the node.
  486                          */
  487                         rq = malloc(sizeof(*rq), M_FTABLE, M_NOWAIT);
  488                         if (rq == NULL) {
  489                                 m_freem(m0);
  490                                 return NULL;
  491                         }
  492                         rq->fr_id = id;
  493                         LIST_INIT(&rq->rq_pkt);
  494                         LIST_INSERT_HEAD(&ic->ic_reassq, rq, rq_node);
  495                         break;
  496                 }
  497                 if (rq->fr_id == id)
  498                         break;
  499         }
  500         for (rp = LIST_FIRST(&rq->rq_pkt); rp != NULL; rp = nrp) {
  501                 nrp = LIST_NEXT(rp, rp_next);
  502                 if (rp->rp_dgl != dgl)
  503                         continue;
  504                 /*
  505                  * sanity check:
  506                  * datagram size must be same for all fragments, and
  507                  * no overlap is allowed.
  508                  */
  509                 if (rp->rp_size != size ||
  510                     (off < rp->rp_off + rp->rp_len && off + len > rp->rp_off)) {
  511                         /*
  512                          * This happens probably due to wrapping dgl value.
  513                          * Destroy all previously received fragment and
  514                          * enqueue current fragment.
  515                          */
  516                         for (rp = LIST_FIRST(&rq->rq_pkt); rp != NULL;
  517                             rp = nrp) {
  518                                 nrp = LIST_NEXT(rp, rp_next);
  519                                 if (rp->rp_dgl == dgl) {
  520                                         LIST_REMOVE(rp, rp_next);
  521                                         m_freem(rp->rp_m);
  522                                         free(rp, M_FTABLE);
  523                                 }
  524                         }
  525                         break;
  526                 }
  527                 if (rp->rp_off + rp->rp_len == off) {
  528                         /*
  529                          * All the subsequent fragments received in sequence
  530                          * come here.
  531                          * Concatinate mbuf to previous one instead of
  532                          * allocating new reassemble queue structure,
  533                          * and try to merge more with the subsequent fragment
  534                          * in the queue.
  535                          */
  536                         m_cat(rp->rp_m, m0);
  537                         rp->rp_len += len;
  538                         while (rp->rp_off + rp->rp_len < size &&
  539                             nrp != NULL && nrp->rp_dgl == dgl &&
  540                             nrp->rp_off == rp->rp_off + rp->rp_len) {
  541                                 LIST_REMOVE(nrp, rp_next);
  542                                 m_cat(rp->rp_m, nrp->rp_m);
  543                                 rp->rp_len += nrp->rp_len;
  544                                 free(nrp, M_FTABLE);
  545                                 nrp = LIST_NEXT(rp, rp_next);
  546                         }
  547                         m0 = NULL;      /* mark merged */
  548                         break;
  549                 }
  550                 if (off + m0->m_pkthdr.len == rp->rp_off) {
  551                         m_cat(m0, rp->rp_m);
  552                         rp->rp_m = m0;
  553                         rp->rp_off = off;
  554                         rp->rp_etype = etype;    /* over writing trust etype */
  555                         rp->rp_len += len;
  556                         m0 = NULL;      /* mark merged */
  557                         break;
  558                 }
  559                 if (rp->rp_off > off) {
  560                         /* insert before rp */
  561                         nrp = rp;
  562                         break;
  563                 }
  564                 if (nrp == NULL || nrp->rp_dgl != dgl) {
  565                         /* insert after rp */
  566                         nrp = NULL;
  567                         break;
  568                 }
  569         }
  570         if (m0 == NULL) {
  571                 if (rp->rp_off != 0 || rp->rp_len != size)
  572                         return NULL;
  573                 /* fragment done */
  574                 LIST_REMOVE(rp, rp_next);
  575                 m0 = rp->rp_m;
  576                 m0->m_pkthdr.len = rp->rp_len;
  577                 M_PREPEND(m0, sizeof(*iuh), M_DONTWAIT);
  578                 if (m0 != NULL) {
  579                         iuh = mtod(m0, struct ieee1394_unfraghdr *);
  580                         iuh->iuh_ft = 0;
  581                         iuh->iuh_etype = rp->rp_etype;
  582                 }
  583                 free(rp, M_FTABLE);
  584                 return m0;
  585         }
  586 
  587         /*
  588          * New fragment received.  Allocate reassemble queue structure.
  589          */
  590         trp = malloc(sizeof(*trp), M_FTABLE, M_NOWAIT);
  591         if (trp == NULL) {
  592                 m_freem(m0);
  593                 return NULL;
  594         }
  595         trp->rp_m = m0;
  596         trp->rp_size = size;
  597         trp->rp_etype = etype;           /* valid only if off==0 */
  598         trp->rp_off = off;
  599         trp->rp_dgl = dgl;
  600         trp->rp_len = len;
  601         trp->rp_ttl = IEEE1394_REASS_TIMEOUT;
  602         if (trp->rp_ttl <= ifp->if_timer)
  603                 trp->rp_ttl = ifp->if_timer + 1;
  604 
  605         if (rp == NULL) {
  606                 /* first fragment for the dgl */
  607                 LIST_INSERT_HEAD(&rq->rq_pkt, trp, rp_next);
  608         } else if (nrp == NULL) {
  609                 /* no next fragment for the dgl */
  610                 LIST_INSERT_AFTER(rp, trp, rp_next);
  611         } else {
  612                 /* there is a hole */
  613                 LIST_INSERT_BEFORE(nrp, trp, rp_next);
  614         }
  615         return NULL;
  616 }
  617 
  618 void
  619 ieee1394_drain(struct ifnet *ifp)
  620 {
  621         struct ieee1394com *ic = (struct ieee1394com *)ifp;
  622         struct ieee1394_reassq *rq;
  623         struct ieee1394_reass_pkt *rp;
  624 
  625         while ((rq = LIST_FIRST(&ic->ic_reassq)) != NULL) {
  626                 LIST_REMOVE(rq, rq_node);
  627                 while ((rp = LIST_FIRST(&rq->rq_pkt)) != NULL) {
  628                         LIST_REMOVE(rp, rp_next);
  629                         m_freem(rp->rp_m);
  630                         free(rp, M_FTABLE);
  631                 }
  632                 free(rq, M_FTABLE);
  633         }
  634 }
  635 
  636 void
  637 ieee1394_watchdog(struct ifnet *ifp)
  638 {
  639         struct ieee1394com *ic = (struct ieee1394com *)ifp;
  640         struct ieee1394_reassq *rq;
  641         struct ieee1394_reass_pkt *rp, *nrp;
  642         int dec;
  643 
  644         dec = (ifp->if_timer > 0) ? ifp->if_timer : 1;
  645         for (rq = LIST_FIRST(&ic->ic_reassq); rq != NULL;
  646             rq = LIST_NEXT(rq, rq_node)) {
  647                 for (rp = LIST_FIRST(&rq->rq_pkt); rp != NULL; rp = nrp) {
  648                         nrp = LIST_NEXT(rp, rp_next);
  649                         if (rp->rp_ttl >= dec)
  650                                 rp->rp_ttl -= dec;
  651                         else {
  652                                 LIST_REMOVE(rp, rp_next);
  653                                 m_freem(rp->rp_m);
  654                                 free(rp, M_FTABLE);
  655                         }
  656                 }
  657         }
  658 }
  659 
  660 const char *
  661 ieee1394_sprintf(const uint8_t *laddr)
  662 {
  663         static char buf[3*8];
  664 
  665         snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
  666             laddr[0], laddr[1], laddr[2], laddr[3],
  667             laddr[4], laddr[5], laddr[6], laddr[7]);
  668         return buf;
  669 }
  670 
  671 void
  672 ieee1394_ifattach(struct ifnet *ifp, const struct ieee1394_hwaddr *hwaddr)
  673 {
  674         struct ieee1394_hwaddr *baddr;
  675         struct ieee1394com *ic = (struct ieee1394com *)ifp;
  676 
  677         ifp->if_type = IFT_IEEE1394;
  678         ifp->if_hdrlen = sizeof(struct ieee1394_header);
  679         ifp->if_dlt = DLT_EN10MB;       /* XXX */
  680         ifp->if_mtu = IEEE1394MTU;
  681         ifp->if_output = ieee1394_output;
  682         ifp->if_drain = ieee1394_drain;
  683         ifp->if_watchdog = ieee1394_watchdog;
  684         ifp->if_timer = 1;
  685         if (ifp->if_baudrate == 0)
  686                 ifp->if_baudrate = IF_Mbps(100);
  687 
  688         if_set_sadl(ifp, hwaddr, sizeof(struct ieee1394_hwaddr));
  689 
  690         baddr = malloc(ifp->if_addrlen, M_DEVBUF, M_WAITOK);
  691         memset(baddr->iha_uid, 0xff, IEEE1394_ADDR_LEN);
  692         baddr->iha_speed = 0;   /*XXX: how to determine the speed for bcast? */
  693         baddr->iha_maxrec = 512 << baddr->iha_speed;
  694         memset(baddr->iha_offset, 0, sizeof(baddr->iha_offset));
  695         ifp->if_broadcastaddr = (uint8_t *)baddr;
  696         LIST_INIT(&ic->ic_reassq);
  697 #if NBPFILTER > 0
  698         bpfattach(ifp,
  699             DLT_APPLE_IP_OVER_IEEE1394, sizeof(struct ieee1394_hwaddr));
  700 #endif
  701 }
  702 
  703 void
  704 ieee1394_ifdetach(struct ifnet *ifp)
  705 {
  706         ieee1394_drain(ifp);
  707 #if NBPFILTER > 0
  708         bpfdetach(ifp);
  709 #endif
  710         free(__UNCONST(ifp->if_broadcastaddr), M_DEVBUF);
  711         ifp->if_broadcastaddr = NULL;
  712 #if 0   /* done in if_detach() */
  713         if_free_sadl(ifp);
  714 #endif
  715 }
  716 
  717 int
  718 ieee1394_ioctl(struct ifnet *ifp, u_long cmd, void *data)
  719 {
  720         struct ifreq *ifr = (struct ifreq *)data;
  721         struct ifaddr *ifa = (struct ifaddr *)data;
  722         int error = 0;
  723 #if __NetBSD_Version__ < 105080000
  724         int fw_init(struct ifnet *);
  725         void fw_stop(struct ifnet *, int);
  726 #endif
  727 
  728         switch (cmd) {
  729         case SIOCSIFADDR:
  730                 ifp->if_flags |= IFF_UP;
  731                 switch (ifa->ifa_addr->sa_family) {
  732 #ifdef INET
  733                 case AF_INET:
  734 #if __NetBSD_Version__ >= 105080000
  735                         if ((error = (*ifp->if_init)(ifp)) != 0)
  736 #else
  737                         if ((error = fw_init(ifp)) != 0)
  738 #endif
  739                                 break;
  740                         arp_ifinit(ifp, ifa);
  741                         break;
  742 #endif /* INET */
  743                 default:
  744 #if __NetBSD_Version__ >= 105080000
  745                         error = (*ifp->if_init)(ifp);
  746 #else
  747                         error = fw_init(ifp);
  748 #endif
  749                         break;
  750                 }
  751                 break;
  752 
  753         case SIOCGIFADDR:
  754                 memcpy(((struct sockaddr *)&ifr->ifr_data)->sa_data,
  755                     CLLADDR(ifp->if_sadl), IEEE1394_ADDR_LEN);
  756                     break;
  757 
  758         case SIOCSIFMTU:
  759                 if (ifr->ifr_mtu > IEEE1394MTU)
  760                         error = EINVAL;
  761                 else if ((error = ifioctl_common(ifp, cmd, data)) == ENETRESET)
  762                         error = 0;
  763                 break;
  764 
  765         case SIOCSIFCAP:
  766                 return ifioctl_common(ifp, cmd, data);
  767         default:
  768                 error = ENOTTY;
  769                 break;
  770         }
  771 
  772         return error;
  773 }

Cache object: 96727f9d81810d5109aa1e55c6c7fe65


[ 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.