[BACK]Return to ip6_input.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/ip6_input.c between version 1.178.2.9 and 1.180

version 1.178.2.9, 2019/09/24 18:27:09 version 1.180, 2017/07/06 17:14:35
Line 69  __KERNEL_RCSID(0, "$NetBSD$");
Line 69  __KERNEL_RCSID(0, "$NetBSD$");
 #include "opt_inet.h"  #include "opt_inet.h"
 #include "opt_inet6.h"  #include "opt_inet6.h"
 #include "opt_ipsec.h"  #include "opt_ipsec.h"
 #include "opt_compat_netbsd.h"  
 #include "opt_net_mpsafe.h"  #include "opt_net_mpsafe.h"
 #endif  #endif
   
Line 120  __KERNEL_RCSID(0, "$NetBSD$");
Line 119  __KERNEL_RCSID(0, "$NetBSD$");
 #include <netipsec/key.h>  #include <netipsec/key.h>
 #endif /* IPSEC */  #endif /* IPSEC */
   
 #ifdef COMPAT_50  
 #include <compat/sys/time.h>  
 #include <compat/sys/socket.h>  
 #endif  
   
 #include <netinet6/ip6protosw.h>  #include <netinet6/ip6protosw.h>
   
 #include "faith.h"  #include "faith.h"
Line 205  ip6_init(void)
Line 199  ip6_init(void)
         KASSERT(inet6_pfil_hook != NULL);          KASSERT(inet6_pfil_hook != NULL);
   
         ip6stat_percpu = percpu_alloc(sizeof(uint64_t) * IP6_NSTATS);          ip6stat_percpu = percpu_alloc(sizeof(uint64_t) * IP6_NSTATS);
         ip6_forward_rt_percpu = rtcache_percpu_alloc();          ip6_forward_rt_percpu = percpu_alloc(sizeof(struct route));
 }  }
   
 static void  static void
Line 228  ip6intr(void *arg __unused)
Line 222  ip6intr(void *arg __unused)
 {  {
         struct mbuf *m;          struct mbuf *m;
   
         SOFTNET_KERNEL_LOCK_UNLESS_NET_MPSAFE();  #ifndef NET_MPSAFE
           mutex_enter(softnet_lock);
   #endif
         while ((m = pktq_dequeue(ip6_pktq)) != NULL) {          while ((m = pktq_dequeue(ip6_pktq)) != NULL) {
                 struct psref psref;                  struct psref psref;
                 struct ifnet *rcvif = m_get_rcvif_psref(m, &psref);                  struct ifnet *rcvif = m_get_rcvif_psref(m, &psref);
Line 248  ip6intr(void *arg __unused)
Line 244  ip6intr(void *arg __unused)
                 ip6_input(m, rcvif);                  ip6_input(m, rcvif);
                 m_put_rcvif_psref(rcvif, &psref);                  m_put_rcvif_psref(rcvif, &psref);
         }          }
         SOFTNET_KERNEL_UNLOCK_UNLESS_NET_MPSAFE();  #ifndef NET_MPSAFE
           mutex_exit(softnet_lock);
   #endif
 }  }
   
 void  void
