1686cdd19SJun-ichiro itojun Hagino /* $FreeBSD$ */ 2686cdd19SJun-ichiro itojun Hagino /* $KAME: if_gif.c,v 1.28 2000/06/20 12:30:03 jinmei Exp $ */ 3686cdd19SJun-ichiro itojun Hagino 4cfa1ca9dSYoshinobu Inoue /* 5cfa1ca9dSYoshinobu Inoue * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 6cfa1ca9dSYoshinobu Inoue * All rights reserved. 7cfa1ca9dSYoshinobu Inoue * 8cfa1ca9dSYoshinobu Inoue * Redistribution and use in source and binary forms, with or without 9cfa1ca9dSYoshinobu Inoue * modification, are permitted provided that the following conditions 10cfa1ca9dSYoshinobu Inoue * are met: 11cfa1ca9dSYoshinobu Inoue * 1. Redistributions of source code must retain the above copyright 12cfa1ca9dSYoshinobu Inoue * notice, this list of conditions and the following disclaimer. 13cfa1ca9dSYoshinobu Inoue * 2. Redistributions in binary form must reproduce the above copyright 14cfa1ca9dSYoshinobu Inoue * notice, this list of conditions and the following disclaimer in the 15cfa1ca9dSYoshinobu Inoue * documentation and/or other materials provided with the distribution. 16cfa1ca9dSYoshinobu Inoue * 3. Neither the name of the project nor the names of its contributors 17cfa1ca9dSYoshinobu Inoue * may be used to endorse or promote products derived from this software 18cfa1ca9dSYoshinobu Inoue * without specific prior written permission. 19cfa1ca9dSYoshinobu Inoue * 20cfa1ca9dSYoshinobu Inoue * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21cfa1ca9dSYoshinobu Inoue * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22cfa1ca9dSYoshinobu Inoue * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23cfa1ca9dSYoshinobu Inoue * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24cfa1ca9dSYoshinobu Inoue * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25cfa1ca9dSYoshinobu Inoue * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26cfa1ca9dSYoshinobu Inoue * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27cfa1ca9dSYoshinobu Inoue * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28cfa1ca9dSYoshinobu Inoue * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29cfa1ca9dSYoshinobu Inoue * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30cfa1ca9dSYoshinobu Inoue * SUCH DAMAGE. 31cfa1ca9dSYoshinobu Inoue */ 32cfa1ca9dSYoshinobu Inoue 33cfa1ca9dSYoshinobu Inoue #include "opt_inet.h" 34cfa1ca9dSYoshinobu Inoue #include "opt_inet6.h" 35cfa1ca9dSYoshinobu Inoue 36cfa1ca9dSYoshinobu Inoue #include <sys/param.h> 37cfa1ca9dSYoshinobu Inoue #include <sys/systm.h> 38cfa1ca9dSYoshinobu Inoue #include <sys/kernel.h> 39cfa1ca9dSYoshinobu Inoue #include <sys/malloc.h> 40cfa1ca9dSYoshinobu Inoue #include <sys/mbuf.h> 41cfa1ca9dSYoshinobu Inoue #include <sys/socket.h> 42cfa1ca9dSYoshinobu Inoue #include <sys/sockio.h> 43cfa1ca9dSYoshinobu Inoue #include <sys/errno.h> 44cfa1ca9dSYoshinobu Inoue #include <sys/time.h> 45cfa1ca9dSYoshinobu Inoue #include <sys/syslog.h> 46686cdd19SJun-ichiro itojun Hagino #include <sys/protosw.h> 47cfa1ca9dSYoshinobu Inoue #include <machine/cpu.h> 48cfa1ca9dSYoshinobu Inoue 49cfa1ca9dSYoshinobu Inoue #include <net/if.h> 50cfa1ca9dSYoshinobu Inoue #include <net/if_types.h> 51cfa1ca9dSYoshinobu Inoue #include <net/netisr.h> 52cfa1ca9dSYoshinobu Inoue #include <net/route.h> 53cfa1ca9dSYoshinobu Inoue #include <net/bpf.h> 54cfa1ca9dSYoshinobu Inoue 55cfa1ca9dSYoshinobu Inoue #ifdef INET 56cfa1ca9dSYoshinobu Inoue #include <netinet/in.h> 57cfa1ca9dSYoshinobu Inoue #include <netinet/in_systm.h> 58cfa1ca9dSYoshinobu Inoue #include <netinet/in_var.h> 59cfa1ca9dSYoshinobu Inoue #include <netinet/ip.h> 60cfa1ca9dSYoshinobu Inoue #include <netinet/in_gif.h> 61cfa1ca9dSYoshinobu Inoue #endif /* INET */ 62cfa1ca9dSYoshinobu Inoue 63cfa1ca9dSYoshinobu Inoue #ifdef INET6 64cfa1ca9dSYoshinobu Inoue #ifndef INET 65cfa1ca9dSYoshinobu Inoue #include <netinet/in.h> 66cfa1ca9dSYoshinobu Inoue #endif 67cfa1ca9dSYoshinobu Inoue #include <netinet6/in6_var.h> 68cfa1ca9dSYoshinobu Inoue #include <netinet/ip6.h> 69cfa1ca9dSYoshinobu Inoue #include <netinet6/ip6_var.h> 70cfa1ca9dSYoshinobu Inoue #include <netinet6/in6_gif.h> 71686cdd19SJun-ichiro itojun Hagino #include <netinet6/ip6protosw.h> 72cfa1ca9dSYoshinobu Inoue #endif /* INET6 */ 73cfa1ca9dSYoshinobu Inoue 74686cdd19SJun-ichiro itojun Hagino #include <netinet/ip_encap.h> 75cfa1ca9dSYoshinobu Inoue #include <net/if_gif.h> 76cfa1ca9dSYoshinobu Inoue 77cfa1ca9dSYoshinobu Inoue #include "gif.h" 78686cdd19SJun-ichiro itojun Hagino #include "bpf.h" 79686cdd19SJun-ichiro itojun Hagino #define NBPFILTER NBPF 80cfa1ca9dSYoshinobu Inoue 81cfa1ca9dSYoshinobu Inoue #include <net/net_osdep.h> 82cfa1ca9dSYoshinobu Inoue 83686cdd19SJun-ichiro itojun Hagino #if NGIF > 0 84686cdd19SJun-ichiro itojun Hagino 85cfa1ca9dSYoshinobu Inoue void gifattach __P((void *)); 86686cdd19SJun-ichiro itojun Hagino static int gif_encapcheck __P((const struct mbuf *, int, int, void *)); 87686cdd19SJun-ichiro itojun Hagino #ifdef INET 88686cdd19SJun-ichiro itojun Hagino extern struct protosw in_gif_protosw; 89686cdd19SJun-ichiro itojun Hagino #endif 90686cdd19SJun-ichiro itojun Hagino #ifdef INET6 91686cdd19SJun-ichiro itojun Hagino extern struct ip6protosw in6_gif_protosw; 92686cdd19SJun-ichiro itojun Hagino #endif 93cfa1ca9dSYoshinobu Inoue 94cfa1ca9dSYoshinobu Inoue /* 95cfa1ca9dSYoshinobu Inoue * gif global variable definitions 96cfa1ca9dSYoshinobu Inoue */ 97686cdd19SJun-ichiro itojun Hagino static int ngif; /* number of interfaces */ 98686cdd19SJun-ichiro itojun Hagino static struct gif_softc *gif = 0; 99686cdd19SJun-ichiro itojun Hagino 100686cdd19SJun-ichiro itojun Hagino #ifndef MAX_GIF_NEST 101686cdd19SJun-ichiro itojun Hagino /* 102686cdd19SJun-ichiro itojun Hagino * This macro controls the upper limitation on nesting of gif tunnels. 103686cdd19SJun-ichiro itojun Hagino * Since, setting a large value to this macro with a careless configuration 104686cdd19SJun-ichiro itojun Hagino * may introduce system crash, we don't allow any nestings by default. 105686cdd19SJun-ichiro itojun Hagino * If you need to configure nested gif tunnels, you can define this macro 106686cdd19SJun-ichiro itojun Hagino * in your kernel configuration file. However, if you do so, please be 107686cdd19SJun-ichiro itojun Hagino * careful to configure the tunnels so that it won't make a loop. 108686cdd19SJun-ichiro itojun Hagino */ 109686cdd19SJun-ichiro itojun Hagino #define MAX_GIF_NEST 1 110686cdd19SJun-ichiro itojun Hagino #endif 111686cdd19SJun-ichiro itojun Hagino static int max_gif_nesting = MAX_GIF_NEST; 112cfa1ca9dSYoshinobu Inoue 113cfa1ca9dSYoshinobu Inoue void 114cfa1ca9dSYoshinobu Inoue gifattach(dummy) 115cfa1ca9dSYoshinobu Inoue void *dummy; 116cfa1ca9dSYoshinobu Inoue { 117cfa1ca9dSYoshinobu Inoue register struct gif_softc *sc; 118cfa1ca9dSYoshinobu Inoue register int i; 119cfa1ca9dSYoshinobu Inoue 120686cdd19SJun-ichiro itojun Hagino ngif = NGIF; 1212a0c503eSBosko Milekic gif = sc = malloc (ngif * sizeof(struct gif_softc), M_DEVBUF, M_WAITOK); 122cfa1ca9dSYoshinobu Inoue bzero(sc, ngif * sizeof(struct gif_softc)); 123686cdd19SJun-ichiro itojun Hagino for (i = 0; i < ngif; sc++, i++) { 124cfa1ca9dSYoshinobu Inoue sc->gif_if.if_name = "gif"; 125cfa1ca9dSYoshinobu Inoue sc->gif_if.if_unit = i; 126686cdd19SJun-ichiro itojun Hagino 127686cdd19SJun-ichiro itojun Hagino sc->encap_cookie4 = sc->encap_cookie6 = NULL; 128686cdd19SJun-ichiro itojun Hagino #ifdef INET 129686cdd19SJun-ichiro itojun Hagino sc->encap_cookie4 = encap_attach_func(AF_INET, -1, 130686cdd19SJun-ichiro itojun Hagino gif_encapcheck, &in_gif_protosw, sc); 131686cdd19SJun-ichiro itojun Hagino if (sc->encap_cookie4 == NULL) { 132686cdd19SJun-ichiro itojun Hagino printf("%s: attach failed\n", if_name(&sc->gif_if)); 133686cdd19SJun-ichiro itojun Hagino continue; 134686cdd19SJun-ichiro itojun Hagino } 135686cdd19SJun-ichiro itojun Hagino #endif 136686cdd19SJun-ichiro itojun Hagino #ifdef INET6 137686cdd19SJun-ichiro itojun Hagino sc->encap_cookie6 = encap_attach_func(AF_INET6, -1, 138686cdd19SJun-ichiro itojun Hagino gif_encapcheck, (struct protosw *)&in6_gif_protosw, sc); 139686cdd19SJun-ichiro itojun Hagino if (sc->encap_cookie6 == NULL) { 140686cdd19SJun-ichiro itojun Hagino if (sc->encap_cookie4) { 141686cdd19SJun-ichiro itojun Hagino encap_detach(sc->encap_cookie4); 142686cdd19SJun-ichiro itojun Hagino sc->encap_cookie4 = NULL; 143686cdd19SJun-ichiro itojun Hagino } 144686cdd19SJun-ichiro itojun Hagino printf("%s: attach failed\n", if_name(&sc->gif_if)); 145686cdd19SJun-ichiro itojun Hagino continue; 146686cdd19SJun-ichiro itojun Hagino } 147686cdd19SJun-ichiro itojun Hagino #endif 148686cdd19SJun-ichiro itojun Hagino 149cfa1ca9dSYoshinobu Inoue sc->gif_if.if_mtu = GIF_MTU; 150cfa1ca9dSYoshinobu Inoue sc->gif_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST; 151cfa1ca9dSYoshinobu Inoue sc->gif_if.if_ioctl = gif_ioctl; 152cfa1ca9dSYoshinobu Inoue sc->gif_if.if_output = gif_output; 153cfa1ca9dSYoshinobu Inoue sc->gif_if.if_type = IFT_GIF; 154686cdd19SJun-ichiro itojun Hagino sc->gif_if.if_snd.ifq_maxlen = IFQ_MAXLEN; 155cfa1ca9dSYoshinobu Inoue if_attach(&sc->gif_if); 156686cdd19SJun-ichiro itojun Hagino #if NBPFILTER > 0 157686cdd19SJun-ichiro itojun Hagino #ifdef HAVE_OLD_BPF 158cfa1ca9dSYoshinobu Inoue bpfattach(&sc->gif_if, DLT_NULL, sizeof(u_int)); 159686cdd19SJun-ichiro itojun Hagino #else 160686cdd19SJun-ichiro itojun Hagino bpfattach(&sc->gif_if.if_bpf, &sc->gif_if, DLT_NULL, sizeof(u_int)); 161686cdd19SJun-ichiro itojun Hagino #endif 162686cdd19SJun-ichiro itojun Hagino #endif 163cfa1ca9dSYoshinobu Inoue } 164cfa1ca9dSYoshinobu Inoue } 165cfa1ca9dSYoshinobu Inoue 166cfa1ca9dSYoshinobu Inoue PSEUDO_SET(gifattach, if_gif); 167cfa1ca9dSYoshinobu Inoue 168686cdd19SJun-ichiro itojun Hagino static int 169686cdd19SJun-ichiro itojun Hagino gif_encapcheck(m, off, proto, arg) 170686cdd19SJun-ichiro itojun Hagino const struct mbuf *m; 171686cdd19SJun-ichiro itojun Hagino int off; 172686cdd19SJun-ichiro itojun Hagino int proto; 173686cdd19SJun-ichiro itojun Hagino void *arg; 174686cdd19SJun-ichiro itojun Hagino { 175686cdd19SJun-ichiro itojun Hagino struct ip ip; 176686cdd19SJun-ichiro itojun Hagino struct gif_softc *sc; 177686cdd19SJun-ichiro itojun Hagino 178686cdd19SJun-ichiro itojun Hagino sc = (struct gif_softc *)arg; 179686cdd19SJun-ichiro itojun Hagino if (sc == NULL) 180686cdd19SJun-ichiro itojun Hagino return 0; 181686cdd19SJun-ichiro itojun Hagino 182686cdd19SJun-ichiro itojun Hagino if ((sc->gif_if.if_flags & IFF_UP) == 0) 183686cdd19SJun-ichiro itojun Hagino return 0; 184686cdd19SJun-ichiro itojun Hagino 185686cdd19SJun-ichiro itojun Hagino /* no physical address */ 186686cdd19SJun-ichiro itojun Hagino if (!sc->gif_psrc || !sc->gif_pdst) 187686cdd19SJun-ichiro itojun Hagino return 0; 188686cdd19SJun-ichiro itojun Hagino 189686cdd19SJun-ichiro itojun Hagino switch (proto) { 190686cdd19SJun-ichiro itojun Hagino #ifdef INET 191686cdd19SJun-ichiro itojun Hagino case IPPROTO_IPV4: 192686cdd19SJun-ichiro itojun Hagino break; 193686cdd19SJun-ichiro itojun Hagino #endif 194686cdd19SJun-ichiro itojun Hagino #ifdef INET6 195686cdd19SJun-ichiro itojun Hagino case IPPROTO_IPV6: 196686cdd19SJun-ichiro itojun Hagino break; 197686cdd19SJun-ichiro itojun Hagino #endif 198686cdd19SJun-ichiro itojun Hagino default: 199686cdd19SJun-ichiro itojun Hagino return 0; 200686cdd19SJun-ichiro itojun Hagino } 201686cdd19SJun-ichiro itojun Hagino 202686cdd19SJun-ichiro itojun Hagino /* LINTED const cast */ 203686cdd19SJun-ichiro itojun Hagino m_copydata((struct mbuf *)m, 0, sizeof(ip), (caddr_t)&ip); 204686cdd19SJun-ichiro itojun Hagino 205686cdd19SJun-ichiro itojun Hagino switch (ip.ip_v) { 206686cdd19SJun-ichiro itojun Hagino #ifdef INET 207686cdd19SJun-ichiro itojun Hagino case 4: 208686cdd19SJun-ichiro itojun Hagino if (sc->gif_psrc->sa_family != AF_INET || 209686cdd19SJun-ichiro itojun Hagino sc->gif_pdst->sa_family != AF_INET) 210686cdd19SJun-ichiro itojun Hagino return 0; 211686cdd19SJun-ichiro itojun Hagino return gif_encapcheck4(m, off, proto, arg); 212686cdd19SJun-ichiro itojun Hagino #endif 213686cdd19SJun-ichiro itojun Hagino #ifdef INET6 214686cdd19SJun-ichiro itojun Hagino case 6: 215686cdd19SJun-ichiro itojun Hagino if (sc->gif_psrc->sa_family != AF_INET6 || 216686cdd19SJun-ichiro itojun Hagino sc->gif_pdst->sa_family != AF_INET6) 217686cdd19SJun-ichiro itojun Hagino return 0; 218686cdd19SJun-ichiro itojun Hagino return gif_encapcheck6(m, off, proto, arg); 219686cdd19SJun-ichiro itojun Hagino #endif 220686cdd19SJun-ichiro itojun Hagino default: 221686cdd19SJun-ichiro itojun Hagino return 0; 222686cdd19SJun-ichiro itojun Hagino } 223686cdd19SJun-ichiro itojun Hagino } 224686cdd19SJun-ichiro itojun Hagino 225cfa1ca9dSYoshinobu Inoue int 226cfa1ca9dSYoshinobu Inoue gif_output(ifp, m, dst, rt) 227cfa1ca9dSYoshinobu Inoue struct ifnet *ifp; 228cfa1ca9dSYoshinobu Inoue struct mbuf *m; 229cfa1ca9dSYoshinobu Inoue struct sockaddr *dst; 230cfa1ca9dSYoshinobu Inoue struct rtentry *rt; /* added in net2 */ 231cfa1ca9dSYoshinobu Inoue { 232cfa1ca9dSYoshinobu Inoue register struct gif_softc *sc = (struct gif_softc*)ifp; 233cfa1ca9dSYoshinobu Inoue int error = 0; 234cfa1ca9dSYoshinobu Inoue static int called = 0; /* XXX: MUTEX */ 235cfa1ca9dSYoshinobu Inoue 236cfa1ca9dSYoshinobu Inoue /* 237cfa1ca9dSYoshinobu Inoue * gif may cause infinite recursion calls when misconfigured. 238cfa1ca9dSYoshinobu Inoue * We'll prevent this by introducing upper limit. 239cfa1ca9dSYoshinobu Inoue * XXX: this mechanism may introduce another problem about 240cfa1ca9dSYoshinobu Inoue * mutual exclusion of the variable CALLED, especially if we 241cfa1ca9dSYoshinobu Inoue * use kernel thread. 242cfa1ca9dSYoshinobu Inoue */ 243686cdd19SJun-ichiro itojun Hagino if (++called > max_gif_nesting) { 244cfa1ca9dSYoshinobu Inoue log(LOG_NOTICE, 245cfa1ca9dSYoshinobu Inoue "gif_output: recursively called too many times(%d)\n", 246cfa1ca9dSYoshinobu Inoue called); 247cfa1ca9dSYoshinobu Inoue m_freem(m); 248cfa1ca9dSYoshinobu Inoue error = EIO; /* is there better errno? */ 249cfa1ca9dSYoshinobu Inoue goto end; 250cfa1ca9dSYoshinobu Inoue } 251686cdd19SJun-ichiro itojun Hagino 252cfa1ca9dSYoshinobu Inoue getmicrotime(&ifp->if_lastchange); 253cfa1ca9dSYoshinobu Inoue m->m_flags &= ~(M_BCAST|M_MCAST); 254cfa1ca9dSYoshinobu Inoue if (!(ifp->if_flags & IFF_UP) || 255cfa1ca9dSYoshinobu Inoue sc->gif_psrc == NULL || sc->gif_pdst == NULL) { 256cfa1ca9dSYoshinobu Inoue m_freem(m); 257cfa1ca9dSYoshinobu Inoue error = ENETDOWN; 258cfa1ca9dSYoshinobu Inoue goto end; 259cfa1ca9dSYoshinobu Inoue } 260cfa1ca9dSYoshinobu Inoue 261686cdd19SJun-ichiro itojun Hagino #if NBPFILTER > 0 262cfa1ca9dSYoshinobu Inoue if (ifp->if_bpf) { 263cfa1ca9dSYoshinobu Inoue /* 264cfa1ca9dSYoshinobu Inoue * We need to prepend the address family as 265cfa1ca9dSYoshinobu Inoue * a four byte field. Cons up a dummy header 266cfa1ca9dSYoshinobu Inoue * to pacify bpf. This is safe because bpf 267cfa1ca9dSYoshinobu Inoue * will only read from the mbuf (i.e., it won't 268cfa1ca9dSYoshinobu Inoue * try to free it or keep a pointer a to it). 269cfa1ca9dSYoshinobu Inoue */ 270cfa1ca9dSYoshinobu Inoue struct mbuf m0; 271cfa1ca9dSYoshinobu Inoue u_int af = dst->sa_family; 272cfa1ca9dSYoshinobu Inoue 273cfa1ca9dSYoshinobu Inoue m0.m_next = m; 274cfa1ca9dSYoshinobu Inoue m0.m_len = 4; 275cfa1ca9dSYoshinobu Inoue m0.m_data = (char *)⁡ 276cfa1ca9dSYoshinobu Inoue 277686cdd19SJun-ichiro itojun Hagino #ifdef HAVE_OLD_BPF 278cfa1ca9dSYoshinobu Inoue bpf_mtap(ifp, &m0); 279686cdd19SJun-ichiro itojun Hagino #else 280686cdd19SJun-ichiro itojun Hagino bpf_mtap(ifp->if_bpf, &m0); 281686cdd19SJun-ichiro itojun Hagino #endif 282cfa1ca9dSYoshinobu Inoue } 283686cdd19SJun-ichiro itojun Hagino #endif 284cfa1ca9dSYoshinobu Inoue ifp->if_opackets++; 285cfa1ca9dSYoshinobu Inoue ifp->if_obytes += m->m_pkthdr.len; 286cfa1ca9dSYoshinobu Inoue 287686cdd19SJun-ichiro itojun Hagino /* XXX should we check if our outer source is legal? */ 288686cdd19SJun-ichiro itojun Hagino 289cfa1ca9dSYoshinobu Inoue switch (sc->gif_psrc->sa_family) { 290cfa1ca9dSYoshinobu Inoue #ifdef INET 291cfa1ca9dSYoshinobu Inoue case AF_INET: 292cfa1ca9dSYoshinobu Inoue error = in_gif_output(ifp, dst->sa_family, m, rt); 293cfa1ca9dSYoshinobu Inoue break; 294cfa1ca9dSYoshinobu Inoue #endif 295cfa1ca9dSYoshinobu Inoue #ifdef INET6 296cfa1ca9dSYoshinobu Inoue case AF_INET6: 297cfa1ca9dSYoshinobu Inoue error = in6_gif_output(ifp, dst->sa_family, m, rt); 298cfa1ca9dSYoshinobu Inoue break; 299cfa1ca9dSYoshinobu Inoue #endif 300cfa1ca9dSYoshinobu Inoue default: 301cfa1ca9dSYoshinobu Inoue m_freem(m); 302cfa1ca9dSYoshinobu Inoue error = ENETDOWN; 303cfa1ca9dSYoshinobu Inoue } 304cfa1ca9dSYoshinobu Inoue 305cfa1ca9dSYoshinobu Inoue end: 306cfa1ca9dSYoshinobu Inoue called = 0; /* reset recursion counter */ 307cfa1ca9dSYoshinobu Inoue if (error) ifp->if_oerrors++; 308cfa1ca9dSYoshinobu Inoue return error; 309cfa1ca9dSYoshinobu Inoue } 310cfa1ca9dSYoshinobu Inoue 311cfa1ca9dSYoshinobu Inoue void 312cfa1ca9dSYoshinobu Inoue gif_input(m, af, gifp) 313cfa1ca9dSYoshinobu Inoue struct mbuf *m; 314cfa1ca9dSYoshinobu Inoue int af; 315cfa1ca9dSYoshinobu Inoue struct ifnet *gifp; 316cfa1ca9dSYoshinobu Inoue { 317df5e1987SJonathan Lemon int isr; 318cfa1ca9dSYoshinobu Inoue register struct ifqueue *ifq = 0; 319cfa1ca9dSYoshinobu Inoue 320cfa1ca9dSYoshinobu Inoue if (gifp == NULL) { 321cfa1ca9dSYoshinobu Inoue /* just in case */ 322cfa1ca9dSYoshinobu Inoue m_freem(m); 323cfa1ca9dSYoshinobu Inoue return; 324cfa1ca9dSYoshinobu Inoue } 325cfa1ca9dSYoshinobu Inoue 326cfa1ca9dSYoshinobu Inoue m->m_pkthdr.rcvif = gifp; 327cfa1ca9dSYoshinobu Inoue 328686cdd19SJun-ichiro itojun Hagino #if NBPFILTER > 0 329cfa1ca9dSYoshinobu Inoue if (gifp->if_bpf) { 330cfa1ca9dSYoshinobu Inoue /* 331cfa1ca9dSYoshinobu Inoue * We need to prepend the address family as 332cfa1ca9dSYoshinobu Inoue * a four byte field. Cons up a dummy header 333cfa1ca9dSYoshinobu Inoue * to pacify bpf. This is safe because bpf 334cfa1ca9dSYoshinobu Inoue * will only read from the mbuf (i.e., it won't 335cfa1ca9dSYoshinobu Inoue * try to free it or keep a pointer a to it). 336cfa1ca9dSYoshinobu Inoue */ 337cfa1ca9dSYoshinobu Inoue struct mbuf m0; 338cfa1ca9dSYoshinobu Inoue u_int af = AF_INET6; 339cfa1ca9dSYoshinobu Inoue 340cfa1ca9dSYoshinobu Inoue m0.m_next = m; 341cfa1ca9dSYoshinobu Inoue m0.m_len = 4; 342cfa1ca9dSYoshinobu Inoue m0.m_data = (char *)⁡ 343cfa1ca9dSYoshinobu Inoue 344686cdd19SJun-ichiro itojun Hagino #ifdef HAVE_OLD_BPF 345cfa1ca9dSYoshinobu Inoue bpf_mtap(gifp, &m0); 346686cdd19SJun-ichiro itojun Hagino #else 347686cdd19SJun-ichiro itojun Hagino bpf_mtap(gifp->if_bpf, &m0); 348686cdd19SJun-ichiro itojun Hagino #endif 349cfa1ca9dSYoshinobu Inoue } 350686cdd19SJun-ichiro itojun Hagino #endif /*NBPFILTER > 0*/ 351cfa1ca9dSYoshinobu Inoue 352cfa1ca9dSYoshinobu Inoue /* 353cfa1ca9dSYoshinobu Inoue * Put the packet to the network layer input queue according to the 354cfa1ca9dSYoshinobu Inoue * specified address family. 355cfa1ca9dSYoshinobu Inoue * Note: older versions of gif_input directly called network layer 356cfa1ca9dSYoshinobu Inoue * input functions, e.g. ip6_input, here. We changed the policy to 357cfa1ca9dSYoshinobu Inoue * prevent too many recursive calls of such input functions, which 358cfa1ca9dSYoshinobu Inoue * might cause kernel panic. But the change may introduce another 359cfa1ca9dSYoshinobu Inoue * problem; if the input queue is full, packets are discarded. 360cfa1ca9dSYoshinobu Inoue * We believed it rarely occurs and changed the policy. If we find 361cfa1ca9dSYoshinobu Inoue * it occurs more times than we thought, we may change the policy 362cfa1ca9dSYoshinobu Inoue * again. 363cfa1ca9dSYoshinobu Inoue */ 364cfa1ca9dSYoshinobu Inoue switch (af) { 365cfa1ca9dSYoshinobu Inoue #ifdef INET 366cfa1ca9dSYoshinobu Inoue case AF_INET: 367cfa1ca9dSYoshinobu Inoue ifq = &ipintrq; 368cfa1ca9dSYoshinobu Inoue isr = NETISR_IP; 369cfa1ca9dSYoshinobu Inoue break; 370cfa1ca9dSYoshinobu Inoue #endif 371cfa1ca9dSYoshinobu Inoue #ifdef INET6 372cfa1ca9dSYoshinobu Inoue case AF_INET6: 373cfa1ca9dSYoshinobu Inoue ifq = &ip6intrq; 374cfa1ca9dSYoshinobu Inoue isr = NETISR_IPV6; 375cfa1ca9dSYoshinobu Inoue break; 376cfa1ca9dSYoshinobu Inoue #endif 377cfa1ca9dSYoshinobu Inoue default: 378cfa1ca9dSYoshinobu Inoue m_freem(m); 379cfa1ca9dSYoshinobu Inoue return; 380cfa1ca9dSYoshinobu Inoue } 381cfa1ca9dSYoshinobu Inoue 382cfa1ca9dSYoshinobu Inoue gifp->if_ipackets++; 383cfa1ca9dSYoshinobu Inoue gifp->if_ibytes += m->m_pkthdr.len; 384df5e1987SJonathan Lemon (void) IF_HANDOFF(ifq, m, NULL); 385df5e1987SJonathan Lemon /* we need schednetisr since the address family may change */ 386df5e1987SJonathan Lemon schednetisr(isr); 387cfa1ca9dSYoshinobu Inoue 388cfa1ca9dSYoshinobu Inoue return; 389cfa1ca9dSYoshinobu Inoue } 390cfa1ca9dSYoshinobu Inoue 391686cdd19SJun-ichiro itojun Hagino /* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */ 392cfa1ca9dSYoshinobu Inoue int 393cfa1ca9dSYoshinobu Inoue gif_ioctl(ifp, cmd, data) 394cfa1ca9dSYoshinobu Inoue struct ifnet *ifp; 395cfa1ca9dSYoshinobu Inoue u_long cmd; 396cfa1ca9dSYoshinobu Inoue caddr_t data; 397cfa1ca9dSYoshinobu Inoue { 398cfa1ca9dSYoshinobu Inoue struct gif_softc *sc = (struct gif_softc*)ifp; 399cfa1ca9dSYoshinobu Inoue struct ifreq *ifr = (struct ifreq*)data; 400cfa1ca9dSYoshinobu Inoue int error = 0, size; 401686cdd19SJun-ichiro itojun Hagino struct sockaddr *dst, *src; 402686cdd19SJun-ichiro itojun Hagino struct sockaddr *sa; 403686cdd19SJun-ichiro itojun Hagino int i; 404a98dc5e6SYaroslav Tykhiy int s; 405686cdd19SJun-ichiro itojun Hagino struct gif_softc *sc2; 406cfa1ca9dSYoshinobu Inoue 407cfa1ca9dSYoshinobu Inoue switch (cmd) { 408cfa1ca9dSYoshinobu Inoue case SIOCSIFADDR: 409cfa1ca9dSYoshinobu Inoue break; 410cfa1ca9dSYoshinobu Inoue 411cfa1ca9dSYoshinobu Inoue case SIOCSIFDSTADDR: 412cfa1ca9dSYoshinobu Inoue break; 413cfa1ca9dSYoshinobu Inoue 414cfa1ca9dSYoshinobu Inoue case SIOCADDMULTI: 415cfa1ca9dSYoshinobu Inoue case SIOCDELMULTI: 416cfa1ca9dSYoshinobu Inoue break; 417cfa1ca9dSYoshinobu Inoue 418686cdd19SJun-ichiro itojun Hagino #ifdef SIOCSIFMTU /* xxx */ 419cfa1ca9dSYoshinobu Inoue case SIOCGIFMTU: 420cfa1ca9dSYoshinobu Inoue break; 421686cdd19SJun-ichiro itojun Hagino 422cfa1ca9dSYoshinobu Inoue case SIOCSIFMTU: 423cfa1ca9dSYoshinobu Inoue { 424cfa1ca9dSYoshinobu Inoue u_long mtu; 425cfa1ca9dSYoshinobu Inoue mtu = ifr->ifr_mtu; 426cfa1ca9dSYoshinobu Inoue if (mtu < GIF_MTU_MIN || mtu > GIF_MTU_MAX) { 427cfa1ca9dSYoshinobu Inoue return (EINVAL); 428cfa1ca9dSYoshinobu Inoue } 429cfa1ca9dSYoshinobu Inoue ifp->if_mtu = mtu; 430cfa1ca9dSYoshinobu Inoue } 431cfa1ca9dSYoshinobu Inoue break; 432686cdd19SJun-ichiro itojun Hagino #endif /* SIOCSIFMTU */ 433cfa1ca9dSYoshinobu Inoue 434cfa1ca9dSYoshinobu Inoue case SIOCSIFPHYADDR: 435cfa1ca9dSYoshinobu Inoue #ifdef INET6 436cfa1ca9dSYoshinobu Inoue case SIOCSIFPHYADDR_IN6: 437cfa1ca9dSYoshinobu Inoue #endif /* INET6 */ 438686cdd19SJun-ichiro itojun Hagino switch (cmd) { 439686cdd19SJun-ichiro itojun Hagino case SIOCSIFPHYADDR: 440cfa1ca9dSYoshinobu Inoue src = (struct sockaddr *) 441cfa1ca9dSYoshinobu Inoue &(((struct in_aliasreq *)data)->ifra_addr); 442cfa1ca9dSYoshinobu Inoue dst = (struct sockaddr *) 443cfa1ca9dSYoshinobu Inoue &(((struct in_aliasreq *)data)->ifra_dstaddr); 444cfa1ca9dSYoshinobu Inoue break; 445cfa1ca9dSYoshinobu Inoue #ifdef INET6 446686cdd19SJun-ichiro itojun Hagino case SIOCSIFPHYADDR_IN6: 447cfa1ca9dSYoshinobu Inoue src = (struct sockaddr *) 448cfa1ca9dSYoshinobu Inoue &(((struct in6_aliasreq *)data)->ifra_addr); 449cfa1ca9dSYoshinobu Inoue dst = (struct sockaddr *) 450cfa1ca9dSYoshinobu Inoue &(((struct in6_aliasreq *)data)->ifra_dstaddr); 451686cdd19SJun-ichiro itojun Hagino break; 452686cdd19SJun-ichiro itojun Hagino #endif 453686cdd19SJun-ichiro itojun Hagino } 454cfa1ca9dSYoshinobu Inoue 455686cdd19SJun-ichiro itojun Hagino for (i = 0; i < ngif; i++) { 456686cdd19SJun-ichiro itojun Hagino sc2 = gif + i; 457686cdd19SJun-ichiro itojun Hagino if (sc2 == sc) 458686cdd19SJun-ichiro itojun Hagino continue; 459686cdd19SJun-ichiro itojun Hagino if (!sc2->gif_pdst || !sc2->gif_psrc) 460686cdd19SJun-ichiro itojun Hagino continue; 461686cdd19SJun-ichiro itojun Hagino if (sc2->gif_pdst->sa_family != dst->sa_family || 462686cdd19SJun-ichiro itojun Hagino sc2->gif_pdst->sa_len != dst->sa_len || 463686cdd19SJun-ichiro itojun Hagino sc2->gif_psrc->sa_family != src->sa_family || 464686cdd19SJun-ichiro itojun Hagino sc2->gif_psrc->sa_len != src->sa_len) 465686cdd19SJun-ichiro itojun Hagino continue; 466914594eaSKris Kennaway #ifndef XBONEHACK 467686cdd19SJun-ichiro itojun Hagino /* can't configure same pair of address onto two gifs */ 468686cdd19SJun-ichiro itojun Hagino if (bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 && 469686cdd19SJun-ichiro itojun Hagino bcmp(sc2->gif_psrc, src, src->sa_len) == 0) { 470cfa1ca9dSYoshinobu Inoue error = EADDRNOTAVAIL; 471cfa1ca9dSYoshinobu Inoue goto bad; 472cfa1ca9dSYoshinobu Inoue } 473914594eaSKris Kennaway #endif 474686cdd19SJun-ichiro itojun Hagino 475686cdd19SJun-ichiro itojun Hagino /* can't configure multiple multi-dest interfaces */ 476686cdd19SJun-ichiro itojun Hagino #define multidest(x) \ 477686cdd19SJun-ichiro itojun Hagino (((struct sockaddr_in *)(x))->sin_addr.s_addr == INADDR_ANY) 478686cdd19SJun-ichiro itojun Hagino #ifdef INET6 479686cdd19SJun-ichiro itojun Hagino #define multidest6(x) \ 480686cdd19SJun-ichiro itojun Hagino (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)(x))->sin6_addr)) 481686cdd19SJun-ichiro itojun Hagino #endif 482686cdd19SJun-ichiro itojun Hagino if (dst->sa_family == AF_INET && 483686cdd19SJun-ichiro itojun Hagino multidest(dst) && multidest(sc2->gif_pdst)) { 484686cdd19SJun-ichiro itojun Hagino error = EADDRNOTAVAIL; 485686cdd19SJun-ichiro itojun Hagino goto bad; 486cfa1ca9dSYoshinobu Inoue } 487686cdd19SJun-ichiro itojun Hagino #ifdef INET6 488686cdd19SJun-ichiro itojun Hagino if (dst->sa_family == AF_INET6 && 489686cdd19SJun-ichiro itojun Hagino multidest6(dst) && multidest6(sc2->gif_pdst)) { 490686cdd19SJun-ichiro itojun Hagino error = EADDRNOTAVAIL; 491686cdd19SJun-ichiro itojun Hagino goto bad; 492cfa1ca9dSYoshinobu Inoue } 493686cdd19SJun-ichiro itojun Hagino #endif 494686cdd19SJun-ichiro itojun Hagino } 495686cdd19SJun-ichiro itojun Hagino 496686cdd19SJun-ichiro itojun Hagino if (src->sa_family != dst->sa_family || 497686cdd19SJun-ichiro itojun Hagino src->sa_len != dst->sa_len) { 498686cdd19SJun-ichiro itojun Hagino error = EINVAL; 499686cdd19SJun-ichiro itojun Hagino break; 500686cdd19SJun-ichiro itojun Hagino } 501686cdd19SJun-ichiro itojun Hagino switch (src->sa_family) { 502686cdd19SJun-ichiro itojun Hagino #ifdef INET 503686cdd19SJun-ichiro itojun Hagino case AF_INET: 504686cdd19SJun-ichiro itojun Hagino size = sizeof(struct sockaddr_in); 505686cdd19SJun-ichiro itojun Hagino break; 506686cdd19SJun-ichiro itojun Hagino #endif 507686cdd19SJun-ichiro itojun Hagino #ifdef INET6 508686cdd19SJun-ichiro itojun Hagino case AF_INET6: 509cfa1ca9dSYoshinobu Inoue size = sizeof(struct sockaddr_in6); 510cfa1ca9dSYoshinobu Inoue break; 511686cdd19SJun-ichiro itojun Hagino #endif 512cfa1ca9dSYoshinobu Inoue default: 513686cdd19SJun-ichiro itojun Hagino error = EAFNOSUPPORT; 514cfa1ca9dSYoshinobu Inoue goto bad; 515686cdd19SJun-ichiro itojun Hagino } 516686cdd19SJun-ichiro itojun Hagino if (src->sa_len != size) { 517686cdd19SJun-ichiro itojun Hagino error = EINVAL; 518cfa1ca9dSYoshinobu Inoue break; 519cfa1ca9dSYoshinobu Inoue } 520cfa1ca9dSYoshinobu Inoue 521686cdd19SJun-ichiro itojun Hagino if (sc->gif_psrc) 522686cdd19SJun-ichiro itojun Hagino free((caddr_t)sc->gif_psrc, M_IFADDR); 523cfa1ca9dSYoshinobu Inoue sa = (struct sockaddr *)malloc(size, M_IFADDR, M_WAITOK); 524cfa1ca9dSYoshinobu Inoue bcopy((caddr_t)src, (caddr_t)sa, size); 525cfa1ca9dSYoshinobu Inoue sc->gif_psrc = sa; 526cfa1ca9dSYoshinobu Inoue 527686cdd19SJun-ichiro itojun Hagino if (sc->gif_pdst) 528686cdd19SJun-ichiro itojun Hagino free((caddr_t)sc->gif_pdst, M_IFADDR); 529cfa1ca9dSYoshinobu Inoue sa = (struct sockaddr *)malloc(size, M_IFADDR, M_WAITOK); 530cfa1ca9dSYoshinobu Inoue bcopy((caddr_t)dst, (caddr_t)sa, size); 531cfa1ca9dSYoshinobu Inoue sc->gif_pdst = sa; 532cfa1ca9dSYoshinobu Inoue 533a98dc5e6SYaroslav Tykhiy ifp->if_flags |= IFF_RUNNING; 534a98dc5e6SYaroslav Tykhiy s = splimp(); 535a98dc5e6SYaroslav Tykhiy if_up(ifp); /* mark interface UP and send up RTM_IFINFO */ 536a98dc5e6SYaroslav Tykhiy splx(s); 537cfa1ca9dSYoshinobu Inoue 538686cdd19SJun-ichiro itojun Hagino error = 0; 539cfa1ca9dSYoshinobu Inoue break; 540cfa1ca9dSYoshinobu Inoue 541686cdd19SJun-ichiro itojun Hagino #ifdef SIOCDIFPHYADDR 542686cdd19SJun-ichiro itojun Hagino case SIOCDIFPHYADDR: 543686cdd19SJun-ichiro itojun Hagino if (sc->gif_psrc) { 544686cdd19SJun-ichiro itojun Hagino free((caddr_t)sc->gif_psrc, M_IFADDR); 545686cdd19SJun-ichiro itojun Hagino sc->gif_psrc = NULL; 546686cdd19SJun-ichiro itojun Hagino } 547686cdd19SJun-ichiro itojun Hagino if (sc->gif_pdst) { 548686cdd19SJun-ichiro itojun Hagino free((caddr_t)sc->gif_pdst, M_IFADDR); 549686cdd19SJun-ichiro itojun Hagino sc->gif_pdst = NULL; 550686cdd19SJun-ichiro itojun Hagino } 551686cdd19SJun-ichiro itojun Hagino /* change the IFF_UP flag as well? */ 552686cdd19SJun-ichiro itojun Hagino break; 553686cdd19SJun-ichiro itojun Hagino #endif 554686cdd19SJun-ichiro itojun Hagino 555cfa1ca9dSYoshinobu Inoue case SIOCGIFPSRCADDR: 556cfa1ca9dSYoshinobu Inoue #ifdef INET6 557cfa1ca9dSYoshinobu Inoue case SIOCGIFPSRCADDR_IN6: 558cfa1ca9dSYoshinobu Inoue #endif /* INET6 */ 559cfa1ca9dSYoshinobu Inoue if (sc->gif_psrc == NULL) { 560cfa1ca9dSYoshinobu Inoue error = EADDRNOTAVAIL; 561cfa1ca9dSYoshinobu Inoue goto bad; 562cfa1ca9dSYoshinobu Inoue } 563cfa1ca9dSYoshinobu Inoue src = sc->gif_psrc; 564cfa1ca9dSYoshinobu Inoue switch (sc->gif_psrc->sa_family) { 565cfa1ca9dSYoshinobu Inoue #ifdef INET 566cfa1ca9dSYoshinobu Inoue case AF_INET: 567cfa1ca9dSYoshinobu Inoue dst = &ifr->ifr_addr; 568cfa1ca9dSYoshinobu Inoue size = sizeof(struct sockaddr_in); 569cfa1ca9dSYoshinobu Inoue break; 570cfa1ca9dSYoshinobu Inoue #endif /* INET */ 571cfa1ca9dSYoshinobu Inoue #ifdef INET6 572cfa1ca9dSYoshinobu Inoue case AF_INET6: 573cfa1ca9dSYoshinobu Inoue dst = (struct sockaddr *) 574cfa1ca9dSYoshinobu Inoue &(((struct in6_ifreq *)data)->ifr_addr); 575cfa1ca9dSYoshinobu Inoue size = sizeof(struct sockaddr_in6); 576cfa1ca9dSYoshinobu Inoue break; 577cfa1ca9dSYoshinobu Inoue #endif /* INET6 */ 578cfa1ca9dSYoshinobu Inoue default: 579cfa1ca9dSYoshinobu Inoue error = EADDRNOTAVAIL; 580cfa1ca9dSYoshinobu Inoue goto bad; 581cfa1ca9dSYoshinobu Inoue } 582cfa1ca9dSYoshinobu Inoue bcopy((caddr_t)src, (caddr_t)dst, size); 583cfa1ca9dSYoshinobu Inoue break; 584cfa1ca9dSYoshinobu Inoue 585cfa1ca9dSYoshinobu Inoue case SIOCGIFPDSTADDR: 586cfa1ca9dSYoshinobu Inoue #ifdef INET6 587cfa1ca9dSYoshinobu Inoue case SIOCGIFPDSTADDR_IN6: 588cfa1ca9dSYoshinobu Inoue #endif /* INET6 */ 589cfa1ca9dSYoshinobu Inoue if (sc->gif_pdst == NULL) { 590cfa1ca9dSYoshinobu Inoue error = EADDRNOTAVAIL; 591cfa1ca9dSYoshinobu Inoue goto bad; 592cfa1ca9dSYoshinobu Inoue } 593cfa1ca9dSYoshinobu Inoue src = sc->gif_pdst; 594cfa1ca9dSYoshinobu Inoue switch (sc->gif_pdst->sa_family) { 595cfa1ca9dSYoshinobu Inoue #ifdef INET 596cfa1ca9dSYoshinobu Inoue case AF_INET: 597cfa1ca9dSYoshinobu Inoue dst = &ifr->ifr_addr; 598cfa1ca9dSYoshinobu Inoue size = sizeof(struct sockaddr_in); 599cfa1ca9dSYoshinobu Inoue break; 600cfa1ca9dSYoshinobu Inoue #endif /* INET */ 601cfa1ca9dSYoshinobu Inoue #ifdef INET6 602cfa1ca9dSYoshinobu Inoue case AF_INET6: 603cfa1ca9dSYoshinobu Inoue dst = (struct sockaddr *) 604cfa1ca9dSYoshinobu Inoue &(((struct in6_ifreq *)data)->ifr_addr); 605cfa1ca9dSYoshinobu Inoue size = sizeof(struct sockaddr_in6); 606cfa1ca9dSYoshinobu Inoue break; 607cfa1ca9dSYoshinobu Inoue #endif /* INET6 */ 608cfa1ca9dSYoshinobu Inoue default: 609cfa1ca9dSYoshinobu Inoue error = EADDRNOTAVAIL; 610cfa1ca9dSYoshinobu Inoue goto bad; 611cfa1ca9dSYoshinobu Inoue } 612cfa1ca9dSYoshinobu Inoue bcopy((caddr_t)src, (caddr_t)dst, size); 613cfa1ca9dSYoshinobu Inoue break; 614cfa1ca9dSYoshinobu Inoue 615cfa1ca9dSYoshinobu Inoue case SIOCSIFFLAGS: 616686cdd19SJun-ichiro itojun Hagino /* if_ioctl() takes care of it */ 617cfa1ca9dSYoshinobu Inoue break; 618cfa1ca9dSYoshinobu Inoue 619cfa1ca9dSYoshinobu Inoue default: 620cfa1ca9dSYoshinobu Inoue error = EINVAL; 621cfa1ca9dSYoshinobu Inoue break; 622cfa1ca9dSYoshinobu Inoue } 623cfa1ca9dSYoshinobu Inoue bad: 624cfa1ca9dSYoshinobu Inoue return error; 625cfa1ca9dSYoshinobu Inoue } 626686cdd19SJun-ichiro itojun Hagino #endif /*NGIF > 0*/ 627