[BACK]Return to frag6.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / netinet6

Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.

Diff for /src/sys/netinet6/frag6.c between version 1.52 and 1.53

version 1.52, 2011/12/31 20:41:59 version 1.53, 2012/07/01 22:04:44
Line 35  __KERNEL_RCSID(0, "$NetBSD$");
Line 35  __KERNEL_RCSID(0, "$NetBSD$");
   
 #include <sys/param.h>  #include <sys/param.h>
 #include <sys/systm.h>  #include <sys/systm.h>
 #include <sys/malloc.h>  
 #include <sys/mbuf.h>  #include <sys/mbuf.h>
 #include <sys/domain.h>  #include <sys/domain.h>
 #include <sys/protosw.h>  #include <sys/protosw.h>
Line 43  __KERNEL_RCSID(0, "$NetBSD$");
Line 42  __KERNEL_RCSID(0, "$NetBSD$");
 #include <sys/socketvar.h>  #include <sys/socketvar.h>
 #include <sys/errno.h>  #include <sys/errno.h>
 #include <sys/time.h>  #include <sys/time.h>
   #include <sys/kmem.h>
 #include <sys/kernel.h>  #include <sys/kernel.h>
 #include <sys/syslog.h>  #include <sys/syslog.h>
   
Line 84  frag6_init(void)
Line 84  frag6_init(void)
 }  }
   
 /*  /*
    * IPv6 fragment input.
    *
  * In RFC2460, fragment and reassembly rule do not agree with each other,   * In RFC2460, fragment and reassembly rule do not agree with each other,
  * in terms of next header field handling in fragment header.   * in terms of next header field handling in fragment header.
  * While the sender will use the same value for all of the fragmented packets,   * While the sender will use the same value for all of the fragmented packets,
Line 112  frag6_init(void)
Line 114  frag6_init(void)
  *   *
  * There is no explicit reason given in the RFC.  Historical reason maybe?   * There is no explicit reason given in the RFC.  Historical reason maybe?
  */   */
 /*  int
  * Fragment input  frag6_input(struct mbuf **mp, int *offp, int proto)
  */  
 static int  
 frag6_in(struct mbuf **mp, int *offp)  
 {  {
         struct rtentry *rt;          struct rtentry *rt;
         struct mbuf *m = *mp, *t;          struct mbuf *m = *mp, *t;
Line 137  frag6_in(struct mbuf **mp, int *offp)
Line 136  frag6_in(struct mbuf **mp, int *offp)
         ip6 = mtod(m, struct ip6_hdr *);          ip6 = mtod(m, struct ip6_hdr *);
         IP6_EXTHDR_GET(ip6f, struct ip6_frag *, m, offset, sizeof(*ip6f));          IP6_EXTHDR_GET(ip6f, struct ip6_frag *, m, offset, sizeof(*ip6f));
         if (ip6f == NULL)          if (ip6f == NULL)
                 return -1;                  return IPPROTO_DONE;
   
         dstifp = NULL;          dstifp = NULL;
         /* find the destination interface of the packet. */          /* find the destination interface of the packet. */
Line 149  frag6_in(struct mbuf **mp, int *offp)
Line 148  frag6_in(struct mbuf **mp, int *offp)
         if (ip6->ip6_plen == 0) {          if (ip6->ip6_plen == 0) {
                 icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, offset);                  icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, offset);
                 in6_ifstat_inc(dstifp, ifs6_reass_fail);                  in6_ifstat_inc(dstifp, ifs6_reass_fail);
                 return -1;                  return IPPROTO_DONE;
         }          }
   
         /*          /*
Line 163  frag6_in(struct mbuf **mp, int *offp)
Line 162  frag6_in(struct mbuf **mp, int *offp)
                 icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER,                  icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER,
                     offsetof(struct ip6_hdr, ip6_plen));                      offsetof(struct ip6_hdr, ip6_plen));
                 in6_ifstat_inc(dstifp, ifs6_reass_fail);                  in6_ifstat_inc(dstifp, ifs6_reass_fail);
                 return -1;                  return IPPROTO_DONE;
         }          }
   
         IP6_STATINC(IP6_STAT_FRAGMENTS);          IP6_STATINC(IP6_STAT_FRAGMENTS);
Line 208  frag6_in(struct mbuf **mp, int *offp)
Line 207  frag6_in(struct mbuf **mp, int *offp)
                 else if (frag6_nfragpackets >= (u_int)ip6_maxfragpackets)                  else if (frag6_nfragpackets >= (u_int)ip6_maxfragpackets)
                         goto dropfrag;                          goto dropfrag;
                 frag6_nfragpackets++;                  frag6_nfragpackets++;
                 q6 = (struct ip6q *)malloc(sizeof(struct ip6q), M_FTABLE,  
                     M_DONTWAIT);                  q6 = kmem_intr_zalloc(sizeof(struct ip6q), KM_NOSLEEP);
                 if (q6 == NULL)                  if (q6 == NULL) {
                         goto dropfrag;                          goto dropfrag;
                 memset(q6, 0, sizeof(*q6));                  }
                 frag6_insque(q6, &ip6q);                  frag6_insque(q6, &ip6q);
   
                 /* ip6q_nxt will be filled afterwards, from 1st fragment */                  /* ip6q_nxt will be filled afterwards, from 1st fragment */
