if_gif.c revision 78064
162587Sitojun/* $FreeBSD: head/sys/net/if_gif.c 78064 2001-06-11 12:39:29Z ume $ */ 278064Sume/* $KAME: if_gif.c,v 1.47 2001/05/01 05:28:42 itojun Exp $ */ 362587Sitojun 454263Sshin/* 554263Sshin * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 654263Sshin * All rights reserved. 754263Sshin * 854263Sshin * Redistribution and use in source and binary forms, with or without 954263Sshin * modification, are permitted provided that the following conditions 1054263Sshin * are met: 1154263Sshin * 1. Redistributions of source code must retain the above copyright 1254263Sshin * notice, this list of conditions and the following disclaimer. 1354263Sshin * 2. Redistributions in binary form must reproduce the above copyright 1454263Sshin * notice, this list of conditions and the following disclaimer in the 1554263Sshin * documentation and/or other materials provided with the distribution. 1654263Sshin * 3. Neither the name of the project nor the names of its contributors 1754263Sshin * may be used to endorse or promote products derived from this software 1854263Sshin * without specific prior written permission. 1954263Sshin * 2054263Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 2154263Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2254263Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2354263Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2454263Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2554263Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2654263Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2754263Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2854263Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2954263Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3054263Sshin * SUCH DAMAGE. 3154263Sshin */ 3254263Sshin 3354263Sshin#include "opt_inet.h" 3454263Sshin#include "opt_inet6.h" 3554263Sshin 3654263Sshin#include <sys/param.h> 3754263Sshin#include <sys/systm.h> 3854263Sshin#include <sys/kernel.h> 3954263Sshin#include <sys/malloc.h> 4054263Sshin#include <sys/mbuf.h> 4154263Sshin#include <sys/socket.h> 4254263Sshin#include <sys/sockio.h> 4354263Sshin#include <sys/errno.h> 4454263Sshin#include <sys/time.h> 4554263Sshin#include <sys/syslog.h> 4662587Sitojun#include <sys/protosw.h> 4754263Sshin#include <machine/cpu.h> 4854263Sshin 4954263Sshin#include <net/if.h> 5054263Sshin#include <net/if_types.h> 5154263Sshin#include <net/netisr.h> 5254263Sshin#include <net/route.h> 5354263Sshin#include <net/bpf.h> 5454263Sshin 5554263Sshin#include <netinet/in.h> 5654263Sshin#include <netinet/in_systm.h> 5778064Sume#include <netinet/ip.h> 5878064Sume#ifdef INET 5954263Sshin#include <netinet/in_var.h> 6054263Sshin#include <netinet/in_gif.h> 6154263Sshin#endif /* INET */ 6254263Sshin 6354263Sshin#ifdef INET6 6454263Sshin#ifndef INET 6554263Sshin#include <netinet/in.h> 6654263Sshin#endif 6754263Sshin#include <netinet6/in6_var.h> 6854263Sshin#include <netinet/ip6.h> 6954263Sshin#include <netinet6/ip6_var.h> 7054263Sshin#include <netinet6/in6_gif.h> 7162587Sitojun#include <netinet6/ip6protosw.h> 7254263Sshin#endif /* INET6 */ 7354263Sshin 7462587Sitojun#include <netinet/ip_encap.h> 7554263Sshin#include <net/if_gif.h> 7654263Sshin 7754263Sshin#include "gif.h" 7862587Sitojun#include "bpf.h" 7962587Sitojun#define NBPFILTER NBPF 8054263Sshin 8154263Sshin#include <net/net_osdep.h> 8254263Sshin 8362587Sitojun#if NGIF > 0 8462587Sitojun 8554263Sshinvoid gifattach __P((void *)); 8662587Sitojunstatic int gif_encapcheck __P((const struct mbuf *, int, int, void *)); 8762587Sitojun#ifdef INET 8862587Sitojunextern struct protosw in_gif_protosw; 8962587Sitojun#endif 9062587Sitojun#ifdef INET6 9162587Sitojunextern struct ip6protosw in6_gif_protosw; 9262587Sitojun#endif 9354263Sshin 9454263Sshin/* 9554263Sshin * gif global variable definitions 9654263Sshin */ 9762587Sitojunstatic int ngif; /* number of interfaces */ 9862587Sitojunstatic struct gif_softc *gif = 0; 9954263Sshin 10062587Sitojun#ifndef MAX_GIF_NEST 10162587Sitojun/* 10262587Sitojun * This macro controls the upper limitation on nesting of gif tunnels. 10362587Sitojun * Since, setting a large value to this macro with a careless configuration 10462587Sitojun * may introduce system crash, we don't allow any nestings by default. 10562587Sitojun * If you need to configure nested gif tunnels, you can define this macro 10662587Sitojun * in your kernel configuration file. However, if you do so, please be 10762587Sitojun * careful to configure the tunnels so that it won't make a loop. 10862587Sitojun */ 10962587Sitojun#define MAX_GIF_NEST 1 11062587Sitojun#endif 11162587Sitojunstatic int max_gif_nesting = MAX_GIF_NEST; 11262587Sitojun 11354263Sshinvoid 11454263Sshingifattach(dummy) 11554263Sshin void *dummy; 11654263Sshin{ 11778064Sume struct gif_softc *sc; 11878064Sume int i; 11954263Sshin 12062587Sitojun ngif = NGIF; 12178064Sume gif = sc = malloc(ngif * sizeof(struct gif_softc), M_DEVBUF, M_WAITOK); 12254263Sshin bzero(sc, ngif * sizeof(struct gif_softc)); 12362587Sitojun for (i = 0; i < ngif; sc++, i++) { 12454263Sshin sc->gif_if.if_name = "gif"; 12554263Sshin sc->gif_if.if_unit = i; 12662587Sitojun 12762587Sitojun sc->encap_cookie4 = sc->encap_cookie6 = NULL; 12862587Sitojun#ifdef INET 12962587Sitojun sc->encap_cookie4 = encap_attach_func(AF_INET, -1, 13062587Sitojun gif_encapcheck, &in_gif_protosw, sc); 13162587Sitojun if (sc->encap_cookie4 == NULL) { 13262587Sitojun printf("%s: attach failed\n", if_name(&sc->gif_if)); 13362587Sitojun continue; 13462587Sitojun } 13562587Sitojun#endif 13662587Sitojun#ifdef INET6 13762587Sitojun sc->encap_cookie6 = encap_attach_func(AF_INET6, -1, 13862587Sitojun gif_encapcheck, (struct protosw *)&in6_gif_protosw, sc); 13962587Sitojun if (sc->encap_cookie6 == NULL) { 14062587Sitojun if (sc->encap_cookie4) { 14162587Sitojun encap_detach(sc->encap_cookie4); 14262587Sitojun sc->encap_cookie4 = NULL; 14362587Sitojun } 14462587Sitojun printf("%s: attach failed\n", if_name(&sc->gif_if)); 14562587Sitojun continue; 14662587Sitojun } 14762587Sitojun#endif 14862587Sitojun 14954263Sshin sc->gif_if.if_mtu = GIF_MTU; 15054263Sshin sc->gif_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST; 15178064Sume#if 0 15278064Sume /* turn off ingress filter */ 15378064Sume sc->gif_if.if_flags |= IFF_LINK2; 15478064Sume#endif 15554263Sshin sc->gif_if.if_ioctl = gif_ioctl; 15654263Sshin sc->gif_if.if_output = gif_output; 15754263Sshin sc->gif_if.if_type = IFT_GIF; 15862587Sitojun sc->gif_if.if_snd.ifq_maxlen = IFQ_MAXLEN; 15954263Sshin if_attach(&sc->gif_if); 16062587Sitojun#if NBPFILTER > 0 16162587Sitojun#ifdef HAVE_OLD_BPF 16254263Sshin bpfattach(&sc->gif_if, DLT_NULL, sizeof(u_int)); 16362587Sitojun#else 16462587Sitojun bpfattach(&sc->gif_if.if_bpf, &sc->gif_if, DLT_NULL, sizeof(u_int)); 16562587Sitojun#endif 16662587Sitojun#endif 16754263Sshin } 16854263Sshin} 16954263Sshin 17054263SshinPSEUDO_SET(gifattach, if_gif); 17154263Sshin 17262587Sitojunstatic int 17362587Sitojungif_encapcheck(m, off, proto, arg) 17462587Sitojun const struct mbuf *m; 17562587Sitojun int off; 17662587Sitojun int proto; 17762587Sitojun void *arg; 17862587Sitojun{ 17962587Sitojun struct ip ip; 18062587Sitojun struct gif_softc *sc; 18162587Sitojun 18262587Sitojun sc = (struct gif_softc *)arg; 18362587Sitojun if (sc == NULL) 18462587Sitojun return 0; 18562587Sitojun 18662587Sitojun if ((sc->gif_if.if_flags & IFF_UP) == 0) 18762587Sitojun return 0; 18862587Sitojun 18962587Sitojun /* no physical address */ 19062587Sitojun if (!sc->gif_psrc || !sc->gif_pdst) 19162587Sitojun return 0; 19262587Sitojun 19362587Sitojun switch (proto) { 19462587Sitojun#ifdef INET 19562587Sitojun case IPPROTO_IPV4: 19662587Sitojun break; 19762587Sitojun#endif 19862587Sitojun#ifdef INET6 19962587Sitojun case IPPROTO_IPV6: 20062587Sitojun break; 20162587Sitojun#endif 20262587Sitojun default: 20362587Sitojun return 0; 20462587Sitojun } 20562587Sitojun 20662587Sitojun /* LINTED const cast */ 20762587Sitojun m_copydata((struct mbuf *)m, 0, sizeof(ip), (caddr_t)&ip); 20862587Sitojun 20962587Sitojun switch (ip.ip_v) { 21062587Sitojun#ifdef INET 21162587Sitojun case 4: 21262587Sitojun if (sc->gif_psrc->sa_family != AF_INET || 21362587Sitojun sc->gif_pdst->sa_family != AF_INET) 21462587Sitojun return 0; 21562587Sitojun return gif_encapcheck4(m, off, proto, arg); 21662587Sitojun#endif 21762587Sitojun#ifdef INET6 21862587Sitojun case 6: 21962587Sitojun if (sc->gif_psrc->sa_family != AF_INET6 || 22062587Sitojun sc->gif_pdst->sa_family != AF_INET6) 22162587Sitojun return 0; 22262587Sitojun return gif_encapcheck6(m, off, proto, arg); 22362587Sitojun#endif 22462587Sitojun default: 22562587Sitojun return 0; 22662587Sitojun } 22762587Sitojun} 22862587Sitojun 22954263Sshinint 23054263Sshingif_output(ifp, m, dst, rt) 23154263Sshin struct ifnet *ifp; 23254263Sshin struct mbuf *m; 23354263Sshin struct sockaddr *dst; 23454263Sshin struct rtentry *rt; /* added in net2 */ 23554263Sshin{ 23678064Sume struct gif_softc *sc = (struct gif_softc*)ifp; 23754263Sshin int error = 0; 23854263Sshin static int called = 0; /* XXX: MUTEX */ 23954263Sshin 24054263Sshin /* 24154263Sshin * gif may cause infinite recursion calls when misconfigured. 24254263Sshin * We'll prevent this by introducing upper limit. 24354263Sshin * XXX: this mechanism may introduce another problem about 24454263Sshin * mutual exclusion of the variable CALLED, especially if we 24554263Sshin * use kernel thread. 24654263Sshin */ 24762587Sitojun if (++called > max_gif_nesting) { 24854263Sshin log(LOG_NOTICE, 24954263Sshin "gif_output: recursively called too many times(%d)\n", 25054263Sshin called); 25154263Sshin m_freem(m); 25254263Sshin error = EIO; /* is there better errno? */ 25354263Sshin goto end; 25454263Sshin } 25562587Sitojun 25654263Sshin getmicrotime(&ifp->if_lastchange); 25754263Sshin m->m_flags &= ~(M_BCAST|M_MCAST); 25854263Sshin if (!(ifp->if_flags & IFF_UP) || 25954263Sshin sc->gif_psrc == NULL || sc->gif_pdst == NULL) { 26054263Sshin m_freem(m); 26154263Sshin error = ENETDOWN; 26254263Sshin goto end; 26354263Sshin } 26454263Sshin 26562587Sitojun#if NBPFILTER > 0 26654263Sshin if (ifp->if_bpf) { 26754263Sshin /* 26854263Sshin * We need to prepend the address family as 26954263Sshin * a four byte field. Cons up a dummy header 27054263Sshin * to pacify bpf. This is safe because bpf 27154263Sshin * will only read from the mbuf (i.e., it won't 27254263Sshin * try to free it or keep a pointer a to it). 27354263Sshin */ 27454263Sshin struct mbuf m0; 27578064Sume u_int32_t af = dst->sa_family; 27654263Sshin 27754263Sshin m0.m_next = m; 27854263Sshin m0.m_len = 4; 27954263Sshin m0.m_data = (char *)⁡ 28062587Sitojun 28162587Sitojun#ifdef HAVE_OLD_BPF 28254263Sshin bpf_mtap(ifp, &m0); 28362587Sitojun#else 28462587Sitojun bpf_mtap(ifp->if_bpf, &m0); 28562587Sitojun#endif 28654263Sshin } 28762587Sitojun#endif 28862587Sitojun ifp->if_opackets++; 28954263Sshin ifp->if_obytes += m->m_pkthdr.len; 29054263Sshin 29178064Sume /* inner AF-specific encapsulation */ 29278064Sume 29362587Sitojun /* XXX should we check if our outer source is legal? */ 29462587Sitojun 29578064Sume /* dispatch to output logic based on outer AF */ 29654263Sshin switch (sc->gif_psrc->sa_family) { 29754263Sshin#ifdef INET 29854263Sshin case AF_INET: 29954263Sshin error = in_gif_output(ifp, dst->sa_family, m, rt); 30054263Sshin break; 30154263Sshin#endif 30254263Sshin#ifdef INET6 30354263Sshin case AF_INET6: 30454263Sshin error = in6_gif_output(ifp, dst->sa_family, m, rt); 30554263Sshin break; 30654263Sshin#endif 30754263Sshin default: 30862587Sitojun m_freem(m); 30954263Sshin error = ENETDOWN; 31078064Sume goto end; 31154263Sshin } 31254263Sshin 31354263Sshin end: 31454263Sshin called = 0; /* reset recursion counter */ 31578064Sume if (error) 31678064Sume ifp->if_oerrors++; 31754263Sshin return error; 31854263Sshin} 31954263Sshin 32054263Sshinvoid 32154263Sshingif_input(m, af, gifp) 32254263Sshin struct mbuf *m; 32354263Sshin int af; 32454263Sshin struct ifnet *gifp; 32554263Sshin{ 32669152Sjlemon int isr; 32778064Sume struct ifqueue *ifq = 0; 32854263Sshin 32954263Sshin if (gifp == NULL) { 33054263Sshin /* just in case */ 33154263Sshin m_freem(m); 33254263Sshin return; 33354263Sshin } 33454263Sshin 33562587Sitojun m->m_pkthdr.rcvif = gifp; 33662587Sitojun 33762587Sitojun#if NBPFILTER > 0 33854263Sshin if (gifp->if_bpf) { 33954263Sshin /* 34054263Sshin * We need to prepend the address family as 34154263Sshin * a four byte field. Cons up a dummy header 34254263Sshin * to pacify bpf. This is safe because bpf 34354263Sshin * will only read from the mbuf (i.e., it won't 34454263Sshin * try to free it or keep a pointer a to it). 34554263Sshin */ 34654263Sshin struct mbuf m0; 34778064Sume u_int32_t af1 = af; 34862587Sitojun 34954263Sshin m0.m_next = m; 35054263Sshin m0.m_len = 4; 35178064Sume m0.m_data = (char *)&af1; 35262587Sitojun 35362587Sitojun#ifdef HAVE_OLD_BPF 35454263Sshin bpf_mtap(gifp, &m0); 35562587Sitojun#else 35662587Sitojun bpf_mtap(gifp->if_bpf, &m0); 35762587Sitojun#endif 35854263Sshin } 35962587Sitojun#endif /*NBPFILTER > 0*/ 36054263Sshin 36154263Sshin /* 36254263Sshin * Put the packet to the network layer input queue according to the 36354263Sshin * specified address family. 36454263Sshin * Note: older versions of gif_input directly called network layer 36554263Sshin * input functions, e.g. ip6_input, here. We changed the policy to 36654263Sshin * prevent too many recursive calls of such input functions, which 36754263Sshin * might cause kernel panic. But the change may introduce another 36854263Sshin * problem; if the input queue is full, packets are discarded. 36954263Sshin * We believed it rarely occurs and changed the policy. If we find 37054263Sshin * it occurs more times than we thought, we may change the policy 37154263Sshin * again. 37254263Sshin */ 37354263Sshin switch (af) { 37454263Sshin#ifdef INET 37554263Sshin case AF_INET: 37654263Sshin ifq = &ipintrq; 37754263Sshin isr = NETISR_IP; 37854263Sshin break; 37954263Sshin#endif 38054263Sshin#ifdef INET6 38154263Sshin case AF_INET6: 38254263Sshin ifq = &ip6intrq; 38354263Sshin isr = NETISR_IPV6; 38454263Sshin break; 38554263Sshin#endif 38654263Sshin default: 38754263Sshin m_freem(m); 38854263Sshin return; 38954263Sshin } 39054263Sshin 39169152Sjlemon gifp->if_ipackets++; 39269152Sjlemon gifp->if_ibytes += m->m_pkthdr.len; 39369152Sjlemon (void) IF_HANDOFF(ifq, m, NULL); 39454263Sshin /* we need schednetisr since the address family may change */ 39554263Sshin schednetisr(isr); 39654263Sshin 39754263Sshin return; 39854263Sshin} 39954263Sshin 40062587Sitojun/* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */ 40154263Sshinint 40254263Sshingif_ioctl(ifp, cmd, data) 40354263Sshin struct ifnet *ifp; 40454263Sshin u_long cmd; 40554263Sshin caddr_t data; 40654263Sshin{ 40754263Sshin struct gif_softc *sc = (struct gif_softc*)ifp; 40854263Sshin struct ifreq *ifr = (struct ifreq*)data; 40954263Sshin int error = 0, size; 41062587Sitojun struct sockaddr *dst, *src; 41162587Sitojun struct sockaddr *sa; 41262587Sitojun int i; 41377658Syar int s; 41462587Sitojun struct gif_softc *sc2; 41562587Sitojun 41654263Sshin switch (cmd) { 41754263Sshin case SIOCSIFADDR: 41854263Sshin break; 41962587Sitojun 42054263Sshin case SIOCSIFDSTADDR: 42154263Sshin break; 42254263Sshin 42354263Sshin case SIOCADDMULTI: 42454263Sshin case SIOCDELMULTI: 42554263Sshin break; 42654263Sshin 42762587Sitojun#ifdef SIOCSIFMTU /* xxx */ 42854263Sshin case SIOCGIFMTU: 42954263Sshin break; 43062587Sitojun 43154263Sshin case SIOCSIFMTU: 43254263Sshin { 43354263Sshin u_long mtu; 43454263Sshin mtu = ifr->ifr_mtu; 43554263Sshin if (mtu < GIF_MTU_MIN || mtu > GIF_MTU_MAX) { 43654263Sshin return (EINVAL); 43754263Sshin } 43854263Sshin ifp->if_mtu = mtu; 43954263Sshin } 44054263Sshin break; 44162587Sitojun#endif /* SIOCSIFMTU */ 44254263Sshin 44354263Sshin case SIOCSIFPHYADDR: 44454263Sshin#ifdef INET6 44554263Sshin case SIOCSIFPHYADDR_IN6: 44654263Sshin#endif /* INET6 */ 44778064Sume case SIOCSLIFPHYADDR: 44862587Sitojun switch (cmd) { 44978064Sume#ifdef INET 45062587Sitojun case SIOCSIFPHYADDR: 45154263Sshin src = (struct sockaddr *) 45254263Sshin &(((struct in_aliasreq *)data)->ifra_addr); 45354263Sshin dst = (struct sockaddr *) 45454263Sshin &(((struct in_aliasreq *)data)->ifra_dstaddr); 45562587Sitojun break; 45678064Sume#endif 45762587Sitojun#ifdef INET6 45862587Sitojun case SIOCSIFPHYADDR_IN6: 45962587Sitojun src = (struct sockaddr *) 46062587Sitojun &(((struct in6_aliasreq *)data)->ifra_addr); 46162587Sitojun dst = (struct sockaddr *) 46262587Sitojun &(((struct in6_aliasreq *)data)->ifra_dstaddr); 46362587Sitojun break; 46462587Sitojun#endif 46578064Sume case SIOCSLIFPHYADDR: 46678064Sume src = (struct sockaddr *) 46778064Sume &(((struct if_laddrreq *)data)->addr); 46878064Sume dst = (struct sockaddr *) 46978064Sume &(((struct if_laddrreq *)data)->dstaddr); 47062587Sitojun } 47154263Sshin 47278064Sume /* sa_family must be equal */ 47378064Sume if (src->sa_family != dst->sa_family) 47478064Sume return EINVAL; 47578064Sume 47678064Sume /* validate sa_len */ 47778064Sume switch (src->sa_family) { 47878064Sume#ifdef INET 47978064Sume case AF_INET: 48078064Sume if (src->sa_len != sizeof(struct sockaddr_in)) 48178064Sume return EINVAL; 48278064Sume break; 48378064Sume#endif 48478064Sume#ifdef INET6 48578064Sume case AF_INET6: 48678064Sume if (src->sa_len != sizeof(struct sockaddr_in6)) 48778064Sume return EINVAL; 48878064Sume break; 48978064Sume#endif 49078064Sume default: 49178064Sume return EAFNOSUPPORT; 49278064Sume } 49378064Sume switch (dst->sa_family) { 49478064Sume#ifdef INET 49578064Sume case AF_INET: 49678064Sume if (dst->sa_len != sizeof(struct sockaddr_in)) 49778064Sume return EINVAL; 49878064Sume break; 49978064Sume#endif 50078064Sume#ifdef INET6 50178064Sume case AF_INET6: 50278064Sume if (dst->sa_len != sizeof(struct sockaddr_in6)) 50378064Sume return EINVAL; 50478064Sume break; 50578064Sume#endif 50678064Sume default: 50778064Sume return EAFNOSUPPORT; 50878064Sume } 50978064Sume 51078064Sume /* check sa_family looks sane for the cmd */ 51178064Sume switch (cmd) { 51278064Sume case SIOCSIFPHYADDR: 51378064Sume if (src->sa_family == AF_INET) 51478064Sume break; 51578064Sume return EAFNOSUPPORT; 51678064Sume#ifdef INET6 51778064Sume case SIOCSIFPHYADDR_IN6: 51878064Sume if (src->sa_family == AF_INET6) 51978064Sume break; 52078064Sume return EAFNOSUPPORT; 52178064Sume#endif /* INET6 */ 52278064Sume case SIOCSLIFPHYADDR: 52378064Sume /* checks done in the above */ 52478064Sume break; 52578064Sume } 52678064Sume 52762587Sitojun for (i = 0; i < ngif; i++) { 52862587Sitojun sc2 = gif + i; 52962587Sitojun if (sc2 == sc) 53062587Sitojun continue; 53162587Sitojun if (!sc2->gif_pdst || !sc2->gif_psrc) 53262587Sitojun continue; 53362587Sitojun if (sc2->gif_pdst->sa_family != dst->sa_family || 53462587Sitojun sc2->gif_pdst->sa_len != dst->sa_len || 53562587Sitojun sc2->gif_psrc->sa_family != src->sa_family || 53662587Sitojun sc2->gif_psrc->sa_len != src->sa_len) 53762587Sitojun continue; 53863577Skris#ifndef XBONEHACK 53962587Sitojun /* can't configure same pair of address onto two gifs */ 54062587Sitojun if (bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 && 54162587Sitojun bcmp(sc2->gif_psrc, src, src->sa_len) == 0) { 54262587Sitojun error = EADDRNOTAVAIL; 54362587Sitojun goto bad; 54462587Sitojun } 54563577Skris#endif 54654263Sshin 54762587Sitojun /* can't configure multiple multi-dest interfaces */ 54862587Sitojun#define multidest(x) \ 54962587Sitojun (((struct sockaddr_in *)(x))->sin_addr.s_addr == INADDR_ANY) 55057903Sshin#ifdef INET6 55162587Sitojun#define multidest6(x) \ 55262587Sitojun (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)(x))->sin6_addr)) 55357903Sshin#endif 55462587Sitojun if (dst->sa_family == AF_INET && 55562587Sitojun multidest(dst) && multidest(sc2->gif_pdst)) { 55662587Sitojun error = EADDRNOTAVAIL; 55762587Sitojun goto bad; 55862587Sitojun } 55962587Sitojun#ifdef INET6 56062587Sitojun if (dst->sa_family == AF_INET6 && 56162587Sitojun multidest6(dst) && multidest6(sc2->gif_pdst)) { 56262587Sitojun error = EADDRNOTAVAIL; 56362587Sitojun goto bad; 56462587Sitojun } 56562587Sitojun#endif 56662587Sitojun } 56757903Sshin 56862587Sitojun if (sc->gif_psrc) 56954263Sshin free((caddr_t)sc->gif_psrc, M_IFADDR); 57078064Sume sa = (struct sockaddr *)malloc(src->sa_len, M_IFADDR, M_WAITOK); 57178064Sume bcopy((caddr_t)src, (caddr_t)sa, src->sa_len); 57254263Sshin sc->gif_psrc = sa; 57354263Sshin 57462587Sitojun if (sc->gif_pdst) 57562587Sitojun free((caddr_t)sc->gif_pdst, M_IFADDR); 57678064Sume sa = (struct sockaddr *)malloc(dst->sa_len, M_IFADDR, M_WAITOK); 57778064Sume bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len); 57854263Sshin sc->gif_pdst = sa; 57954263Sshin 58077658Syar ifp->if_flags |= IFF_RUNNING; 58177658Syar s = splimp(); 58277658Syar if_up(ifp); /* mark interface UP and send up RTM_IFINFO */ 58377658Syar splx(s); 58454263Sshin 58562587Sitojun error = 0; 58662587Sitojun break; 58762587Sitojun 58862587Sitojun#ifdef SIOCDIFPHYADDR 58962587Sitojun case SIOCDIFPHYADDR: 59062587Sitojun if (sc->gif_psrc) { 59162587Sitojun free((caddr_t)sc->gif_psrc, M_IFADDR); 59262587Sitojun sc->gif_psrc = NULL; 59357536Sshin } 59462587Sitojun if (sc->gif_pdst) { 59562587Sitojun free((caddr_t)sc->gif_pdst, M_IFADDR); 59662587Sitojun sc->gif_pdst = NULL; 59762587Sitojun } 59878064Sume /* change the IFF_{UP, RUNNING} flag as well? */ 59954263Sshin break; 60062587Sitojun#endif 60162587Sitojun 60254263Sshin case SIOCGIFPSRCADDR: 60354263Sshin#ifdef INET6 60454263Sshin case SIOCGIFPSRCADDR_IN6: 60554263Sshin#endif /* INET6 */ 60654263Sshin if (sc->gif_psrc == NULL) { 60754263Sshin error = EADDRNOTAVAIL; 60854263Sshin goto bad; 60954263Sshin } 61054263Sshin src = sc->gif_psrc; 61178064Sume switch (cmd) { 61254263Sshin#ifdef INET 61378064Sume case SIOCGIFPSRCADDR: 61454263Sshin dst = &ifr->ifr_addr; 61578064Sume size = sizeof(ifr->ifr_addr); 61654263Sshin break; 61754263Sshin#endif /* INET */ 61854263Sshin#ifdef INET6 61978064Sume case SIOCGIFPSRCADDR_IN6: 62054263Sshin dst = (struct sockaddr *) 62154263Sshin &(((struct in6_ifreq *)data)->ifr_addr); 62278064Sume size = sizeof(((struct in6_ifreq *)data)->ifr_addr); 62354263Sshin break; 62454263Sshin#endif /* INET6 */ 62554263Sshin default: 62654263Sshin error = EADDRNOTAVAIL; 62754263Sshin goto bad; 62854263Sshin } 62978064Sume if (src->sa_len > size) 63078064Sume return EINVAL; 63178064Sume bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 63254263Sshin break; 63362587Sitojun 63454263Sshin case SIOCGIFPDSTADDR: 63554263Sshin#ifdef INET6 63654263Sshin case SIOCGIFPDSTADDR_IN6: 63754263Sshin#endif /* INET6 */ 63854263Sshin if (sc->gif_pdst == NULL) { 63954263Sshin error = EADDRNOTAVAIL; 64054263Sshin goto bad; 64154263Sshin } 64254263Sshin src = sc->gif_pdst; 64378064Sume switch (cmd) { 64454263Sshin#ifdef INET 64578064Sume case SIOCGIFPDSTADDR: 64654263Sshin dst = &ifr->ifr_addr; 64778064Sume size = sizeof(ifr->ifr_addr); 64854263Sshin break; 64954263Sshin#endif /* INET */ 65054263Sshin#ifdef INET6 65178064Sume case SIOCGIFPDSTADDR_IN6: 65254263Sshin dst = (struct sockaddr *) 65354263Sshin &(((struct in6_ifreq *)data)->ifr_addr); 65478064Sume size = sizeof(((struct in6_ifreq *)data)->ifr_addr); 65554263Sshin break; 65654263Sshin#endif /* INET6 */ 65754263Sshin default: 65854263Sshin error = EADDRNOTAVAIL; 65954263Sshin goto bad; 66054263Sshin } 66178064Sume if (src->sa_len > size) 66278064Sume return EINVAL; 66378064Sume bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 66454263Sshin break; 66554263Sshin 66678064Sume case SIOCGLIFPHYADDR: 66778064Sume if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) { 66878064Sume error = EADDRNOTAVAIL; 66978064Sume goto bad; 67078064Sume } 67178064Sume 67278064Sume /* copy src */ 67378064Sume src = sc->gif_psrc; 67478064Sume dst = (struct sockaddr *) 67578064Sume &(((struct if_laddrreq *)data)->addr); 67678064Sume size = sizeof(((struct if_laddrreq *)data)->addr); 67778064Sume if (src->sa_len > size) 67878064Sume return EINVAL; 67978064Sume bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 68078064Sume 68178064Sume /* copy dst */ 68278064Sume src = sc->gif_pdst; 68378064Sume dst = (struct sockaddr *) 68478064Sume &(((struct if_laddrreq *)data)->dstaddr); 68578064Sume size = sizeof(((struct if_laddrreq *)data)->dstaddr); 68678064Sume if (src->sa_len > size) 68778064Sume return EINVAL; 68878064Sume bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 68978064Sume break; 69078064Sume 69154263Sshin case SIOCSIFFLAGS: 69262587Sitojun /* if_ioctl() takes care of it */ 69354263Sshin break; 69454263Sshin 69554263Sshin default: 69654263Sshin error = EINVAL; 69754263Sshin break; 69854263Sshin } 69954263Sshin bad: 70054263Sshin return error; 70154263Sshin} 70262587Sitojun#endif /*NGIF > 0*/ 703