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.25 2003/10/26 19:09:44 christos 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.25 2003/10/26 19:09:44 christos 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                 struct mbuf mb;
  191 
  192                 mb.m_flags = 0;
  193                 mb.m_next = m0;
  194                 mb.m_len = 14;
  195                 mb.m_data = mb.m_dat;
  196                 ((u_int32_t *)mb.m_data)[0] = 0;
  197                 ((u_int32_t *)mb.m_data)[1] = 0;
  198                 ((u_int32_t *)mb.m_data)[2] = 0;
  199                 ((u_int16_t *)mb.m_data)[6] = etype;
  200                 bpf_mtap(ifp->if_bpf, &mb);
  201         }
  202 #endif
  203         myaddr = (struct ieee1394_hwaddr *)LLADDR(ifp->if_sadl);
  204         if ((ifp->if_flags & IFF_SIMPLEX) &&
  205             memcmp(&hwdst, myaddr, IEEE1394_ADDR_LEN) == 0)
  206                 return looutput(ifp, m0, dst, rt);
  207 
  208         /*
  209          * XXX:
  210          * The maximum possible rate depends on the topology.
  211          * So the determination of maxrec and fragmentation should be
  212          * called from the driver after probing the topology map.
  213          */
  214         if (m0->m_flags & (M_BCAST | M_MCAST)) {
  215                 hdrlen = IEEE1394_GASP_LEN;
  216                 hwdst.iha_speed = 0;    /* XXX */
  217         } else
  218                 hdrlen = 0;
  219         if (hwdst.iha_speed > myaddr->iha_speed)
  220                 hwdst.iha_speed = myaddr->iha_speed;
  221         if (hwdst.iha_maxrec > myaddr->iha_maxrec)
  222                 hwdst.iha_maxrec = myaddr->iha_maxrec;
  223         if (hwdst.iha_maxrec > (8 + hwdst.iha_speed))
  224                 hwdst.iha_maxrec = 8 + hwdst.iha_speed;
  225         if (hwdst.iha_maxrec < 8)
  226                 hwdst.iha_maxrec = 8;
  227 
  228         m0 = ieee1394_fragment(ifp, m0, (2<<hwdst.iha_maxrec) - hdrlen, etype);
  229         if (m0 == NULL)
  230                 senderr(ENOBUFS);
  231 
  232         s = splnet();
  233         ifp->if_obytes += m0->m_pkthdr.len;
  234         if (m0->m_flags & M_MCAST)
  235                 ifp->if_omcasts++;
  236         while ((m = m0) != NULL) {
  237                 m0 = m->m_nextpkt;
  238                 M_PREPEND(m, sizeof(struct ieee1394_header), M_DONTWAIT);
  239                 if (m == NULL) {
  240                         splx(s);
  241                         senderr(ENOBUFS);
  242                 }
  243                 memcpy(mtod(m, caddr_t), &hwdst, sizeof(hwdst));
  244                 IFQ_ENQUEUE(&ifp->if_snd, m, &pktattr, error);
  245                 if (error) {
  246                         /* mbuf is already freed */
  247                         splx(s);
  248                         goto bad;
  249                 }
  250         }
  251         if ((ifp->if_flags & IFF_OACTIVE) == 0)
  252                 (*ifp->if_start)(ifp);
  253         splx(s);
  254         return 0;
  255 
  256   bad:
  257         while (m0 != NULL) {
  258                 m = m0->m_nextpkt;
  259                 m_freem(m0);
  260                 m0 = m;
  261         }
  262 
  263         return error;
  264 }
  265 
  266 struct mbuf *
  267 ieee1394_fragment(struct ifnet *ifp, struct mbuf *m0, int maxsize,
  268     u_int16_t etype)
  269 {
  270         struct ieee1394com *ic = (struct ieee1394com *)ifp;
  271         int totlen, fraglen, off;
  272         struct mbuf *m, **mp;
  273         struct ieee1394_fraghdr *ifh;
  274         struct ieee1394_unfraghdr *iuh;
  275 
  276         totlen = m0->m_pkthdr.len;
  277         if (totlen + sizeof(struct ieee1394_unfraghdr) <= maxsize) {
  278                 M_PREPEND(m0, sizeof(struct ieee1394_unfraghdr), M_DONTWAIT);
  279                 if (m0 == NULL)
  280                         goto bad;
  281                 iuh = mtod(m0, struct ieee1394_unfraghdr *);
  282                 iuh->iuh_ft = 0;
  283                 iuh->iuh_etype = etype;
  284                 return m0;
  285         }
  286 
  287         fraglen = maxsize - sizeof(struct ieee1394_fraghdr);
  288 
  289         M_PREPEND(m0, sizeof(struct ieee1394_fraghdr), M_DONTWAIT);
  290         if (m0 == NULL)
  291                 goto bad;
  292         ifh = mtod(m0, struct ieee1394_fraghdr *);
  293         ifh->ifh_ft_size = htons(IEEE1394_FT_MORE | (totlen - 1));
  294         ifh->ifh_etype_off = etype;
  295         ifh->ifh_dgl = htons(ic->ic_dgl);
  296         ifh->ifh_reserved = 0;
  297         off = fraglen;
  298         mp = &m0->m_nextpkt;
  299         while (off < totlen) {
  300                 if (off + fraglen > totlen)
  301                         fraglen = totlen - off;
  302                 MGETHDR(m, M_DONTWAIT, MT_HEADER);
  303                 if (m == NULL)
  304                         goto bad;
  305                 m->m_flags |= m0->m_flags & (M_BCAST|M_MCAST);  /* copy bcast */
  306                 MH_ALIGN(m, sizeof(struct ieee1394_fraghdr));
  307                 m->m_len = sizeof(struct ieee1394_fraghdr);
  308                 ifh = mtod(m, struct ieee1394_fraghdr *);
  309                 ifh->ifh_ft_size =
  310                     htons(IEEE1394_FT_SUBSEQ | IEEE1394_FT_MORE | (totlen - 1));
  311                 ifh->ifh_etype_off = htons(off);
  312                 ifh->ifh_dgl = htons(ic->ic_dgl);
  313                 ifh->ifh_reserved = 0;
  314                 m->m_next = m_copy(m0, sizeof(*ifh) + off, fraglen);
  315                 if (m->m_next == NULL)
  316                         goto bad;
  317                 m->m_pkthdr.len = sizeof(*ifh) + fraglen;
  318                 off += fraglen;
  319                 *mp = m;
  320                 mp = &m->m_nextpkt;
  321         }
  322         ifh->ifh_ft_size &= ~htons(IEEE1394_FT_MORE);   /* last fragment */
  323         m_adj(m0, -(m0->m_pkthdr.len - maxsize));
  324 
  325         ic->ic_dgl++;
  326         return m0;
  327 
  328   bad:
  329         while ((m = m0) != NULL) {
  330                 m0 = m->m_nextpkt;
  331                 m->m_nextpkt = NULL;
  332                 m_freem(m);
  333         }
  334         return NULL;
  335 }
  336 
  337 static void
  338 ieee1394_input(struct ifnet *ifp, struct mbuf *m)
  339 {
  340         struct ifqueue *inq;
  341         u_int16_t etype;
  342         int s;
  343         struct ieee1394_header *ih;
  344         struct ieee1394_unfraghdr *iuh;
  345 
  346         if ((ifp->if_flags & IFF_UP) == 0) {
  347                 m_freem(m);
  348                 return;
  349         }
  350         if (m->m_len < sizeof(*ih) + sizeof(*iuh)) {
  351                 if ((m = m_pullup(m, sizeof(*ih) + sizeof(*iuh))) == NULL)
  352                         return;
  353         }
  354 
  355         ih = mtod(m, struct ieee1394_header *);
  356         iuh = (struct ieee1394_unfraghdr *)&ih[1];
  357 
  358         if (ntohs(iuh->iuh_ft) & (IEEE1394_FT_SUBSEQ | IEEE1394_FT_MORE)) {
  359                 if ((m = ieee1394_reass(ifp, m)) == NULL)
  360                         return;
  361                 ih = mtod(m, struct ieee1394_header *);
  362                 iuh = (struct ieee1394_unfraghdr *)&ih[1];
  363         }
  364         etype = ntohs(iuh->iuh_etype);
  365 
  366         /* strip off the ieee1394 header */
  367         m_adj(m, sizeof(*ih) + sizeof(*iuh));
  368 #if NBPFILTER > 0
  369         /* XXX: emulate DLT_EN10MB */
  370         if (ifp->if_bpf) {
  371                 struct mbuf mb;
  372 
  373                 mb.m_flags = 0;
  374                 mb.m_next = m;
  375                 mb.m_len = 14;
  376                 mb.m_data = mb.m_dat;
  377                 ((u_int32_t *)mb.m_data)[0] = 0;
  378                 ((u_int32_t *)mb.m_data)[1] = 0;
  379                 ((u_int32_t *)mb.m_data)[2] = 0;
  380                 ((u_int16_t *)mb.m_data)[6] = iuh->iuh_etype;
  381                 bpf_mtap(ifp->if_bpf, &mb);
  382         }
  383 #endif
  384 
  385         switch (etype) {
  386 #ifdef INET
  387         case ETHERTYPE_IP:
  388                 schednetisr(NETISR_IP);
  389                 inq = &ipintrq;
  390                 break;
  391 
  392         case ETHERTYPE_ARP:
  393                 schednetisr(NETISR_ARP);
  394                 inq = &arpintrq;
  395                 break;
  396 #endif /* INET */
  397 
  398 #ifdef INET6
  399         case ETHERTYPE_IPV6:
  400                 schednetisr(NETISR_IPV6);
  401                 inq = &ip6intrq;
  402                 break;
  403 #endif /* INET6 */
  404 
  405         default:
  406                 m_freem(m);
  407                 return;
  408         }
  409 
  410         s = splnet();
  411         if (IF_QFULL(inq)) {
  412                 IF_DROP(inq);
  413                 m_freem(m);
  414         } else
  415                 IF_ENQUEUE(inq, m);
  416         splx(s);
  417 }
  418 
  419 static struct mbuf *
  420 ieee1394_reass(struct ifnet *ifp, struct mbuf *m0)
  421 {
  422         struct ieee1394com *ic = (struct ieee1394com *)ifp;
  423         struct ieee1394_header *ih;
  424         struct ieee1394_fraghdr *ifh;
  425         struct ieee1394_unfraghdr *iuh;
  426         struct ieee1394_reassq *rq;
  427         struct ieee1394_reass_pkt *rp, *trp, *nrp = NULL;
  428         int len;
  429         u_int16_t off, ftype, size, dgl;
  430 
  431         if (m0->m_len < sizeof(*ih) + sizeof(*ifh)) {
  432                 if ((m0 = m_pullup(m0, sizeof(*ih) + sizeof(*ifh))) == NULL)
  433                         return NULL;
  434         }
  435         ih = mtod(m0, struct ieee1394_header *);
  436         ifh = (struct ieee1394_fraghdr *)&ih[1];
  437         m_adj(m0, sizeof(*ih) + sizeof(*ifh));
  438         size = ntohs(ifh->ifh_ft_size);
  439         ftype = size & (IEEE1394_FT_SUBSEQ | IEEE1394_FT_MORE);
  440         size = (size & ~ftype) + 1;
  441         dgl = ifh->ifh_dgl;
  442         len = m0->m_pkthdr.len;
  443         if (ftype & IEEE1394_FT_SUBSEQ) {
  444                 m_tag_delete_chain(m0, NULL);
  445                 m0->m_flags &= ~M_PKTHDR;
  446                 off = ntohs(ifh->ifh_etype_off);
  447         } else
  448                 off = 0;
  449 
  450         for (rq = LIST_FIRST(&ic->ic_reassq); ; rq = LIST_NEXT(rq, rq_node)) {
  451                 if (rq == NULL) {
  452                         /*
  453                          * Create a new reassemble queue head for the node.
  454                          */
  455                         rq = malloc(sizeof(*rq), M_FTABLE, M_NOWAIT);
  456                         if (rq == NULL) {
  457                                 m_freem(m0);
  458                                 return NULL;
  459                         }
  460                         memcpy(rq->rq_uid, ih->ih_uid, IEEE1394_ADDR_LEN);
  461                         LIST_INIT(&rq->rq_pkt);
  462                         LIST_INSERT_HEAD(&ic->ic_reassq, rq, rq_node);
  463                         break;
  464                 }
  465                 if (memcmp(rq->rq_uid, ih->ih_uid, IEEE1394_ADDR_LEN) == 0)
  466                         break;
  467         }
  468         for (rp = LIST_FIRST(&rq->rq_pkt); rp != NULL; rp = nrp) {
  469                 nrp = LIST_NEXT(rp, rp_next);
  470                 if (rp->rp_dgl != dgl)
  471                         continue;
  472                 /*
  473                  * sanity check:
  474                  * datagram size must be same for all fragments, and
  475                  * no overlap is allowed.
  476                  */
  477                 if (rp->rp_size != size ||
  478                     (off < rp->rp_off + rp->rp_len && off + len > rp->rp_off)) {
  479                         /*
  480                          * This happens probably due to wrapping dgl value.
  481                          * Destroy all previously received fragment and
  482                          * enqueue current fragment.
  483                          */
  484                         for (rp = LIST_FIRST(&rq->rq_pkt); rp != NULL;
  485                             rp = nrp) {
  486                                 nrp = LIST_NEXT(rp, rp_next);
  487                                 if (rp->rp_dgl == dgl) {
  488                                         LIST_REMOVE(rp, rp_next);
  489                                         m_freem(rp->rp_m);
  490                                         free(rp, M_FTABLE);
  491                                 }
  492                         }
  493                         break;
  494                 }
  495                 if (rp->rp_off + rp->rp_len == off) {
  496                         /*
  497                          * All the subsequent fragments received in sequence
  498                          * come here.
  499                          * Concatinate mbuf to previous one instead of
  500                          * allocating new reassemble queue structure,
  501                          * and try to merge more with the subsequent fragment
  502                          * in the queue.
  503                          */
  504                         m_cat(rp->rp_m, m0);
  505                         rp->rp_len += len;
  506                         while (rp->rp_off + rp->rp_len < size &&
  507                             nrp != NULL && nrp->rp_dgl == dgl &&
  508                             nrp->rp_off == rp->rp_off + rp->rp_len) {
  509                                 LIST_REMOVE(nrp, rp_next);
  510                                 m_cat(rp->rp_m, nrp->rp_m);
  511                                 rp->rp_len += nrp->rp_len;
  512                                 free(nrp, M_FTABLE);
  513                                 nrp = LIST_NEXT(rp, rp_next);
  514                         }
  515                         m0 = NULL;      /* mark merged */
  516                         break;
  517                 }
  518                 if (off + m0->m_pkthdr.len == rp->rp_off) {
  519                         m_cat(m0, rp->rp_m);
  520                         rp->rp_m = m0;
  521                         rp->rp_off = off;
  522                         rp->rp_len += len;
  523                         m0 = NULL;      /* mark merged */
  524                         break;
  525                 }
  526                 if (rp->rp_off > off) {
  527                         /* insert before rp */
  528                         nrp = rp;
  529                         break;
  530                 }
  531                 if (nrp == NULL || nrp->rp_dgl != dgl) {
  532                         /* insert after rp */
  533                         nrp = NULL;
  534                         break;
  535                 }
  536         }
  537         if (m0 == NULL) {
  538                 if (rp->rp_off != 0 || rp->rp_len != size)
  539                         return NULL;
  540                 /* fragment done */
  541                 LIST_REMOVE(rp, rp_next);
  542                 m0 = rp->rp_m;
  543                 m0->m_pkthdr.len = rp->rp_len;
  544                 M_PREPEND(m0, sizeof(*ih) + sizeof(*iuh), M_DONTWAIT);
  545                 if (m0 != NULL) {
  546                         ih = mtod(m0, struct ieee1394_header *);
  547                         iuh = (struct ieee1394_unfraghdr *)&ih[1];
  548                         memcpy(ih, &rp->rp_hdr, sizeof(*ih));
  549                         iuh->iuh_ft = 0;
  550                         iuh->iuh_etype = rp->rp_etype;
  551                 }
  552                 free(rp, M_FTABLE);
  553                 return m0;
  554         }
  555 
  556         /*
  557          * New fragment received.  Allocate reassemble queue structure.
  558          */
  559         trp = malloc(sizeof(*trp), M_FTABLE, M_NOWAIT);
  560         if (trp == NULL) {
  561                 m_freem(m0);
  562                 return NULL;
  563         }
  564         trp->rp_m = m0;
  565         memcpy(&trp->rp_hdr, ih, sizeof(*ih));
  566         trp->rp_size = size;
  567         trp->rp_etype = ifh->ifh_etype_off;      /* valid only if off==0 */
  568         trp->rp_off = off;
  569         trp->rp_dgl = dgl;
  570         trp->rp_len = len;
  571         trp->rp_ttl = IEEE1394_REASS_TIMEOUT;
  572         if (trp->rp_ttl <= ifp->if_timer)
  573                 trp->rp_ttl = ifp->if_timer + 1;
  574 
  575         if (rp == NULL) {
  576                 /* first fragment for the dgl */
  577                 LIST_INSERT_HEAD(&rq->rq_pkt, trp, rp_next);
  578         } else if (nrp == NULL) {
  579                 /* no next fragment for the dgl */
  580                 LIST_INSERT_AFTER(rp, trp, rp_next);
  581         } else {
  582                 /* there is a hole */
  583                 LIST_INSERT_BEFORE(nrp, trp, rp_next);
  584         }
  585         return NULL;
  586 }
  587 
  588 void
  589 ieee1394_drain(struct ifnet *ifp)
  590 {
  591         struct ieee1394com *ic = (struct ieee1394com *)ifp;
  592         struct ieee1394_reassq *rq;
  593         struct ieee1394_reass_pkt *rp;
  594 
  595         while ((rq = LIST_FIRST(&ic->ic_reassq)) != NULL) {
  596                 LIST_REMOVE(rq, rq_node);
  597                 while ((rp = LIST_FIRST(&rq->rq_pkt)) != NULL) {
  598                         LIST_REMOVE(rp, rp_next);
  599                         m_freem(rp->rp_m);
  600                         free(rp, M_FTABLE);
  601                 }
  602                 free(rq, M_FTABLE);
  603         }
  604 }
  605 
  606 void
  607 ieee1394_watchdog(struct ifnet *ifp)
  608 {
  609         struct ieee1394com *ic = (struct ieee1394com *)ifp;
  610         struct ieee1394_reassq *rq;
  611         struct ieee1394_reass_pkt *rp, *nrp;
  612         int dec;
  613 
  614         dec = (ifp->if_timer > 0) ? ifp->if_timer : 1;
  615         for (rq = LIST_FIRST(&ic->ic_reassq); rq != NULL;
  616             rq = LIST_NEXT(rq, rq_node)) {
  617                 for (rp = LIST_FIRST(&rq->rq_pkt); rp != NULL; rp = nrp) {
  618                         nrp = LIST_NEXT(rp, rp_next);
  619                         if (rp->rp_ttl >= dec)
  620                                 rp->rp_ttl -= dec;
  621                         else {
  622                                 LIST_REMOVE(rp, rp_next);
  623                                 m_freem(rp->rp_m);
  624                                 free(rp, M_FTABLE);
  625                         }
  626                 }
  627         }
  628 }
  629 
  630 const char *
  631 ieee1394_sprintf(const u_int8_t *laddr)
  632 {
  633         static char buf[3*8];
  634 
  635         snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
  636             laddr[0], laddr[1], laddr[2], laddr[3],
  637             laddr[4], laddr[5], laddr[6], laddr[7]);
  638         return buf;
  639 }
  640 
  641 void
  642 ieee1394_ifattach(struct ifnet *ifp, const struct ieee1394_hwaddr *hwaddr)
  643 {
  644         struct ieee1394_hwaddr *baddr;
  645         struct ieee1394com *ic = (struct ieee1394com *)ifp;
  646 
  647         ifp->if_type = IFT_IEEE1394;
  648         ifp->if_addrlen = sizeof(struct ieee1394_hwaddr);
  649         ifp->if_hdrlen = sizeof(struct ieee1394_header);
  650         ifp->if_dlt = DLT_EN10MB;       /* XXX */
  651         ifp->if_mtu = IEEE1394MTU;
  652         ifp->if_output = ieee1394_output;
  653         ifp->if_input = ieee1394_input;
  654         ifp->if_drain = ieee1394_drain;
  655         ifp->if_watchdog = ieee1394_watchdog;
  656         ifp->if_timer = 1;
  657         if (ifp->if_baudrate == 0)
  658                 ifp->if_baudrate = IF_Mbps(100);
  659 
  660         if_alloc_sadl(ifp);
  661         memcpy(LLADDR(ifp->if_sadl), hwaddr, ifp->if_addrlen);
  662 
  663         ifp->if_broadcastaddr = malloc(ifp->if_addrlen, M_DEVBUF, M_WAITOK);
  664         baddr = (struct ieee1394_hwaddr *)ifp->if_broadcastaddr;
  665         memset(baddr->iha_uid, 0xff, IEEE1394_ADDR_LEN);
  666         baddr->iha_speed = 0;   /*XXX: how to determine the speed for bcast? */
  667         baddr->iha_maxrec = 512 << baddr->iha_speed;
  668         memset(baddr->iha_offset, 0, sizeof(baddr->iha_offset));
  669         LIST_INIT(&ic->ic_reassq);
  670 #if NBPFILTER > 0
  671         bpfattach(ifp, DLT_EN10MB, 14); /* XXX */
  672 #endif
  673 }
  674 
  675 void
  676 ieee1394_ifdetach(struct ifnet *ifp)
  677 {
  678         ieee1394_drain(ifp);
  679 #if NBPFILTER > 0
  680         bpfdetach(ifp);
  681 #endif
  682         free(ifp->if_broadcastaddr, M_DEVBUF);
  683         ifp->if_broadcastaddr = NULL;
  684 #if 0   /* done in if_detach() */
  685         if_free_sadl(ifp);
  686 #endif
  687 }
  688 
  689 int
  690 ieee1394_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
  691 {
  692         struct ifreq *ifr = (struct ifreq *)data;
  693         struct ifaddr *ifa = (struct ifaddr *)data;
  694         int error = 0;
  695 #if __NetBSD_Version__ < 105080000
  696         int fw_init(struct ifnet *);
  697         void fw_stop(struct ifnet *, int);
  698 #endif
  699 
  700         switch (cmd) {
  701         case SIOCSIFADDR:
  702                 ifp->if_flags |= IFF_UP;
  703                 switch (ifa->ifa_addr->sa_family) {
  704 #ifdef INET
  705                 case AF_INET:
  706 #if __NetBSD_Version__ >= 105080000
  707                         if ((error = (*ifp->if_init)(ifp)) != 0)
  708 #else
  709                         if ((error = fw_init(ifp)) != 0)
  710 #endif
  711                                 break;
  712                         arp_ifinit(ifp, ifa);
  713                         break;
  714 #endif /* INET */
  715                 default:
  716 #if __NetBSD_Version__ >= 105080000
  717                         error = (*ifp->if_init)(ifp);
  718 #else
  719                         error = fw_init(ifp);
  720 #endif
  721                         break;
  722                 }
  723                 break;
  724 
  725         case SIOCGIFADDR:
  726                 memcpy(((struct sockaddr *)&ifr->ifr_data)->sa_data,
  727                     LLADDR(ifp->if_sadl), IEEE1394_ADDR_LEN);
  728                     break;
  729 
  730         case SIOCSIFMTU:
  731                 if (ifr->ifr_mtu > IEEE1394MTU)
  732                         error = EINVAL;
  733                 else
  734                         ifp->if_mtu = ifr->ifr_mtu;
  735                 break;
  736 
  737         case SIOCSIFFLAGS:
  738 #if __NetBSD_Version__ >= 105080000
  739                 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) == IFF_RUNNING)
  740                         (*ifp->if_stop)(ifp, 1);
  741                 else if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) == IFF_UP)
  742                         error = (*ifp->if_init)(ifp);
  743                 else if ((ifp->if_flags & IFF_UP) != 0)
  744                         error = (*ifp->if_init)(ifp);
  745 #else
  746                 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) == IFF_RUNNING)
  747                         fw_stop(ifp, 1);
  748                 else if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) == IFF_UP)
  749                         error = fw_init(ifp);
  750                 else if ((ifp->if_flags & IFF_UP) != 0)
  751                         error = fw_init(ifp);
  752 #endif
  753                 break;
  754 
  755         case SIOCADDMULTI:
  756         case SIOCDELMULTI:
  757                 /* nothing to do */
  758                 break;
  759 
  760         default:
  761                 error = ENOTTY;
  762                 break;
  763         }
  764 
  765         return error;
  766 }

Cache object: 5f3f476e60a17f836fdfbe1653d12ca9


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