Line 254  frag6_in(struct mbuf **mp, int *offp)
Line 253  frag6_in(struct mbuf **mp, int *offp)
                         icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER,                          icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER,
                             offset - sizeof(struct ip6_frag) +                              offset - sizeof(struct ip6_frag) +
                             offsetof(struct ip6_frag, ip6f_offlg));                              offsetof(struct ip6_frag, ip6f_offlg));
                         return -1;                          return IPPROTO_DONE;
                 }                  }
         } else if (fragoff + frgpartlen > IPV6_MAXPACKET) {          } else if (fragoff + frgpartlen > IPV6_MAXPACKET) {
                 mutex_exit(&frag6_lock);                  mutex_exit(&frag6_lock);
                 icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER,                  icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER,
                             offset - sizeof(struct ip6_frag) +                              offset - sizeof(struct ip6_frag) +
                                 offsetof(struct ip6_frag, ip6f_offlg));                                  offsetof(struct ip6_frag, ip6f_offlg));
                 return -1;                  return IPPROTO_DONE;
         }          }
         /*          /*
          * If it's the first fragment, do the above check for each           * If it's the first fragment, do the above check for each
Line 280  frag6_in(struct mbuf **mp, int *offp)
Line 279  frag6_in(struct mbuf **mp, int *offp)
   
                                 /* dequeue the fragment. */                                  /* dequeue the fragment. */
                                 frag6_deq(af6);                                  frag6_deq(af6);
                                 free(af6, M_FTABLE);                                  kmem_intr_free(af6, sizeof(struct ip6asfrag));
   
                                 /* adjust pointer. */                                  /* adjust pointer. */
                                 ip6err = mtod(merr, struct ip6_hdr *);                                  ip6err = mtod(merr, struct ip6_hdr *);
Line 300  frag6_in(struct mbuf **mp, int *offp)
Line 299  frag6_in(struct mbuf **mp, int *offp)
                 }                  }
         }          }
   
         ip6af = (struct ip6asfrag *)malloc(sizeof(struct ip6asfrag), M_FTABLE,          ip6af = kmem_intr_zalloc(sizeof(struct ip6asfrag), KM_NOSLEEP);
             M_DONTWAIT);          if (ip6af == NULL) {
         if (ip6af == NULL)  
                 goto dropfrag;                  goto dropfrag;
         memset(ip6af, 0, sizeof(*ip6af));          }
         ip6af->ip6af_head = ip6->ip6_flow;          ip6af->ip6af_head = ip6->ip6_flow;
         ip6af->ip6af_len = ip6->ip6_plen;          ip6af->ip6af_len = ip6->ip6_plen;
         ip6af->ip6af_nxt = ip6->ip6_nxt;          ip6af->ip6af_nxt = ip6->ip6_nxt;
