[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]

FreeBSD/Linux Kernel Cross Reference
sys/netinet6/in6_gif.c

Version: -  FREEBSD  -  FREEBSD7  -  FREEBSD70  -  FREEBSD6  -  FREEBSD64  -  FREEBSD63  -  FREEBSD62  -  FREEBSD61  -  FREEBSD60  -  FREEBSD5  -  FREEBSD55  -  FREEBSD54  -  FREEBSD53  -  FREEBSD52  -  FREEBSD51  -  FREEBSD50  -  FREEBSD4  -  FREEBSD3  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  OPENSOLARIS  -  minix-3-1-1  -  TRUSTEDBSD-SEBSD  -  FREEBSD-LIBC  -  FREEBSD7-LIBC  -  FREEBSD6-LIBC  -  GLIBC27 
SearchContext: -  none  -  excerpts  -  bigexcerpts 

  1 /*-
  2  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
  3  * All rights reserved.
  4  *
  5  * Redistribution and use in source and binary forms, with or without
  6  * modification, are permitted provided that the following conditions
  7  * are met:
  8  * 1. Redistributions of source code must retain the above copyright
  9  *    notice, this list of conditions and the following disclaimer.
 10  * 2. Redistributions in binary form must reproduce the above copyright
 11  *    notice, this list of conditions and the following disclaimer in the
 12  *    documentation and/or other materials provided with the distribution.
 13  * 3. Neither the name of the project nor the names of its contributors
 14  *    may be used to endorse or promote products derived from this software
 15  *    without specific prior written permission.
 16  *
 17  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
 18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
 21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 27  * SUCH DAMAGE.
 28  *
 29  *      $KAME: in6_gif.c,v 1.49 2001/05/14 14:02:17 itojun Exp $
 30  */
 31 
 32 #include <sys/cdefs.h>
 33 __FBSDID("$FreeBSD: src/sys/netinet6/in6_gif.c,v 1.34 2008/12/02 21:37:28 bz Exp $");
 34 
 35 #include "opt_inet.h"
 36 #include "opt_inet6.h"
 37 
 38 #include <sys/param.h>
 39 #include <sys/systm.h>
 40 #include <sys/socket.h>
 41 #include <sys/sockio.h>
 42 #include <sys/mbuf.h>
 43 #include <sys/errno.h>
 44 #include <sys/queue.h>
 45 #include <sys/syslog.h>
 46 #include <sys/protosw.h>
 47 #include <sys/malloc.h>
 48 #include <sys/vimage.h>
 49 
 50 #include <net/if.h>
 51 #include <net/route.h>
 52 
 53 #include <netinet/in.h>
 54 #include <netinet/in_systm.h>
 55 #ifdef INET
 56 #include <netinet/ip.h>
 57 #endif
 58 #include <netinet/ip_encap.h>
 59 #ifdef INET6
 60 #include <netinet/ip6.h>
 61 #include <netinet6/ip6_var.h>
 62 #include <netinet6/in6_gif.h>
 63 #include <netinet6/in6_var.h>
 64 #endif
 65 #include <netinet6/ip6protosw.h>
 66 #include <netinet/ip_ecn.h>
 67 #ifdef INET6
 68 #include <netinet6/ip6_ecn.h>
 69 #include <netinet6/vinet6.h>
 70 #endif
 71 
 72 #include <net/if_gif.h>
 73 
 74 static int gif_validate6(const struct ip6_hdr *, struct gif_softc *,
 75                          struct ifnet *);
 76 
 77 extern  struct domain inet6domain;
 78 struct ip6protosw in6_gif_protosw =
 79 { SOCK_RAW,     &inet6domain,   0/* IPPROTO_IPV[46] */, PR_ATOMIC|PR_ADDR,
 80   in6_gif_input, rip6_output,   0,              rip6_ctloutput,
 81   0,
 82   0,            0,              0,              0,
 83   &rip6_usrreqs
 84 };
 85 
 86 int
 87 in6_gif_output(struct ifnet *ifp,
 88     int family,                 /* family of the packet to be encapsulate */
 89     struct mbuf *m)
 90 {
 91         INIT_VNET_GIF(ifp->if_vnet);
 92         struct gif_softc *sc = ifp->if_softc;
 93         struct sockaddr_in6 *dst = (struct sockaddr_in6 *)&sc->gif_ro6.ro_dst;
 94         struct sockaddr_in6 *sin6_src = (struct sockaddr_in6 *)sc->gif_psrc;
 95         struct sockaddr_in6 *sin6_dst = (struct sockaddr_in6 *)sc->gif_pdst;
 96         struct ip6_hdr *ip6;
 97         struct etherip_header eiphdr;
 98         int proto, error;
 99         u_int8_t itos, otos;
100 
101         GIF_LOCK_ASSERT(sc);
102 
103         if (sin6_src == NULL || sin6_dst == NULL ||
104             sin6_src->sin6_family != AF_INET6 ||
105             sin6_dst->sin6_family != AF_INET6) {
106                 m_freem(m);
107                 return EAFNOSUPPORT;
108         }
109 
110         switch (family) {
111 #ifdef INET
112         case AF_INET:
113             {
114                 struct ip *ip;
115 
116                 proto = IPPROTO_IPV4;
117                 if (m->m_len < sizeof(*ip)) {
118                         m = m_pullup(m, sizeof(*ip));
119                         if (!m)
120                                 return ENOBUFS;
121                 }
122                 ip = mtod(m, struct ip *);
123                 itos = ip->ip_tos;
124                 break;
125             }
126 #endif
127 #ifdef INET6
128         case AF_INET6:
129             {
130                 struct ip6_hdr *ip6;
131                 proto = IPPROTO_IPV6;
132                 if (m->m_len < sizeof(*ip6)) {
133                         m = m_pullup(m, sizeof(*ip6));
134                         if (!m)
135                                 return ENOBUFS;
136                 }
137                 ip6 = mtod(m, struct ip6_hdr *);
138                 itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
139                 break;
140             }
141 #endif
142         case AF_LINK:
143                 proto = IPPROTO_ETHERIP;
144                 eiphdr.eip_ver = ETHERIP_VERSION & ETHERIP_VER_VERS_MASK;
145                 eiphdr.eip_pad = 0;
146                 /* prepend Ethernet-in-IP header */
147                 M_PREPEND(m, sizeof(struct etherip_header), M_DONTWAIT);
148                 if (m && m->m_len < sizeof(struct etherip_header))
149                         m = m_pullup(m, sizeof(struct etherip_header));
150                 if (m == NULL)
151                         return ENOBUFS;
152                 bcopy(&eiphdr, mtod(m, struct etherip_header *),
153                     sizeof(struct etherip_header));
154                 break;
155 
156         default:
157 #ifdef DEBUG
158                 printf("in6_gif_output: warning: unknown family %d passed\n",
159                         family);
160 #endif
161                 m_freem(m);
162                 return EAFNOSUPPORT;
163         }
164 
165         /* prepend new IP header */
166         M_PREPEND(m, sizeof(struct ip6_hdr), M_DONTWAIT);
167         if (m && m->m_len < sizeof(struct ip6_hdr))
168                 m = m_pullup(m, sizeof(struct ip6_hdr));
169         if (m == NULL) {
170                 printf("ENOBUFS in in6_gif_output %d\n", __LINE__);
171                 return ENOBUFS;
172         }
173 
174         ip6 = mtod(m, struct ip6_hdr *);
175         ip6->ip6_flow   = 0;
176         ip6->ip6_vfc    &= ~IPV6_VERSION_MASK;
177         ip6->ip6_vfc    |= IPV6_VERSION;
178         ip6->ip6_plen   = htons((u_short)m->m_pkthdr.len);
179         ip6->ip6_nxt    = proto;
180         ip6->ip6_hlim   = V_ip6_gif_hlim;
181         ip6->ip6_src    = sin6_src->sin6_addr;
182         /* bidirectional configured tunnel mode */
183         if (!IN6_IS_ADDR_UNSPECIFIED(&sin6_dst->sin6_addr))
184                 ip6->ip6_dst = sin6_dst->sin6_addr;
185         else  {
186                 m_freem(m);
187                 return ENETUNREACH;
188         }
189         ip_ecn_ingress((ifp->if_flags & IFF_LINK1) ? ECN_ALLOWED : ECN_NOCARE,
190                        &otos, &itos);
191         ip6->ip6_flow &= ~htonl(0xff << 20);
192         ip6->ip6_flow |= htonl((u_int32_t)otos << 20);
193 
194         if (dst->sin6_family != sin6_dst->sin6_family ||
195              !IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &sin6_dst->sin6_addr)) {
196                 /* cache route doesn't match */
197                 bzero(dst, sizeof(*dst));
198                 dst->sin6_family = sin6_dst->sin6_family;
199                 dst->sin6_len = sizeof(struct sockaddr_in6);
200                 dst->sin6_addr = sin6_dst->sin6_addr;
201                 if (sc->gif_ro6.ro_rt) {
202                         RTFREE(sc->gif_ro6.ro_rt);
203                         sc->gif_ro6.ro_rt = NULL;
204                 }
205 #if 0
206                 GIF2IFP(sc)->if_mtu = GIF_MTU;
207 #endif
208         }
209 
210         if (sc->gif_ro6.ro_rt == NULL) {
211                 rtalloc((struct route *)&sc->gif_ro6);
212                 if (sc->gif_ro6.ro_rt == NULL) {
213                         m_freem(m);
214                         return ENETUNREACH;
215                 }
216 
217                 /* if it constitutes infinite encapsulation, punt. */
218                 if (sc->gif_ro.ro_rt->rt_ifp == ifp) {
219                         m_freem(m);
220                         return ENETUNREACH;     /*XXX*/
221                 }
222 #if 0
223                 ifp->if_mtu = sc->gif_ro6.ro_rt->rt_ifp->if_mtu
224                         - sizeof(struct ip6_hdr);
225 #endif
226         }
227 
228 #ifdef IPV6_MINMTU
229         /*
230          * force fragmentation to minimum MTU, to avoid path MTU discovery.
231          * it is too painful to ask for resend of inner packet, to achieve
232          * path MTU discovery for encapsulated packets.
233          */
234         error = ip6_output(m, 0, &sc->gif_ro6, IPV6_MINMTU, 0, NULL, NULL);
235 #else
236         error = ip6_output(m, 0, &sc->gif_ro6, 0, 0, NULL, NULL);
237 #endif
238 
239         if (!(GIF2IFP(sc)->if_flags & IFF_LINK0) &&
240             sc->gif_ro6.ro_rt != NULL) {
241                 RTFREE(sc->gif_ro6.ro_rt);
242                 sc->gif_ro6.ro_rt = NULL;
243         }
244 
245         return (error);
246 }
247 
248 int
249 in6_gif_input(struct mbuf **mp, int *offp, int proto)
250 {
251         INIT_VNET_INET6(curvnet);
252         struct mbuf *m = *mp;
253         struct ifnet *gifp = NULL;
254         struct gif_softc *sc;
255         struct ip6_hdr *ip6;
256         int af = 0;
257         u_int32_t otos;
258 
259         ip6 = mtod(m, struct ip6_hdr *);
260 
261         sc = (struct gif_softc *)encap_getarg(m);
262         if (sc == NULL) {
263                 m_freem(m);
264                 V_ip6stat.ip6s_nogif++;
265                 return IPPROTO_DONE;
266         }
267 
268         gifp = GIF2IFP(sc);
269         if (gifp == NULL || (gifp->if_flags & IFF_UP) == 0) {
270                 m_freem(m);
271                 V_ip6stat.ip6s_nogif++;
272                 return IPPROTO_DONE;
273         }
274 
275         otos = ip6->ip6_flow;
276         m_adj(m, *offp);
277 
278         switch (proto) {
279 #ifdef INET
280         case IPPROTO_IPV4:
281             {
282                 struct ip *ip;
283                 u_int8_t otos8;
284                 af = AF_INET;
285                 otos8 = (ntohl(otos) >> 20) & 0xff;
286                 if (m->m_len < sizeof(*ip)) {
287                         m = m_pullup(m, sizeof(*ip));
288                         if (!m)
289                                 return IPPROTO_DONE;
290                 }
291                 ip = mtod(m, struct ip *);
292                 if (ip_ecn_egress((gifp->if_flags & IFF_LINK1) ?
293                                   ECN_ALLOWED : ECN_NOCARE,
294                                   &otos8, &ip->ip_tos) == 0) {
295                         m_freem(m);
296                         return IPPROTO_DONE;
297                 }
298                 break;
299             }
300 #endif /* INET */
301 #ifdef INET6
302         case IPPROTO_IPV6:
303             {
304                 struct ip6_hdr *ip6;
305                 af = AF_INET6;
306                 if (m->m_len < sizeof(*ip6)) {
307                         m = m_pullup(m, sizeof(*ip6));
308                         if (!m)
309                                 return IPPROTO_DONE;
310                 }
311                 ip6 = mtod(m, struct ip6_hdr *);
312                 if (ip6_ecn_egress((gifp->if_flags & IFF_LINK1) ?
313                                    ECN_ALLOWED : ECN_NOCARE,
314                                    &otos, &ip6->ip6_flow) == 0) {
315                         m_freem(m);
316                         return IPPROTO_DONE;
317                 }
318                 break;
319             }
320 #endif
321         case IPPROTO_ETHERIP:
322                 af = AF_LINK;
323                 break;
324 
325         default:
326                 V_ip6stat.ip6s_nogif++;
327                 m_freem(m);
328                 return IPPROTO_DONE;
329         }
330 
331         gif_input(m, af, gifp);
332         return IPPROTO_DONE;
333 }
334 
335 /*
336  * validate outer address.
337  */
338 static int
339 gif_validate6(const struct ip6_hdr *ip6, struct gif_softc *sc,
340     struct ifnet *ifp)
341 {
342         struct sockaddr_in6 *src, *dst;
343 
344         src = (struct sockaddr_in6 *)sc->gif_psrc;
345         dst = (struct sockaddr_in6 *)sc->gif_pdst;
346 
347         /*
348          * Check for address match.  Note that the check is for an incoming
349          * packet.  We should compare the *source* address in our configuration
350          * and the *destination* address of the packet, and vice versa.
351          */
352         if (!IN6_ARE_ADDR_EQUAL(&src->sin6_addr, &ip6->ip6_dst) ||
353             !IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &ip6->ip6_src))
354                 return 0;
355 
356         /* martian filters on outer source - done in ip6_input */
357 
358         /* ingress filters on outer source */
359         if ((GIF2IFP(sc)->if_flags & IFF_LINK2) == 0 && ifp) {
360                 struct sockaddr_in6 sin6;
361                 struct rtentry *rt;
362 
363                 bzero(&sin6, sizeof(sin6));
364                 sin6.sin6_family = AF_INET6;
365                 sin6.sin6_len = sizeof(struct sockaddr_in6);
366                 sin6.sin6_addr = ip6->ip6_src;
367                 sin6.sin6_scope_id = 0; /* XXX */
368 
369                 rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL);
370                 if (!rt || rt->rt_ifp != ifp) {
371 #if 0
372                         char ip6buf[INET6_ADDRSTRLEN];
373                         log(LOG_WARNING, "%s: packet from %s dropped "
374                             "due to ingress filter\n", if_name(GIF2IFP(sc)),
375                             ip6_sprintf(ip6buf, &sin6.sin6_addr));
376 #endif
377                         if (rt)
378                                 rtfree(rt);
379                         return 0;
380                 }
381                 rtfree(rt);
382         }
383 
384         return 128 * 2;
385 }
386 
387 /*
388  * we know that we are in IFF_UP, outer address available, and outer family
389  * matched the physical addr family.  see gif_encapcheck().
390  * sanity check for arg should have been done in the caller.
391  */
392 int
393 gif_encapcheck6(const struct mbuf *m, int off, int proto, void *arg)
394 {
395         struct ip6_hdr ip6;
396         struct gif_softc *sc;
397         struct ifnet *ifp;
398 
399         /* sanity check done in caller */
400         sc = (struct gif_softc *)arg;
401 
402         /* LINTED const cast */
403         m_copydata(m, 0, sizeof(ip6), (caddr_t)&ip6);
404         ifp = ((m->m_flags & M_PKTHDR) != 0) ? m->m_pkthdr.rcvif : NULL;
405 
406         return gif_validate6(&ip6, sc, ifp);
407 }
408 
409 int
410 in6_gif_attach(struct gif_softc *sc)
411 {
412         sc->encap_cookie6 = encap_attach_func(AF_INET6, -1, gif_encapcheck,
413             (void *)&in6_gif_protosw, sc);
414         if (sc->encap_cookie6 == NULL)
415                 return EEXIST;
416         return 0;
417 }
418 
419 int
420 in6_gif_detach(struct gif_softc *sc)
421 {
422         int error;
423 
424         error = encap_detach(sc->encap_cookie6);
425         if (error == 0)
426                 sc->encap_cookie6 = NULL;
427         return error;
428 }
429 

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.