Line 258  ip6_input(struct mbuf *m, struct ifnet *
Line 256  ip6_input(struct mbuf *m, struct ifnet *
         int hit, off = sizeof(struct ip6_hdr), nest;          int hit, off = sizeof(struct ip6_hdr), nest;
         u_int32_t plen;          u_int32_t plen;
         u_int32_t rtalert = ~0;          u_int32_t rtalert = ~0;
         int nxt, ours = 0, rh_present = 0, frg_present;          int nxt, ours = 0, rh_present = 0;
         struct ifnet *deliverifp = NULL;          struct ifnet *deliverifp = NULL;
         int srcrt = 0;          int srcrt = 0;
         struct rtentry *rt = NULL;          struct rtentry *rt = NULL;
Line 358  ip6_input(struct mbuf *m, struct ifnet *
Line 356  ip6_input(struct mbuf *m, struct ifnet *
                         return;                          return;
                 if (m == NULL)                  if (m == NULL)
                         return;                          return;
                 if (__predict_false(m->m_len < sizeof(struct ip6_hdr))) {  
                         if ((m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL) {  
                                 IP6_STATINC(IP6_STAT_TOOSMALL);  
                                 in6_ifstat_inc(rcvif, ifs6_in_hdrerr);  
                                 return;  
                         }  
                 }  
                 ip6 = mtod(m, struct ip6_hdr *);                  ip6 = mtod(m, struct ip6_hdr *);
                 srcrt = !IN6_ARE_ADDR_EQUAL(&odst, &ip6->ip6_dst);                  srcrt = !IN6_ARE_ADDR_EQUAL(&odst, &ip6->ip6_dst);
         }          }
Line 453  ip6_input(struct mbuf *m, struct ifnet *
Line 444  ip6_input(struct mbuf *m, struct ifnet *
                 goto bad;                  goto bad;
         }          }
   
         ro = rtcache_percpu_getref(ip6_forward_rt_percpu);          ro = percpu_getref(ip6_forward_rt_percpu);
         /*          /*
          * Multicast check           * Multicast check
          */           */
Line 514  ip6_input(struct mbuf *m, struct ifnet *
Line 505  ip6_input(struct mbuf *m, struct ifnet *
 #endif  #endif
             rt->rt_ifp->if_type == IFT_LOOP) {              rt->rt_ifp->if_type == IFT_LOOP) {
                 struct in6_ifaddr *ia6 = (struct in6_ifaddr *)rt->rt_ifa;                  struct in6_ifaddr *ia6 = (struct in6_ifaddr *)rt->rt_ifa;
                 int addrok;  
   
                 if (ia6->ia6_flags & IN6_IFF_ANYCAST)                  if (ia6->ia6_flags & IN6_IFF_ANYCAST)
                         m->m_flags |= M_ANYCAST6;                          m->m_flags |= M_ANYCAST6;
                 /*                  /*
                  * packets to a tentative, duplicated, or somehow invalid                   * packets to a tentative, duplicated, or somehow invalid
                  * address must not be accepted.                   * address must not be accepted.
                  */                   */
                 if (ia6->ia6_flags & IN6_IFF_NOTREADY)                  if (!(ia6->ia6_flags & (IN6_IFF_NOTREADY | IN6_IFF_DETACHED))) {
                         addrok = 0;  
                 else if (ia6->ia6_flags & IN6_IFF_DETACHED &&  
                     !IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src))  
                 {  
                         /* Allow internal traffic to DETACHED addresses */  
                         struct sockaddr_in6 sin6;  
                         int s;  
   
                         memset(&sin6, 0, sizeof(sin6));  
                         sin6.sin6_family = AF_INET6;  
                         sin6.sin6_len = sizeof(sin6);  
                         sin6.sin6_addr = ip6->ip6_src;  
                         s = pserialize_read_enter();  
                         addrok = (ifa_ifwithaddr(sin6tosa(&sin6)) != NULL);  
                         pserialize_read_exit(s);  
                 } else  
                         addrok = 1;  
                 if (addrok) {  
                         /* this address is ready */                          /* this address is ready */
                         ours = 1;                          ours = 1;
                         deliverifp = ia6->ia_ifp;       /* correct? */                          deliverifp = ia6->ia_ifp;       /* correct? */
Line 639  ip6_input(struct mbuf *m, struct ifnet *
Line 610  ip6_input(struct mbuf *m, struct ifnet *
                         in6_ifstat_inc(rcvif, ifs6_in_discard);                          in6_ifstat_inc(rcvif, ifs6_in_discard);
 #endif  #endif
                         rtcache_unref(rt, ro);                          rtcache_unref(rt, ro);
                         rtcache_percpu_putref(ip6_forward_rt_percpu);                          percpu_putref(ip6_forward_rt_percpu);
                         return; /* m have already been freed */                          return; /* m have already been freed */
                 }                  }
   
Line 664  ip6_input(struct mbuf *m, struct ifnet *
Line 635  ip6_input(struct mbuf *m, struct ifnet *
                                     ICMP6_PARAMPROB_HEADER,                                      ICMP6_PARAMPROB_HEADER,
                                     (char *)&ip6->ip6_plen - (char *)ip6);                                      (char *)&ip6->ip6_plen - (char *)ip6);
                         rtcache_unref(rt, ro);                          rtcache_unref(rt, ro);
                         rtcache_percpu_putref(ip6_forward_rt_percpu);                          percpu_putref(ip6_forward_rt_percpu);
                         return;                          return;
                 }                  }
                 IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m, sizeof(struct ip6_hdr),                  IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m, sizeof(struct ip6_hdr),
Line 672  ip6_input(struct mbuf *m, struct ifnet *
Line 643  ip6_input(struct mbuf *m, struct ifnet *
                 if (hbh == NULL) {                  if (hbh == NULL) {
                         IP6_STATINC(IP6_STAT_TOOSHORT);                          IP6_STATINC(IP6_STAT_TOOSHORT);
                         rtcache_unref(rt, ro);                          rtcache_unref(rt, ro);
                         rtcache_percpu_putref(ip6_forward_rt_percpu);                          percpu_putref(ip6_forward_rt_percpu);
                         return;                          return;
                 }                  }
                 KASSERT(IP6_HDR_ALIGNED_P(hbh));                  KASSERT(IP6_HDR_ALIGNED_P(hbh));
Line 727  ip6_input(struct mbuf *m, struct ifnet *
Line 698  ip6_input(struct mbuf *m, struct ifnet *
   
                         if (error != 0) {                          if (error != 0) {
                                 rtcache_unref(rt, ro);                                  rtcache_unref(rt, ro);
                                 rtcache_percpu_putref(ip6_forward_rt_percpu);                                  percpu_putref(ip6_forward_rt_percpu);
                                 IP6_STATINC(IP6_STAT_CANTFORWARD);                                  IP6_STATINC(IP6_STAT_CANTFORWARD);
                                 goto bad;                                  goto bad;
                         }                          }
Line 736  ip6_input(struct mbuf *m, struct ifnet *
Line 707  ip6_input(struct mbuf *m, struct ifnet *
                         goto bad_unref;                          goto bad_unref;
         } else if (!ours) {          } else if (!ours) {
                 rtcache_unref(rt, ro);                  rtcache_unref(rt, ro);
                 rtcache_percpu_putref(ip6_forward_rt_percpu);                  percpu_putref(ip6_forward_rt_percpu);
                 ip6_forward(m, srcrt);                  ip6_forward(m, srcrt);
                 return;                  return;
         }          }
Line 780  ip6_input(struct mbuf *m, struct ifnet *
Line 751  ip6_input(struct mbuf *m, struct ifnet *
                 rtcache_unref(rt, ro);                  rtcache_unref(rt, ro);
                 rt = NULL;                  rt = NULL;
         }          }
         rtcache_percpu_putref(ip6_forward_rt_percpu);          percpu_putref(ip6_forward_rt_percpu);
   
         rh_present = 0;          rh_present = 0;
         frg_present = 0;  
         while (nxt != IPPROTO_DONE) {          while (nxt != IPPROTO_DONE) {
                 if (ip6_hdrnestlimit && (++nest > ip6_hdrnestlimit)) {                  if (ip6_hdrnestlimit && (++nest > ip6_hdrnestlimit)) {
                         IP6_STATINC(IP6_STAT_TOOMANYHDR);                          IP6_STATINC(IP6_STAT_TOOMANYHDR);
Line 807  ip6_input(struct mbuf *m, struct ifnet *
Line 777  ip6_input(struct mbuf *m, struct ifnet *
                                 IP6_STATINC(IP6_STAT_BADOPTIONS);                                  IP6_STATINC(IP6_STAT_BADOPTIONS);
                                 goto bad;                                  goto bad;
                         }                          }
                 } else if (nxt == IPPROTO_FRAGMENT) {  
                         if (frg_present++) {  
                                 in6_ifstat_inc(rcvif, ifs6_in_hdrerr);  
                                 IP6_STATINC(IP6_STAT_BADOPTIONS);  
                                 goto bad;  
                         }  
                 }                  }
   
 #ifdef IPSEC  #ifdef IPSEC
Line 826  ip6_input(struct mbuf *m, struct ifnet *
Line 790  ip6_input(struct mbuf *m, struct ifnet *
                             & PR_LASTHDR) != 0) {                              & PR_LASTHDR) != 0) {
                                 int error;                                  int error;
   
                                   SOFTNET_LOCK();
                                 error = ipsec6_input(m);                                  error = ipsec6_input(m);
                                   SOFTNET_UNLOCK();
                                 if (error)                                  if (error)
                                         goto bad;                                          goto bad;
                         }                          }
                 }                  }
 #endif /* IPSEC */  #endif /* IPSEC */
   
                   SOFTNET_LOCK();
                 nxt = (*inet6sw[ip6_protox[nxt]].pr_input)(&m, &off, nxt);                  nxt = (*inet6sw[ip6_protox[nxt]].pr_input)(&m, &off, nxt);
                   SOFTNET_UNLOCK();
         }          }
         return;          return;
   
  bad_unref:   bad_unref:
         rtcache_unref(rt, ro);          rtcache_unref(rt, ro);
         rtcache_percpu_putref(ip6_forward_rt_percpu);          percpu_putref(ip6_forward_rt_percpu);
  bad:   bad:
         m_freem(m);          m_freem(m);
         return;          return;
Line 1111  void
Line 1079  void
 ip6_savecontrol(struct in6pcb *in6p, struct mbuf **mp,  ip6_savecontrol(struct in6pcb *in6p, struct mbuf **mp,
         struct ip6_hdr *ip6, struct mbuf *m)          struct ip6_hdr *ip6, struct mbuf *m)
 {  {
           struct socket *so = in6p->in6p_socket;
 #ifdef RFC2292  #ifdef RFC2292
 #define IS2292(x, y)    ((in6p->in6p_flags & IN6P_RFC2292) ? (x) : (y))  #define IS2292(x, y)    ((in6p->in6p_flags & IN6P_RFC2292) ? (x) : (y))
 #else  #else
 #define IS2292(x, y)    (y)  #define IS2292(x, y)    (y)
 #endif  #endif
   
         if (in6p->in6p_socket->so_options & SO_TIMESTAMP          if (SOOPT_TIMESTAMP(so->so_options))
 #ifdef SO_OTIMESTAMP                  mp = sbsavetimestamp(so->so_options, m, mp);
             || in6p->in6p_socket->so_options & SO_OTIMESTAMP  
 #endif  
         ) {  
                 struct timeval tv;  
   
                 microtime(&tv);  
 #ifdef SO_OTIMESTAMP  
                 if (in6p->in6p_socket->so_options & SO_OTIMESTAMP) {  
                         struct timeval50 tv50;  
                         timeval_to_timeval50(&tv, &tv50);  
                         *mp = sbcreatecontrol((void *) &tv50, sizeof(tv50),  
                             SCM_OTIMESTAMP, SOL_SOCKET);  
                 } else  
 #endif  
                 *mp = sbcreatecontrol((void *) &tv, sizeof(tv),  
                     SCM_TIMESTAMP, SOL_SOCKET);  
                 if (*mp)  
                         mp = &(*mp)->m_next;  
         }  
   
         /* some OSes call this logic with IPv4 packet, for SO_TIMESTAMP */          /* some OSes call this logic with IPv4 packet, for SO_TIMESTAMP */
         if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION)          if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION)
Line 1150  ip6_savecontrol(struct in6pcb *in6p, str
Line 1100  ip6_savecontrol(struct in6pcb *in6p, str
                 memcpy(&pi6.ipi6_addr, &ip6->ip6_dst, sizeof(struct in6_addr));                  memcpy(&pi6.ipi6_addr, &ip6->ip6_dst, sizeof(struct in6_addr));
                 in6_clearscope(&pi6.ipi6_addr); /* XXX */                  in6_clearscope(&pi6.ipi6_addr); /* XXX */
                 pi6.ipi6_ifindex = m->m_pkthdr.rcvif_index;                  pi6.ipi6_ifindex = m->m_pkthdr.rcvif_index;
                 *mp = sbcreatecontrol((void *) &pi6,                  *mp = sbcreatecontrol(&pi6, sizeof(pi6),
                     sizeof(struct in6_pktinfo),  
                     IS2292(IPV6_2292PKTINFO, IPV6_PKTINFO), IPPROTO_IPV6);                      IS2292(IPV6_2292PKTINFO, IPV6_PKTINFO), IPPROTO_IPV6);
                 if (*mp)                  if (*mp)
                         mp = &(*mp)->m_next;                          mp = &(*mp)->m_next;
Line 1160  ip6_savecontrol(struct in6pcb *in6p, str
Line 1109  ip6_savecontrol(struct in6pcb *in6p, str
         if (in6p->in6p_flags & IN6P_HOPLIMIT) {          if (in6p->in6p_flags & IN6P_HOPLIMIT) {
                 int hlim = ip6->ip6_hlim & 0xff;                  int hlim = ip6->ip6_hlim & 0xff;
   
                 *mp = sbcreatecontrol((void *) &hlim, sizeof(int),                  *mp = sbcreatecontrol(&hlim, sizeof(hlim),
                     IS2292(IPV6_2292HOPLIMIT, IPV6_HOPLIMIT), IPPROTO_IPV6);                      IS2292(IPV6_2292HOPLIMIT, IPV6_HOPLIMIT), IPPROTO_IPV6);
                 if (*mp)                  if (*mp)
                         mp = &(*mp)->m_next;                          mp = &(*mp)->m_next;
Line 1174  ip6_savecontrol(struct in6pcb *in6p, str
Line 1123  ip6_savecontrol(struct in6pcb *in6p, str
                 flowinfo >>= 20;                  flowinfo >>= 20;
   
                 tclass = flowinfo & 0xff;                  tclass = flowinfo & 0xff;
                 *mp = sbcreatecontrol((void *)&tclass, sizeof(tclass),                  *mp = sbcreatecontrol(&tclass, sizeof(tclass),
                     IPV6_TCLASS, IPPROTO_IPV6);                      IPV6_TCLASS, IPPROTO_IPV6);
   
                 if (*mp)                  if (*mp)
Line 1222  ip6_savecontrol(struct in6pcb *in6p, str
Line 1171  ip6_savecontrol(struct in6pcb *in6p, str
                          * be removed before returning in the RFC 2292.                           * be removed before returning in the RFC 2292.
                          * Note: this constraint is removed in RFC3542.                           * Note: this constraint is removed in RFC3542.
                          */                           */
                         *mp = sbcreatecontrol((void *)hbh, hbhlen,                          *mp = sbcreatecontrol(hbh, hbhlen,
                             IS2292(IPV6_2292HOPOPTS, IPV6_HOPOPTS),                              IS2292(IPV6_2292HOPOPTS, IPV6_HOPOPTS),
                             IPPROTO_IPV6);                              IPPROTO_IPV6);
                         if (*mp)                          if (*mp)
Line 1284  ip6_savecontrol(struct in6pcb *in6p, str
Line 1233  ip6_savecontrol(struct in6pcb *in6p, str
                                 if (!(in6p->in6p_flags & IN6P_DSTOPTS))                                  if (!(in6p->in6p_flags & IN6P_DSTOPTS))
                                         break;                                          break;
   
                                 *mp = sbcreatecontrol((void *)ip6e, elen,                                  *mp = sbcreatecontrol(ip6e, elen,
                                     IS2292(IPV6_2292DSTOPTS, IPV6_DSTOPTS),                                      IS2292(IPV6_2292DSTOPTS, IPV6_DSTOPTS),
                                     IPPROTO_IPV6);                                      IPPROTO_IPV6);
                                 if (*mp)                                  if (*mp)
Line 1295  ip6_savecontrol(struct in6pcb *in6p, str
Line 1244  ip6_savecontrol(struct in6pcb *in6p, str
                                 if (!(in6p->in6p_flags & IN6P_RTHDR))                                  if (!(in6p->in6p_flags & IN6P_RTHDR))
                                         break;                                          break;
   
                                 *mp = sbcreatecontrol((void *)ip6e, elen,                                  *mp = sbcreatecontrol(ip6e, elen,
                                     IS2292(IPV6_2292RTHDR, IPV6_RTHDR),                                      IS2292(IPV6_2292RTHDR, IPV6_RTHDR),
                                     IPPROTO_IPV6);                                      IPPROTO_IPV6);
                                 if (*mp)                                  if (*mp)
Line 1353  ip6_notify_pmtu(struct in6pcb *in6p, con
Line 1302  ip6_notify_pmtu(struct in6pcb *in6p, con
         if (sa6_recoverscope(&mtuctl.ip6m_addr))          if (sa6_recoverscope(&mtuctl.ip6m_addr))
                 return;                  return;
   
         if ((m_mtu = sbcreatecontrol((void *)&mtuctl, sizeof(mtuctl),          if ((m_mtu = sbcreatecontrol(&mtuctl, sizeof(mtuctl),
             IPV6_PATHMTU, IPPROTO_IPV6)) == NULL)              IPV6_PATHMTU, IPPROTO_IPV6)) == NULL)
                 return;                  return;
   
         if (sbappendaddr(&so->so_rcv, (const struct sockaddr *)dst, NULL, m_mtu)          if (sbappendaddr(&so->so_rcv, (const struct sockaddr *)dst, NULL, m_mtu)
             == 0) {              == 0) {
                 soroverflow(so);  
                 m_freem(m_mtu);                  m_freem(m_mtu);
                   /* XXX: should count statistics */
         } else          } else
                 sorwakeup(so);                  sorwakeup(so);
   
Line 1419  ip6_pullexthdr(struct mbuf *m, size_t of
Line 1368  ip6_pullexthdr(struct mbuf *m, size_t of
 }  }
   
 /*  /*
  * Get offset to the previous header followed by the header   * Get pointer to the previous header followed by the header
  * currently processed.   * currently processed.
    * XXX: This function supposes that
    *      M includes all headers,
    *      the next header field and the header length field of each header
    *      are valid, and
    *      the sum of each header length equals to OFF.
    * Because of these assumptions, this function must be called very
    * carefully. Moreover, it will not be used in the near future when
    * we develop `neater' mechanism to process extension headers.
  */   */
 int  u_int8_t *
 ip6_get_prevhdr(struct mbuf *m, int off)  ip6_get_prevhdr(struct mbuf *m, int off)
 {  {
         struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);          struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
   
         if (off == sizeof(struct ip6_hdr)) {          if (off == sizeof(struct ip6_hdr))
                 return offsetof(struct ip6_hdr, ip6_nxt);                  return (&ip6->ip6_nxt);
         } else if (off < sizeof(struct ip6_hdr)) {          else {
                 panic("%s: off < sizeof(struct ip6_hdr)", __func__);                  int len, nxt;
         } else {                  struct ip6_ext *ip6e = NULL;
                 int len, nlen, nxt;  
                 struct ip6_ext ip6e;  
   
                 nxt = ip6->ip6_nxt;                  nxt = ip6->ip6_nxt;
                 len = sizeof(struct ip6_hdr);                  len = sizeof(struct ip6_hdr);
                 nlen = 0;  
                 while (len < off) {                  while (len < off) {
                         m_copydata(m, len, sizeof(ip6e), &ip6e);                          ip6e = (struct ip6_ext *)(mtod(m, char *) + len);
   
                         switch (nxt) {                          switch (nxt) {
                         case IPPROTO_FRAGMENT:                          case IPPROTO_FRAGMENT:
                                 nlen = sizeof(struct ip6_frag);                                  len += sizeof(struct ip6_frag);
                                 break;                                  break;
                         case IPPROTO_AH:                          case IPPROTO_AH:
                                 nlen = (ip6e.ip6e_len + 2) << 2;                                  len += (ip6e->ip6e_len + 2) << 2;
                                 break;                                  break;
                         default:                          default:
                                 nlen = (ip6e.ip6e_len + 1) << 3;                                  len += (ip6e->ip6e_len + 1) << 3;
                                 break;                                  break;
                         }                          }
                         len += nlen;                          nxt = ip6e->ip6e_nxt;
                         nxt = ip6e.ip6e_nxt;  
                 }                  }
                   if (ip6e)
                 return (len - nlen);                          return (&ip6e->ip6e_nxt);
                   else
                           return NULL;
         }          }
 }  }
   

Legend:
Removed from v.1.178.2.9  
changed lines
  Added in v.1.180

CVSweb <webmaster@jp.NetBSD.org>