Line 328  frag6_in(struct mbuf **mp, int *offp)
Line 326  frag6_in(struct mbuf **mp, int *offp)
                 if (af6->ip6af_off > ip6af->ip6af_off)                  if (af6->ip6af_off > ip6af->ip6af_off)
                         break;                          break;
   
 #if 0  
         /*          /*
          * If there is a preceding segment, it may provide some of           * If the incoming fragment overlaps some existing fragments in
          * our data already.  If so, drop the data from the incoming           * the reassembly queue - drop it as per RFC 5722.
          * segment.  If it provides all of our data, drop us.  
          */           */
         if (af6->ip6af_up != (struct ip6asfrag *)q6) {          if (af6->ip6af_up != (struct ip6asfrag *)q6) {
                 i = af6->ip6af_up->ip6af_off + af6->ip6af_up->ip6af_frglen                  i = af6->ip6af_up->ip6af_off + af6->ip6af_up->ip6af_frglen
                         - ip6af->ip6af_off;                          - ip6af->ip6af_off;
                 if (i > 0) {                  if (i > 0) {
                         if (i >= ip6af->ip6af_frglen)                          kmem_intr_free(ip6af, sizeof(struct ip6asfrag));
                                 goto dropfrag;  
                         m_adj(IP6_REASS_MBUF(ip6af), i);  
                         ip6af->ip6af_off += i;  
                         ip6af->ip6af_frglen -= i;  
                 }  
         }  
   
         /*  
          * While we overlap succeeding segments trim them or,  
          * if they are completely covered, dequeue them.  
          */  
         while (af6 != (struct ip6asfrag *)q6 &&  
                ip6af->ip6af_off + ip6af->ip6af_frglen > af6->ip6af_off) {  
                 i = (ip6af->ip6af_off + ip6af->ip6af_frglen) - af6->ip6af_off;  
                 if (i < af6->ip6af_frglen) {  
                         af6->ip6af_frglen -= i;  
                         af6->ip6af_off += i;  
                         m_adj(IP6_REASS_MBUF(af6), i);  
                         break;  
                 }  
                 af6 = af6->ip6af_down;  
                 m_freem(IP6_REASS_MBUF(af6->ip6af_up));  
                 frag6_deq(af6->ip6af_up);  
         }  
 #else  
         /*  
          * If the incoming framgent overlaps some existing fragments in  
          * the reassembly queue, drop it, since it is dangerous to override  
          * existing fragments from a security point of view.  
          * We don't know which fragment is the bad guy - here we trust  
          * fragment that came in earlier, with no real reason.  
          */  
         if (af6->ip6af_up != (struct ip6asfrag *)q6) {  
                 i = af6->ip6af_up->ip6af_off + af6->ip6af_up->ip6af_frglen  
                         - ip6af->ip6af_off;  
                 if (i > 0) {  
 #if 0                           /* suppress the noisy log */  
                         log(LOG_ERR, "%d bytes of a fragment from %s "  
                             "overlaps the previous fragment\n",  
                             i, ip6_sprintf(&q6->ip6q_src));  
 #endif  
                         free(ip6af, M_FTABLE);  
                         goto dropfrag;                          goto dropfrag;
                 }                  }
         }          }
         if (af6 != (struct ip6asfrag *)q6) {          if (af6 != (struct ip6asfrag *)q6) {
                 i = (ip6af->ip6af_off + ip6af->ip6af_frglen) - af6->ip6af_off;                  i = (ip6af->ip6af_off + ip6af->ip6af_frglen) - af6->ip6af_off;
                 if (i > 0) {                  if (i > 0) {
 #if 0                           /* suppress the noisy log */                          kmem_intr_free(ip6af, sizeof(struct ip6asfrag));
                         log(LOG_ERR, "%d bytes of a fragment from %s "  
                             "overlaps the succeeding fragment",  
                             i, ip6_sprintf(&q6->ip6q_src));  
 #endif  
                         free(ip6af, M_FTABLE);  
                         goto dropfrag;                          goto dropfrag;
                 }                  }
         }          }
 #endif  
   
 insert:  insert:
   
Line 420  insert:
Line 368  insert:
              af6 = af6->ip6af_down) {               af6 = af6->ip6af_down) {
                 if (af6->ip6af_off != next) {                  if (af6->ip6af_off != next) {
                         mutex_exit(&frag6_lock);                          mutex_exit(&frag6_lock);
                         return 0;                          return IPPROTO_DONE;
                 }                  }
                 next += af6->ip6af_frglen;                  next += af6->ip6af_frglen;
         }          }
         if (af6->ip6af_up->ip6af_mff) {          if (af6->ip6af_up->ip6af_mff) {
                 mutex_exit(&frag6_lock);                  mutex_exit(&frag6_lock);
                 return 0;                  return IPPROTO_DONE;
         }          }
   
         /*          /*
Line 443  insert:
Line 391  insert:
                         t = t->m_next;                          t = t->m_next;
                 t->m_next = IP6_REASS_MBUF(af6);                  t->m_next = IP6_REASS_MBUF(af6);
                 m_adj(t->m_next, af6->ip6af_offset);                  m_adj(t->m_next, af6->ip6af_offset);
                 free(af6, M_FTABLE);                  kmem_intr_free(af6, sizeof(struct ip6asfrag));
                 af6 = af6dwn;                  af6 = af6dwn;
         }          }
   
         /* adjust offset to point where the original next header starts */          /* adjust offset to point where the original next header starts */
         offset = ip6af->ip6af_offset - sizeof(struct ip6_frag);          offset = ip6af->ip6af_offset - sizeof(struct ip6_frag);
         free(ip6af, M_FTABLE);          kmem_intr_free(ip6af, sizeof(struct ip6asfrag));
         ip6 = mtod(m, struct ip6_hdr *);          ip6 = mtod(m, struct ip6_hdr *);
         ip6->ip6_plen = htons(next + offset - sizeof(struct ip6_hdr));          ip6->ip6_plen = htons(next + offset - sizeof(struct ip6_hdr));
         ip6->ip6_src = q6->ip6q_src;          ip6->ip6_src = q6->ip6q_src;
