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

Cache object: 806124e420052e7f202cca7484800aa5


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