in6_gif.c revision 1.12
1/* $NetBSD: in6_gif.c,v 1.12 2000/02/07 06:15:17 itojun Exp $ */ 2 3/* 4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the project nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32/* 33 * in6_gif.c 34 */ 35 36#include "opt_inet.h" 37#include "opt_ipsec.h" 38 39#include <sys/param.h> 40#include <sys/systm.h> 41#include <sys/socket.h> 42#include <sys/sockio.h> 43#include <sys/mbuf.h> 44#include <sys/errno.h> 45#include <sys/ioctl.h> 46#include <sys/protosw.h> 47 48#include <net/if.h> 49#include <net/route.h> 50 51#include <netinet/in.h> 52#include <netinet/in_systm.h> 53#ifdef INET 54#include <netinet/ip.h> 55#endif 56#ifdef INET6 57#include <netinet/ip6.h> 58#include <netinet6/ip6_var.h> 59#include <netinet6/in6_gif.h> 60#endif 61#include <netinet/ip_ecn.h> 62 63#include <net/if_gif.h> 64 65#include <net/net_osdep.h> 66 67int 68in6_gif_output(ifp, family, m, rt) 69 struct ifnet *ifp; 70 int family; /* family of the packet to be encapsulate. */ 71 struct mbuf *m; 72 struct rtentry *rt; 73{ 74 struct gif_softc *sc = (struct gif_softc*)ifp; 75 struct sockaddr_in6 *dst = (struct sockaddr_in6 *)&sc->gif_ro6.ro_dst; 76 struct sockaddr_in6 *sin6_src = (struct sockaddr_in6 *)sc->gif_psrc; 77 struct sockaddr_in6 *sin6_dst = (struct sockaddr_in6 *)sc->gif_pdst; 78 struct ip6_hdr *ip6; 79 int proto; 80 u_int8_t itos, otos; 81 82 if (sin6_src == NULL || sin6_dst == NULL || 83 sin6_src->sin6_family != AF_INET6 || 84 sin6_dst->sin6_family != AF_INET6) { 85 m_freem(m); 86 return EAFNOSUPPORT; 87 } 88 89 switch (family) { 90#ifdef INET 91 case AF_INET: 92 { 93 struct ip *ip; 94 95 proto = IPPROTO_IPV4; 96 if (m->m_len < sizeof(*ip)) { 97 m = m_pullup(m, sizeof(*ip)); 98 if (!m) 99 return ENOBUFS; 100 } 101 ip = mtod(m, struct ip *); 102 itos = ip->ip_tos; 103 break; 104 } 105#endif 106#ifdef INET6 107 case AF_INET6: 108 { 109 struct ip6_hdr *ip6; 110 proto = IPPROTO_IPV6; 111 if (m->m_len < sizeof(*ip6)) { 112 m = m_pullup(m, sizeof(*ip6)); 113 if (!m) 114 return ENOBUFS; 115 } 116 ip6 = mtod(m, struct ip6_hdr *); 117 itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; 118 break; 119 } 120#endif 121 default: 122#ifdef DEBUG 123 printf("in6_gif_output: warning: unknown family %d passed\n", 124 family); 125#endif 126 m_freem(m); 127 return EAFNOSUPPORT; 128 } 129 130 /* prepend new IP header */ 131 M_PREPEND(m, sizeof(struct ip6_hdr), M_DONTWAIT); 132 if (m && m->m_len < sizeof(struct ip6_hdr)) 133 m = m_pullup(m, sizeof(struct ip6_hdr)); 134 if (m == NULL) { 135 printf("ENOBUFS in in6_gif_output %d\n", __LINE__); 136 return ENOBUFS; 137 } 138 139 ip6 = mtod(m, struct ip6_hdr *); 140 ip6->ip6_flow = 0; 141 ip6->ip6_vfc &= ~IPV6_VERSION_MASK; 142 ip6->ip6_vfc |= IPV6_VERSION; 143 ip6->ip6_plen = htons((u_short)m->m_pkthdr.len); 144 ip6->ip6_nxt = proto; 145 ip6->ip6_hlim = ip6_gif_hlim; 146 ip6->ip6_src = sin6_src->sin6_addr; 147 if (ifp->if_flags & IFF_LINK0) { 148 /* multi-destination mode */ 149 if (!IN6_IS_ADDR_UNSPECIFIED(&sin6_dst->sin6_addr)) 150 ip6->ip6_dst = sin6_dst->sin6_addr; 151 else if (rt) { 152 if (family != AF_INET6) { 153 m_freem(m); 154 return EINVAL; /*XXX*/ 155 } 156 ip6->ip6_dst = ((struct sockaddr_in6 *)(rt->rt_gateway))->sin6_addr; 157 } else { 158 m_freem(m); 159 return ENETUNREACH; 160 } 161 } else { 162 /* bidirectional configured tunnel mode */ 163 if (!IN6_IS_ADDR_UNSPECIFIED(&sin6_dst->sin6_addr)) 164 ip6->ip6_dst = sin6_dst->sin6_addr; 165 else { 166 m_freem(m); 167 return ENETUNREACH; 168 } 169 } 170 if (ifp->if_flags & IFF_LINK1) { 171 otos = 0; 172 ip_ecn_ingress(ECN_ALLOWED, &otos, &itos); 173 ip6->ip6_flow |= htonl((u_int32_t)otos << 20); 174 } 175 176 if (dst->sin6_family != sin6_dst->sin6_family || 177 !IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &sin6_dst->sin6_addr)) { 178 /* cache route doesn't match */ 179 bzero(dst, sizeof(*dst)); 180 dst->sin6_family = sin6_dst->sin6_family; 181 dst->sin6_len = sizeof(struct sockaddr_in6); 182 dst->sin6_addr = sin6_dst->sin6_addr; 183 if (sc->gif_ro6.ro_rt) { 184 RTFREE(sc->gif_ro6.ro_rt); 185 sc->gif_ro6.ro_rt = NULL; 186 } 187#if 0 188 sc->gif_if.if_mtu = GIF_MTU; 189#endif 190 } 191 192 if (sc->gif_ro6.ro_rt == NULL) { 193 rtalloc((struct route *)&sc->gif_ro6); 194 if (sc->gif_ro6.ro_rt == NULL) { 195 m_freem(m); 196 return ENETUNREACH; 197 } 198#if 0 199 ifp->if_mtu = sc->gif_ro6.ro_rt->rt_ifp->if_mtu 200 - sizeof(struct ip6_hdr); 201#endif 202 } 203 204#ifdef IPSEC 205 m->m_pkthdr.rcvif = NULL; 206#endif /*IPSEC*/ 207 return(ip6_output(m, 0, &sc->gif_ro6, 0, 0, NULL)); 208} 209 210int in6_gif_input(mp, offp, proto) 211 struct mbuf **mp; 212 int *offp, proto; 213{ 214 struct mbuf *m = *mp; 215 struct gif_softc *sc; 216 struct ifnet *gifp = NULL; 217 struct ip6_hdr *ip6; 218 int i; 219 int af = 0; 220 u_int32_t otos; 221 222 ip6 = mtod(m, struct ip6_hdr *); 223 224#define satoin6(sa) (((struct sockaddr_in6 *)(sa))->sin6_addr) 225 for (i = 0, sc = gif; i < ngif; i++, sc++) { 226 if (sc->gif_psrc == NULL || 227 sc->gif_pdst == NULL || 228 sc->gif_psrc->sa_family != AF_INET6 || 229 sc->gif_pdst->sa_family != AF_INET6) { 230 continue; 231 } 232 if ((sc->gif_if.if_flags & IFF_UP) == 0) 233 continue; 234 if ((sc->gif_if.if_flags & IFF_LINK0) && 235 IN6_ARE_ADDR_EQUAL(&satoin6(sc->gif_psrc), &ip6->ip6_dst) && 236 IN6_IS_ADDR_UNSPECIFIED(&satoin6(sc->gif_pdst))) { 237 gifp = &sc->gif_if; 238 continue; 239 } 240 if (IN6_ARE_ADDR_EQUAL(&satoin6(sc->gif_psrc), &ip6->ip6_dst) && 241 IN6_ARE_ADDR_EQUAL(&satoin6(sc->gif_pdst), &ip6->ip6_src)) { 242 gifp = &sc->gif_if; 243 break; 244 } 245 } 246 247 if (gifp == NULL) { 248 m_freem(m); 249 ip6stat.ip6s_nogif++; 250 return IPPROTO_DONE; 251 } 252 253 otos = ip6->ip6_flow; 254 m_adj(m, *offp); 255 256 switch (proto) { 257#ifdef INET 258 case IPPROTO_IPV4: 259 { 260 struct ip *ip; 261 u_int8_t otos8; 262 af = AF_INET; 263 otos8 = (ntohl(otos) >> 20) & 0xff; 264 if (m->m_len < sizeof(*ip)) { 265 m = m_pullup(m, sizeof(*ip)); 266 if (!m) 267 return IPPROTO_DONE; 268 } 269 ip = mtod(m, struct ip *); 270 if (gifp->if_flags & IFF_LINK1) 271 ip_ecn_egress(ECN_ALLOWED, &otos8, &ip->ip_tos); 272 break; 273 } 274#endif /* INET */ 275#ifdef INET6 276 case IPPROTO_IPV6: 277 { 278 struct ip6_hdr *ip6; 279 af = AF_INET6; 280 if (m->m_len < sizeof(*ip6)) { 281 m = m_pullup(m, sizeof(*ip6)); 282 if (!m) 283 return IPPROTO_DONE; 284 } 285 ip6 = mtod(m, struct ip6_hdr *); 286 if (gifp->if_flags & IFF_LINK1) 287 ip6_ecn_egress(ECN_ALLOWED, &otos, &ip6->ip6_flow); 288 break; 289 } 290#endif 291 default: 292 ip6stat.ip6s_nogif++; 293 m_freem(m); 294 return IPPROTO_DONE; 295 } 296 297 gif_input(m, af, gifp); 298 return IPPROTO_DONE; 299} 300