Line 471  insert:
Line 419  insert:
                 if ((t = m_split(m, offset, M_DONTWAIT)) == NULL) {                  if ((t = m_split(m, offset, M_DONTWAIT)) == NULL) {
                         frag6_remque(q6);                          frag6_remque(q6);
                         frag6_nfrags -= q6->ip6q_nfrag;                          frag6_nfrags -= q6->ip6q_nfrag;
                         free(q6, M_FTABLE);                          kmem_intr_free(q6, sizeof(struct ip6q));
                         frag6_nfragpackets--;                          frag6_nfragpackets--;
                         goto dropfrag;                          goto dropfrag;
                 }                  }
Line 489  insert:
Line 437  insert:
   
         frag6_remque(q6);          frag6_remque(q6);
         frag6_nfrags -= q6->ip6q_nfrag;          frag6_nfrags -= q6->ip6q_nfrag;
         free(q6, M_FTABLE);          kmem_intr_free(q6, sizeof(struct ip6q));
         frag6_nfragpackets--;          frag6_nfragpackets--;
   
         if (m->m_flags & M_PKTHDR) { /* Isn't it always true? */          if (m->m_flags & M_PKTHDR) { /* Isn't it always true? */
Line 517  insert:
Line 465  insert:
         in6_ifstat_inc(dstifp, ifs6_reass_fail);          in6_ifstat_inc(dstifp, ifs6_reass_fail);
         IP6_STATINC(IP6_STAT_FRAGDROPPED);          IP6_STATINC(IP6_STAT_FRAGDROPPED);
         m_freem(m);          m_freem(m);
         return -1;  
 }  
   
 int  
 frag6_input(struct mbuf **mp, int *offp, int proto)  
 {  
         int ret = frag6_in(mp, offp);  
   
         if (ret > 0) {  
                 return ret;  
         }  
         return IPPROTO_DONE;          return IPPROTO_DONE;
 }  }
   
 int  int
 ip6_reass_packet(struct mbuf **mp, int offset)  ip6_reass_packet(struct mbuf **mp, int offset)
 {  {
         int ret = frag6_in(mp, &offset);  
   
         if (ret <= 0) {          if (frag6_input(mp, &offset, IPPROTO_IPV6) == IPPROTO_DONE) {
                 *mp = NULL;                  *mp = NULL;
                   return EINVAL;
         }          }
         return ret < 0 ? ret : 0;          return 0;
 }  }
   
 /*  /*
Line 576  frag6_freef(struct ip6q *q6)
Line 513  frag6_freef(struct ip6q *q6)
   
                         icmp6_error(m, ICMP6_TIME_EXCEEDED,                          icmp6_error(m, ICMP6_TIME_EXCEEDED,
                                     ICMP6_TIME_EXCEED_REASSEMBLY, 0);                                      ICMP6_TIME_EXCEED_REASSEMBLY, 0);
                 } else                  } else {
                         m_freem(m);                          m_freem(m);
                 free(af6, M_FTABLE);                  }
                   kmem_intr_free(af6, sizeof(struct ip6asfrag));
         }          }
         frag6_remque(q6);          frag6_remque(q6);
         frag6_nfrags -= q6->ip6q_nfrag;          frag6_nfrags -= q6->ip6q_nfrag;
         free(q6, M_FTABLE);          kmem_intr_free(q6, sizeof(struct ip6q));
         frag6_nfragpackets--;          frag6_nfragpackets--;
 }  }
   

Legend:
Removed from v.1.52  
changed lines
  Added in v.1.53

CVSweb <webmaster@jp.NetBSD.org>