if_gre.c revision 179894
1111314Snyan/* $NetBSD: if_gre.c,v 1.49 2003/12/11 00:22:29 itojun Exp $ */ 2111314Snyan/* $FreeBSD: head/sys/net/if_gre.c 179894 2008-06-20 17:26:34Z thompsa $ */ 3111314Snyan 4111314Snyan/*- 5111314Snyan * Copyright (c) 1998 The NetBSD Foundation, Inc. 6111314Snyan * All rights reserved. 7111314Snyan * 8111314Snyan * This code is derived from software contributed to The NetBSD Foundation 9111314Snyan * by Heiko W.Rupp <hwr@pilhuhn.de> 10111314Snyan * 11111314Snyan * IPv6-over-GRE contributed by Gert Doering <gert@greenie.muc.de> 12111314Snyan * 13111314Snyan * Redistribution and use in source and binary forms, with or without 14111314Snyan * modification, are permitted provided that the following conditions 15111314Snyan * are met: 16111314Snyan * 1. Redistributions of source code must retain the above copyright 17111314Snyan * notice, this list of conditions and the following disclaimer. 18111314Snyan * 2. Redistributions in binary form must reproduce the above copyright 19111314Snyan * notice, this list of conditions and the following disclaimer in the 20111314Snyan * documentation and/or other materials provided with the distribution. 21111314Snyan * 3. All advertising materials mentioning features or use of this software 22111314Snyan * must display the following acknowledgement: 23111314Snyan * This product includes software developed by the NetBSD 24111314Snyan * Foundation, Inc. and its contributors. 25111314Snyan * 4. Neither the name of The NetBSD Foundation nor the names of its 26122056Snyan * contributors may be used to endorse or promote products derived 27111314Snyan * from this software without specific prior written permission. 28111314Snyan * 29111314Snyan * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 30111314Snyan * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 31111314Snyan * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 32111314Snyan * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 33111314Snyan * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 34111314Snyan * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 35111314Snyan * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 36111314Snyan * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 37111314Snyan * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 38111314Snyan * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 39122056Snyan * POSSIBILITY OF SUCH DAMAGE. 40111314Snyan */ 41111314Snyan 42111314Snyan/* 43111314Snyan * Encapsulate L3 protocols into IP 44111314Snyan * See RFC 2784 (successor of RFC 1701 and 1702) for more details. 45111314Snyan * If_gre is compatible with Cisco GRE tunnels, so you can 46111314Snyan * have a NetBSD box as the other end of a tunnel interface of a Cisco 47111314Snyan * router. See gre(4) for more details. 48111314Snyan * Also supported: IP in IP encaps (proto 55) as of RFC 2004 49111314Snyan */ 50111314Snyan 51111314Snyan#include "opt_atalk.h" 52111314Snyan#include "opt_inet.h" 53111314Snyan#include "opt_inet6.h" 54111314Snyan 55111314Snyan#include <sys/param.h> 56111314Snyan#include <sys/kernel.h> 57111314Snyan#include <sys/malloc.h> 58111314Snyan#include <sys/module.h> 59111314Snyan#include <sys/mbuf.h> 60111314Snyan#include <sys/priv.h> 61111314Snyan#include <sys/proc.h> 62111314Snyan#include <sys/protosw.h> 63111314Snyan#include <sys/socket.h> 64111314Snyan#include <sys/sockio.h> 65111314Snyan#include <sys/sysctl.h> 66111314Snyan#include <sys/systm.h> 67111314Snyan 68111314Snyan#include <net/ethernet.h> 69111314Snyan#include <net/if.h> 70111314Snyan#include <net/if_clone.h> 71111314Snyan#include <net/if_types.h> 72111314Snyan#include <net/route.h> 73111314Snyan 74111314Snyan#ifdef INET 75111314Snyan#include <netinet/in.h> 76111314Snyan#include <netinet/in_systm.h> 77111314Snyan#include <netinet/in_var.h> 78111314Snyan#include <netinet/ip.h> 79111314Snyan#include <netinet/ip_gre.h> 80111314Snyan#include <netinet/ip_var.h> 81111314Snyan#include <netinet/ip_encap.h> 82111314Snyan#else 83111314Snyan#error "Huh? if_gre without inet?" 84111314Snyan#endif 85111314Snyan 86111314Snyan#include <net/bpf.h> 87111314Snyan 88111314Snyan#include <net/if_gre.h> 89111314Snyan 90111314Snyan/* 91111314Snyan * It is not easy to calculate the right value for a GRE MTU. 92111314Snyan * We leave this task to the admin and use the same default that 93111314Snyan * other vendors use. 94111314Snyan */ 95111314Snyan#define GREMTU 1476 96111314Snyan 97111314Snyan#define GRENAME "gre" 98111314Snyan 99111314Snyan/* 100111314Snyan * gre_mtx protects all global variables in if_gre.c. 101111314Snyan * XXX: gre_softc data not protected yet. 102111314Snyan */ 103111314Snyanstruct mtx gre_mtx; 104111314Snyanstatic MALLOC_DEFINE(M_GRE, GRENAME, "Generic Routing Encapsulation"); 105111314Snyan 106111314Snyanstruct gre_softc_head gre_softc_list; 107111314Snyan 108111314Snyanstatic int gre_clone_create(struct if_clone *, int, caddr_t); 109111314Snyanstatic void gre_clone_destroy(struct ifnet *); 110111314Snyanstatic int gre_ioctl(struct ifnet *, u_long, caddr_t); 111111314Snyanstatic int gre_output(struct ifnet *, struct mbuf *, struct sockaddr *, 112111314Snyan struct rtentry *rt); 113111314Snyan 114111314SnyanIFC_SIMPLE_DECLARE(gre, 0); 115111314Snyan 116111314Snyanstatic int gre_compute_route(struct gre_softc *sc); 117111314Snyan 118111314Snyanstatic void greattach(void); 119111314Snyan 120111314Snyan#ifdef INET 121111314Snyanextern struct domain inetdomain; 122111314Snyanstatic const struct protosw in_gre_protosw = { 123111314Snyan .pr_type = SOCK_RAW, 124111314Snyan .pr_domain = &inetdomain, 125111314Snyan .pr_protocol = IPPROTO_GRE, 126111314Snyan .pr_flags = PR_ATOMIC|PR_ADDR, 127111314Snyan .pr_input = gre_input, 128111314Snyan .pr_output = (pr_output_t *)rip_output, 129111314Snyan .pr_ctlinput = rip_ctlinput, 130111314Snyan .pr_ctloutput = rip_ctloutput, 131111314Snyan .pr_usrreqs = &rip_usrreqs 132111314Snyan}; 133111314Snyanstatic const struct protosw in_mobile_protosw = { 134111314Snyan .pr_type = SOCK_RAW, 135111314Snyan .pr_domain = &inetdomain, 136111314Snyan .pr_protocol = IPPROTO_MOBILE, 137111314Snyan .pr_flags = PR_ATOMIC|PR_ADDR, 138111314Snyan .pr_input = gre_mobile_input, 139111314Snyan .pr_output = (pr_output_t *)rip_output, 140111314Snyan .pr_ctlinput = rip_ctlinput, 141111314Snyan .pr_ctloutput = rip_ctloutput, 142111314Snyan .pr_usrreqs = &rip_usrreqs 143111314Snyan}; 144111314Snyan#endif 145111314Snyan 146111314SnyanSYSCTL_DECL(_net_link); 147111314SnyanSYSCTL_NODE(_net_link, IFT_TUNNEL, gre, CTLFLAG_RW, 0, 148111314Snyan "Generic Routing Encapsulation"); 149111314Snyan#ifndef MAX_GRE_NEST 150111314Snyan/* 151111314Snyan * This macro controls the default upper limitation on nesting of gre tunnels. 152111314Snyan * Since, setting a large value to this macro with a careless configuration 153111314Snyan * may introduce system crash, we don't allow any nestings by default. 154111314Snyan * If you need to configure nested gre tunnels, you can define this macro 155111314Snyan * in your kernel configuration file. However, if you do so, please be 156111314Snyan * careful to configure the tunnels so that it won't make a loop. 157111314Snyan */ 158111314Snyan#define MAX_GRE_NEST 1 159111314Snyan#endif 160111314Snyanstatic int max_gre_nesting = MAX_GRE_NEST; 161111314SnyanSYSCTL_INT(_net_link_gre, OID_AUTO, max_nesting, CTLFLAG_RW, 162111314Snyan &max_gre_nesting, 0, "Max nested tunnels"); 163111314Snyan 164111314Snyan/* ARGSUSED */ 165111314Snyanstatic void 166111314Snyangreattach(void) 167111314Snyan{ 168111314Snyan 169111314Snyan mtx_init(&gre_mtx, "gre_mtx", NULL, MTX_DEF); 170111314Snyan LIST_INIT(&gre_softc_list); 171111314Snyan if_clone_attach(&gre_cloner); 172111314Snyan} 173111314Snyan 174111314Snyanstatic int 175111314Snyangre_clone_create(ifc, unit, params) 176111314Snyan struct if_clone *ifc; 177111314Snyan int unit; 178111314Snyan caddr_t params; 179111314Snyan{ 180111314Snyan struct gre_softc *sc; 181111314Snyan 182111314Snyan sc = malloc(sizeof(struct gre_softc), M_GRE, M_WAITOK | M_ZERO); 183111314Snyan 184111314Snyan GRE2IFP(sc) = if_alloc(IFT_TUNNEL); 185111314Snyan if (GRE2IFP(sc) == NULL) { 186111314Snyan free(sc, M_GRE); 187111314Snyan return (ENOSPC); 188111314Snyan } 189111314Snyan 190111314Snyan GRE2IFP(sc)->if_softc = sc; 191111314Snyan if_initname(GRE2IFP(sc), ifc->ifc_name, unit); 192111314Snyan 193111314Snyan GRE2IFP(sc)->if_snd.ifq_maxlen = IFQ_MAXLEN; 194111314Snyan GRE2IFP(sc)->if_addrlen = 0; 195111314Snyan GRE2IFP(sc)->if_hdrlen = 24; /* IP + GRE */ 196111314Snyan GRE2IFP(sc)->if_mtu = GREMTU; 197111314Snyan GRE2IFP(sc)->if_flags = IFF_POINTOPOINT|IFF_MULTICAST; 198111314Snyan GRE2IFP(sc)->if_output = gre_output; 199111314Snyan GRE2IFP(sc)->if_ioctl = gre_ioctl; 200111314Snyan sc->g_dst.s_addr = sc->g_src.s_addr = INADDR_ANY; 201111314Snyan sc->g_proto = IPPROTO_GRE; 202111314Snyan GRE2IFP(sc)->if_flags |= IFF_LINK0; 203111314Snyan sc->encap = NULL; 204111314Snyan sc->called = 0; 205111314Snyan sc->gre_fibnum = curthread->td_proc->p_fibnum; 206111314Snyan sc->wccp_ver = WCCP_V1; 207111314Snyan sc->key = 0; 208111314Snyan if_attach(GRE2IFP(sc)); 209111314Snyan bpfattach(GRE2IFP(sc), DLT_NULL, sizeof(u_int32_t)); 210111314Snyan mtx_lock(&gre_mtx); 211111314Snyan LIST_INSERT_HEAD(&gre_softc_list, sc, sc_list); 212111314Snyan mtx_unlock(&gre_mtx); 213111314Snyan return (0); 214111314Snyan} 215111314Snyan 216111314Snyanstatic void 217111314Snyangre_clone_destroy(ifp) 218111314Snyan struct ifnet *ifp; 219111314Snyan{ 220111314Snyan struct gre_softc *sc = ifp->if_softc; 221111314Snyan 222111314Snyan mtx_lock(&gre_mtx); 223111314Snyan LIST_REMOVE(sc, sc_list); 224111314Snyan mtx_unlock(&gre_mtx); 225111314Snyan 226111314Snyan#ifdef INET 227111314Snyan if (sc->encap != NULL) 228111314Snyan encap_detach(sc->encap); 229111314Snyan#endif 230111314Snyan bpfdetach(ifp); 231111314Snyan if_detach(ifp); 232111314Snyan if_free(ifp); 233111314Snyan free(sc, M_GRE); 234111314Snyan} 235111314Snyan 236111314Snyan/* 237111314Snyan * The output routine. Takes a packet and encapsulates it in the protocol 238111314Snyan * given by sc->g_proto. See also RFC 1701 and RFC 2004 239111314Snyan */ 240111314Snyanstatic int 241111314Snyangre_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, 242111314Snyan struct rtentry *rt) 243111314Snyan{ 244111314Snyan int error = 0; 245111314Snyan struct gre_softc *sc = ifp->if_softc; 246111314Snyan struct greip *gh; 247111314Snyan struct ip *ip; 248111314Snyan u_short ip_id = 0; 249111314Snyan uint8_t ip_tos = 0; 250111314Snyan u_int16_t etype = 0; 251111314Snyan struct mobile_h mob_h; 252111314Snyan u_int32_t af; 253111314Snyan 254111314Snyan /* 255111314Snyan * gre may cause infinite recursion calls when misconfigured. 256111314Snyan * We'll prevent this by introducing upper limit. 257111314Snyan */ 258111314Snyan if (++(sc->called) > max_gre_nesting) { 259111314Snyan printf("%s: gre_output: recursively called too many " 260111314Snyan "times(%d)\n", if_name(GRE2IFP(sc)), sc->called); 261111314Snyan m_freem(m); 262111314Snyan error = EIO; /* is there better errno? */ 263111314Snyan goto end; 264111314Snyan } 265111314Snyan 266111314Snyan if (!((ifp->if_flags & IFF_UP) && 267111314Snyan (ifp->if_drv_flags & IFF_DRV_RUNNING)) || 268111314Snyan sc->g_src.s_addr == INADDR_ANY || sc->g_dst.s_addr == INADDR_ANY) { 269111314Snyan m_freem(m); 270111314Snyan error = ENETDOWN; 271111314Snyan goto end; 272111314Snyan } 273111314Snyan 274111314Snyan gh = NULL; 275111314Snyan ip = NULL; 276111314Snyan 277111314Snyan /* BPF writes need to be handled specially. */ 278111314Snyan if (dst->sa_family == AF_UNSPEC) { 279111314Snyan bcopy(dst->sa_data, &af, sizeof(af)); 280111314Snyan dst->sa_family = af; 281111314Snyan } 282111314Snyan 283111314Snyan if (bpf_peers_present(ifp->if_bpf)) { 284111314Snyan af = dst->sa_family; 285111314Snyan bpf_mtap2(ifp->if_bpf, &af, sizeof(af), m); 286111314Snyan } 287111314Snyan 288111314Snyan m->m_flags &= ~(M_BCAST|M_MCAST); 289111314Snyan 290111314Snyan if (sc->g_proto == IPPROTO_MOBILE) { 291111314Snyan if (dst->sa_family == AF_INET) { 292111314Snyan struct mbuf *m0; 293111314Snyan int msiz; 294111314Snyan 295111314Snyan ip = mtod(m, struct ip *); 296111314Snyan 297111314Snyan /* 298111314Snyan * RFC2004 specifies that fragmented diagrams shouldn't 299111314Snyan * be encapsulated. 300111314Snyan */ 301111314Snyan if (ip->ip_off & (IP_MF | IP_OFFMASK)) { 302111314Snyan _IF_DROP(&ifp->if_snd); 303111314Snyan m_freem(m); 304111314Snyan error = EINVAL; /* is there better errno? */ 305111314Snyan goto end; 306111314Snyan } 307111314Snyan memset(&mob_h, 0, MOB_H_SIZ_L); 308111314Snyan mob_h.proto = (ip->ip_p) << 8; 309111314Snyan mob_h.odst = ip->ip_dst.s_addr; 310111314Snyan ip->ip_dst.s_addr = sc->g_dst.s_addr; 311111314Snyan 312111314Snyan /* 313111314Snyan * If the packet comes from our host, we only change 314111314Snyan * the destination address in the IP header. 315111314Snyan * Else we also need to save and change the source 316111314Snyan */ 317111314Snyan if (in_hosteq(ip->ip_src, sc->g_src)) { 318111314Snyan msiz = MOB_H_SIZ_S; 319111314Snyan } else { 320111314Snyan mob_h.proto |= MOB_H_SBIT; 321111314Snyan mob_h.osrc = ip->ip_src.s_addr; 322111314Snyan ip->ip_src.s_addr = sc->g_src.s_addr; 323111314Snyan msiz = MOB_H_SIZ_L; 324111314Snyan } 325111314Snyan mob_h.proto = htons(mob_h.proto); 326111314Snyan mob_h.hcrc = gre_in_cksum((u_int16_t *)&mob_h, msiz); 327111314Snyan 328111314Snyan if ((m->m_data - msiz) < m->m_pktdat) { 329111314Snyan /* need new mbuf */ 330111314Snyan MGETHDR(m0, M_DONTWAIT, MT_DATA); 331111314Snyan if (m0 == NULL) { 332111314Snyan _IF_DROP(&ifp->if_snd); 333111314Snyan m_freem(m); 334111314Snyan error = ENOBUFS; 335111314Snyan goto end; 336111314Snyan } 337111314Snyan m0->m_next = m; 338111314Snyan m->m_data += sizeof(struct ip); 339111314Snyan m->m_len -= sizeof(struct ip); 340111314Snyan m0->m_pkthdr.len = m->m_pkthdr.len + msiz; 341111314Snyan m0->m_len = msiz + sizeof(struct ip); 342111314Snyan m0->m_data += max_linkhdr; 343111314Snyan memcpy(mtod(m0, caddr_t), (caddr_t)ip, 344111314Snyan sizeof(struct ip)); 345111314Snyan m = m0; 346111314Snyan } else { /* we have some space left in the old one */ 347111314Snyan m->m_data -= msiz; 348111314Snyan m->m_len += msiz; 349111314Snyan m->m_pkthdr.len += msiz; 350111314Snyan bcopy(ip, mtod(m, caddr_t), 351111314Snyan sizeof(struct ip)); 352111314Snyan } 353111314Snyan ip = mtod(m, struct ip *); 354111314Snyan memcpy((caddr_t)(ip + 1), &mob_h, (unsigned)msiz); 355111314Snyan ip->ip_len = ntohs(ip->ip_len) + msiz; 356111314Snyan } else { /* AF_INET */ 357111314Snyan _IF_DROP(&ifp->if_snd); 358111314Snyan m_freem(m); 359111314Snyan error = EINVAL; 360111314Snyan goto end; 361111314Snyan } 362112034Snyan } else if (sc->g_proto == IPPROTO_GRE) { 363112034Snyan switch (dst->sa_family) { 364119985Snyan case AF_INET: 365119985Snyan ip = mtod(m, struct ip *); 366112034Snyan ip_tos = ip->ip_tos; 367111314Snyan ip_id = ip->ip_id; 368112034Snyan etype = ETHERTYPE_IP; 369112034Snyan break; 370111314Snyan#ifdef INET6 371111314Snyan case AF_INET6: 372111314Snyan ip_id = ip_newid(); 373111314Snyan etype = ETHERTYPE_IPV6; 374119985Snyan break; 375111314Snyan#endif 376111314Snyan#ifdef NETATALK 377111314Snyan case AF_APPLETALK: 378111314Snyan etype = ETHERTYPE_ATALK; 379111314Snyan break; 380111314Snyan#endif 381111314Snyan default: 382111314Snyan _IF_DROP(&ifp->if_snd); 383111314Snyan m_freem(m); 384111314Snyan error = EAFNOSUPPORT; 385111314Snyan goto end; 386111314Snyan } 387111314Snyan 388111314Snyan /* Reserve space for GRE header + optional GRE key */ 389111314Snyan int hdrlen = sizeof(struct greip); 390111314Snyan if (sc->key) 391111314Snyan hdrlen += sizeof(uint32_t); 392111314Snyan M_PREPEND(m, hdrlen, M_DONTWAIT); 393111314Snyan } else { 394111314Snyan _IF_DROP(&ifp->if_snd); 395111314Snyan m_freem(m); 396111314Snyan error = EINVAL; 397111314Snyan goto end; 398111314Snyan } 399111314Snyan 400111314Snyan if (m == NULL) { /* mbuf allocation failed */ 401111314Snyan _IF_DROP(&ifp->if_snd); 402111314Snyan error = ENOBUFS; 403111314Snyan goto end; 404111314Snyan } 405111314Snyan 406111314Snyan M_SETFIB(m, sc->gre_fibnum); /* The envelope may use a different FIB */ 407111314Snyan 408111314Snyan gh = mtod(m, struct greip *); 409111314Snyan if (sc->g_proto == IPPROTO_GRE) { 410111314Snyan uint32_t *options = gh->gi_options; 411111314Snyan 412111314Snyan memset((void *)gh, 0, sizeof(struct greip)); 413111314Snyan gh->gi_ptype = htons(etype); 414111314Snyan gh->gi_flags = 0; 415111314Snyan 416111314Snyan /* Add key option */ 417111314Snyan if (sc->key) 418111314Snyan { 419111314Snyan gh->gi_flags |= htons(GRE_KP); 420111314Snyan *(options++) = htonl(sc->key); 421111314Snyan } 422111314Snyan } 423111314Snyan 424111314Snyan gh->gi_pr = sc->g_proto; 425111314Snyan if (sc->g_proto != IPPROTO_MOBILE) { 426111314Snyan gh->gi_src = sc->g_src; 427111314Snyan gh->gi_dst = sc->g_dst; 428111314Snyan ((struct ip*)gh)->ip_v = IPPROTO_IPV4; 429111314Snyan ((struct ip*)gh)->ip_hl = (sizeof(struct ip)) >> 2; 430111314Snyan ((struct ip*)gh)->ip_ttl = GRE_TTL; 431111314Snyan ((struct ip*)gh)->ip_tos = ip_tos; 432111314Snyan ((struct ip*)gh)->ip_id = ip_id; 433111314Snyan gh->gi_len = m->m_pkthdr.len; 434111314Snyan } 435112840Smdodd 436112840Smdodd ifp->if_opackets++; 437112840Smdodd ifp->if_obytes += m->m_pkthdr.len; 438112840Smdodd /* 439112840Smdodd * Send it off and with IP_FORWARD flag to prevent it from 440111314Snyan * overwriting the ip_id again. ip_id is already set to the 441111314Snyan * ip_id of the encapsulated packet. 442111314Snyan */ 443111314Snyan error = ip_output(m, NULL, &sc->route, IP_FORWARDING, 444111314Snyan (struct ip_moptions *)NULL, (struct inpcb *)NULL); 445111314Snyan end: 446111314Snyan sc->called = 0; 447111314Snyan if (error) 448111314Snyan ifp->if_oerrors++; 449111314Snyan return (error); 450111314Snyan} 451111314Snyan 452111314Snyanstatic int 453111314Snyangre_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 454111314Snyan{ 455111314Snyan struct ifreq *ifr = (struct ifreq *)data; 456111314Snyan struct if_laddrreq *lifr = (struct if_laddrreq *)data; 457111314Snyan struct in_aliasreq *aifr = (struct in_aliasreq *)data; 458111314Snyan struct gre_softc *sc = ifp->if_softc; 459111314Snyan int s; 460111314Snyan struct sockaddr_in si; 461111314Snyan struct sockaddr *sa = NULL; 462111314Snyan int error, adj; 463111314Snyan struct sockaddr_in sp, sm, dp, dm; 464111314Snyan uint32_t key; 465111314Snyan 466111314Snyan error = 0; 467111314Snyan adj = 0; 468111314Snyan 469111314Snyan s = splnet(); 470111314Snyan switch (cmd) { 471111314Snyan case SIOCSIFADDR: 472111314Snyan ifp->if_flags |= IFF_UP; 473111314Snyan break; 474111314Snyan case SIOCSIFDSTADDR: 475111314Snyan break; 476111314Snyan case SIOCSIFFLAGS: 477111314Snyan /* 478111314Snyan * XXXRW: Isn't this priv_check() redundant to the ifnet 479111314Snyan * layer check? 480111314Snyan */ 481111314Snyan if ((error = priv_check(curthread, PRIV_NET_SETIFFLAGS)) != 0) 482111314Snyan break; 483111314Snyan if ((ifr->ifr_flags & IFF_LINK0) != 0) 484111314Snyan sc->g_proto = IPPROTO_GRE; 485111314Snyan else 486111314Snyan sc->g_proto = IPPROTO_MOBILE; 487111314Snyan if ((ifr->ifr_flags & IFF_LINK2) != 0) 488111314Snyan sc->wccp_ver = WCCP_V2; 489111314Snyan else 490111314Snyan sc->wccp_ver = WCCP_V1; 491111314Snyan goto recompute; 492111314Snyan case SIOCSIFMTU: 493111314Snyan /* 494111314Snyan * XXXRW: Isn't this priv_check() redundant to the ifnet 495111314Snyan * layer check? 496117918Snyan */ 497117918Snyan if ((error = priv_check(curthread, PRIV_NET_SETIFMTU)) != 0) 498117918Snyan break; 499117918Snyan if (ifr->ifr_mtu < 576) { 500117918Snyan error = EINVAL; 501117918Snyan break; 502117918Snyan } 503117918Snyan ifp->if_mtu = ifr->ifr_mtu; 504117918Snyan break; 505117918Snyan case SIOCGIFMTU: 506111314Snyan ifr->ifr_mtu = GRE2IFP(sc)->if_mtu; 507111314Snyan break; 508111314Snyan case SIOCADDMULTI: 509111314Snyan /* 510111314Snyan * XXXRW: Isn't this priv_checkr() redundant to the ifnet 511111314Snyan * layer check? 512111314Snyan */ 513111314Snyan if ((error = priv_check(curthread, PRIV_NET_ADDMULTI)) != 0) 514111314Snyan break; 515111314Snyan if (ifr == 0) { 516111314Snyan error = EAFNOSUPPORT; 517111314Snyan break; 518111314Snyan } 519111314Snyan switch (ifr->ifr_addr.sa_family) { 520111314Snyan#ifdef INET 521111314Snyan case AF_INET: 522111314Snyan break; 523111314Snyan#endif 524111314Snyan#ifdef INET6 525111314Snyan case AF_INET6: 526111314Snyan break; 527111314Snyan#endif 528111314Snyan default: 529111314Snyan error = EAFNOSUPPORT; 530111314Snyan break; 531111314Snyan } 532111314Snyan break; 533111314Snyan case SIOCDELMULTI: 534111314Snyan /* 535111314Snyan * XXXRW: Isn't this priv_check() redundant to the ifnet 536111314Snyan * layer check? 537111314Snyan */ 538111314Snyan if ((error = priv_check(curthread, PRIV_NET_DELIFGROUP)) != 0) 539111314Snyan break; 540111314Snyan if (ifr == 0) { 541111314Snyan error = EAFNOSUPPORT; 542111314Snyan break; 543111314Snyan } 544111314Snyan switch (ifr->ifr_addr.sa_family) { 545111314Snyan#ifdef INET 546111314Snyan case AF_INET: 547111314Snyan break; 548111314Snyan#endif 549111314Snyan#ifdef INET6 550111314Snyan case AF_INET6: 551111314Snyan break; 552111314Snyan#endif 553111314Snyan default: 554111314Snyan error = EAFNOSUPPORT; 555111314Snyan break; 556111314Snyan } 557111314Snyan break; 558111314Snyan case GRESPROTO: 559111314Snyan /* 560111314Snyan * XXXRW: Isn't this priv_check() redundant to the ifnet 561111314Snyan * layer check? 562111314Snyan */ 563111314Snyan if ((error = priv_check(curthread, PRIV_NET_GRE)) != 0) 564111314Snyan break; 565111314Snyan sc->g_proto = ifr->ifr_flags; 566111314Snyan switch (sc->g_proto) { 567111314Snyan case IPPROTO_GRE: 568111314Snyan ifp->if_flags |= IFF_LINK0; 569111314Snyan break; 570111314Snyan case IPPROTO_MOBILE: 571111314Snyan ifp->if_flags &= ~IFF_LINK0; 572111314Snyan break; 573111314Snyan default: 574111314Snyan error = EPROTONOSUPPORT; 575111314Snyan break; 576111314Snyan } 577111314Snyan goto recompute; 578111314Snyan case GREGPROTO: 579111314Snyan ifr->ifr_flags = sc->g_proto; 580111314Snyan break; 581111314Snyan case GRESADDRS: 582111314Snyan case GRESADDRD: 583115469Sphk error = priv_check(curthread, PRIV_NET_GRE); 584111314Snyan if (error) 585111314Snyan return (error); 586111314Snyan /* 587111314Snyan * set tunnel endpoints, compute a less specific route 588111314Snyan * to the remote end and mark if as up 589111314Snyan */ 590111314Snyan sa = &ifr->ifr_addr; 591111314Snyan if (cmd == GRESADDRS) 592111314Snyan sc->g_src = (satosin(sa))->sin_addr; 593111314Snyan if (cmd == GRESADDRD) 594111314Snyan sc->g_dst = (satosin(sa))->sin_addr; 595111314Snyan recompute: 596111314Snyan#ifdef INET 597111314Snyan if (sc->encap != NULL) { 598111314Snyan encap_detach(sc->encap); 599111314Snyan sc->encap = NULL; 600111314Snyan } 601111314Snyan#endif 602111314Snyan if ((sc->g_src.s_addr != INADDR_ANY) && 603111314Snyan (sc->g_dst.s_addr != INADDR_ANY)) { 604111314Snyan bzero(&sp, sizeof(sp)); 605111314Snyan bzero(&sm, sizeof(sm)); 606111314Snyan bzero(&dp, sizeof(dp)); 607111314Snyan bzero(&dm, sizeof(dm)); 608111314Snyan sp.sin_len = sm.sin_len = dp.sin_len = dm.sin_len = 609111314Snyan sizeof(struct sockaddr_in); 610111314Snyan sp.sin_family = sm.sin_family = dp.sin_family = 611111314Snyan dm.sin_family = AF_INET; 612111314Snyan sp.sin_addr = sc->g_src; 613111314Snyan dp.sin_addr = sc->g_dst; 614111314Snyan sm.sin_addr.s_addr = dm.sin_addr.s_addr = 615111314Snyan INADDR_BROADCAST; 616111314Snyan#ifdef INET 617111314Snyan sc->encap = encap_attach(AF_INET, sc->g_proto, 618111314Snyan sintosa(&sp), sintosa(&sm), sintosa(&dp), 619111314Snyan sintosa(&dm), (sc->g_proto == IPPROTO_GRE) ? 620111314Snyan &in_gre_protosw : &in_mobile_protosw, sc); 621111314Snyan if (sc->encap == NULL) 622111314Snyan printf("%s: unable to attach encap\n", 623111314Snyan if_name(GRE2IFP(sc))); 624111314Snyan#endif 625111314Snyan if (sc->route.ro_rt != 0) /* free old route */ 626111314Snyan RTFREE(sc->route.ro_rt); 627111314Snyan if (gre_compute_route(sc) == 0) 628111314Snyan ifp->if_drv_flags |= IFF_DRV_RUNNING; 629111314Snyan else 630111314Snyan ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 631111314Snyan } 632111314Snyan break; 633111314Snyan case GREGADDRS: 634111314Snyan memset(&si, 0, sizeof(si)); 635111314Snyan si.sin_family = AF_INET; 636111314Snyan si.sin_len = sizeof(struct sockaddr_in); 637111314Snyan si.sin_addr.s_addr = sc->g_src.s_addr; 638111314Snyan sa = sintosa(&si); 639111314Snyan ifr->ifr_addr = *sa; 640111314Snyan break; 641111314Snyan case GREGADDRD: 642111314Snyan memset(&si, 0, sizeof(si)); 643111314Snyan si.sin_family = AF_INET; 644111314Snyan si.sin_len = sizeof(struct sockaddr_in); 645111314Snyan si.sin_addr.s_addr = sc->g_dst.s_addr; 646111314Snyan sa = sintosa(&si); 647111314Snyan ifr->ifr_addr = *sa; 648111314Snyan break; 649111314Snyan case SIOCSIFPHYADDR: 650111314Snyan /* 651111314Snyan * XXXRW: Isn't this priv_check() redundant to the ifnet 652111314Snyan * layer check? 653111314Snyan */ 654111314Snyan if ((error = priv_check(curthread, PRIV_NET_SETIFPHYS)) != 0) 655111314Snyan break; 656111314Snyan if (aifr->ifra_addr.sin_family != AF_INET || 657111314Snyan aifr->ifra_dstaddr.sin_family != AF_INET) { 658111314Snyan error = EAFNOSUPPORT; 659111314Snyan break; 660111314Snyan } 661111314Snyan if (aifr->ifra_addr.sin_len != sizeof(si) || 662111314Snyan aifr->ifra_dstaddr.sin_len != sizeof(si)) { 663111314Snyan error = EINVAL; 664111314Snyan break; 665111314Snyan } 666111314Snyan sc->g_src = aifr->ifra_addr.sin_addr; 667111314Snyan sc->g_dst = aifr->ifra_dstaddr.sin_addr; 668111314Snyan goto recompute; 669111314Snyan case SIOCSLIFPHYADDR: 670111314Snyan /* 671111314Snyan * XXXRW: Isn't this priv_check() redundant to the ifnet 672111314Snyan * layer check? 673111314Snyan */ 674111314Snyan if ((error = priv_check(curthread, PRIV_NET_SETIFPHYS)) != 0) 675111314Snyan break; 676111314Snyan if (lifr->addr.ss_family != AF_INET || 677111314Snyan lifr->dstaddr.ss_family != AF_INET) { 678111314Snyan error = EAFNOSUPPORT; 679111314Snyan break; 680111314Snyan } 681111314Snyan if (lifr->addr.ss_len != sizeof(si) || 682111314Snyan lifr->dstaddr.ss_len != sizeof(si)) { 683111314Snyan error = EINVAL; 684111314Snyan break; 685111314Snyan } 686111314Snyan sc->g_src = (satosin(&lifr->addr))->sin_addr; 687111314Snyan sc->g_dst = 688111314Snyan (satosin(&lifr->dstaddr))->sin_addr; 689111314Snyan goto recompute; 690111314Snyan case SIOCDIFPHYADDR: 691111314Snyan /* 692111314Snyan * XXXRW: Isn't this priv_check() redundant to the ifnet 693111314Snyan * layer check? 694111314Snyan */ 695111314Snyan if ((error = priv_check(curthread, PRIV_NET_SETIFPHYS)) != 0) 696111314Snyan break; 697111314Snyan sc->g_src.s_addr = INADDR_ANY; 698111314Snyan sc->g_dst.s_addr = INADDR_ANY; 699111314Snyan goto recompute; 700111314Snyan case SIOCGLIFPHYADDR: 701111314Snyan if (sc->g_src.s_addr == INADDR_ANY || 702111314Snyan sc->g_dst.s_addr == INADDR_ANY) { 703111314Snyan error = EADDRNOTAVAIL; 704111314Snyan break; 705111314Snyan } 706111314Snyan memset(&si, 0, sizeof(si)); 707111314Snyan si.sin_family = AF_INET; 708111314Snyan si.sin_len = sizeof(struct sockaddr_in); 709111314Snyan si.sin_addr.s_addr = sc->g_src.s_addr; 710111314Snyan memcpy(&lifr->addr, &si, sizeof(si)); 711111314Snyan si.sin_addr.s_addr = sc->g_dst.s_addr; 712111314Snyan memcpy(&lifr->dstaddr, &si, sizeof(si)); 713111314Snyan break; 714111314Snyan case SIOCGIFPSRCADDR: 715111314Snyan#ifdef INET6 716111314Snyan case SIOCGIFPSRCADDR_IN6: 717111314Snyan#endif 718111314Snyan if (sc->g_src.s_addr == INADDR_ANY) { 719111314Snyan error = EADDRNOTAVAIL; 720111314Snyan break; 721111314Snyan } 722111314Snyan memset(&si, 0, sizeof(si)); 723111314Snyan si.sin_family = AF_INET; 724111314Snyan si.sin_len = sizeof(struct sockaddr_in); 725111314Snyan si.sin_addr.s_addr = sc->g_src.s_addr; 726111314Snyan bcopy(&si, &ifr->ifr_addr, sizeof(ifr->ifr_addr)); 727111314Snyan break; 728111314Snyan case SIOCGIFPDSTADDR: 729111314Snyan#ifdef INET6 730111314Snyan case SIOCGIFPDSTADDR_IN6: 731111314Snyan#endif 732111314Snyan if (sc->g_dst.s_addr == INADDR_ANY) { 733111314Snyan error = EADDRNOTAVAIL; 734111314Snyan break; 735111314Snyan } 736111314Snyan memset(&si, 0, sizeof(si)); 737111314Snyan si.sin_family = AF_INET; 738111314Snyan si.sin_len = sizeof(struct sockaddr_in); 739111314Snyan si.sin_addr.s_addr = sc->g_dst.s_addr; 740111314Snyan bcopy(&si, &ifr->ifr_addr, sizeof(ifr->ifr_addr)); 741111314Snyan break; 742111314Snyan case GRESKEY: 743111314Snyan error = priv_check(curthread, PRIV_NET_GRE); 744111314Snyan if (error) 745111314Snyan break; 746111314Snyan error = copyin(ifr->ifr_data, &key, sizeof(key)); 747111314Snyan if (error) 748111314Snyan break; 749111314Snyan /* adjust MTU for option header */ 750111314Snyan if (key == 0 && sc->key != 0) /* clear */ 751111314Snyan adj += sizeof(key); 752111314Snyan else if (key != 0 && sc->key == 0) /* set */ 753111314Snyan adj -= sizeof(key); 754111314Snyan 755111314Snyan if (ifp->if_mtu + adj < 576) { 756111314Snyan error = EINVAL; 757111314Snyan break; 758111314Snyan } 759111314Snyan ifp->if_mtu += adj; 760111314Snyan sc->key = key; 761111314Snyan break; 762111314Snyan case GREGKEY: 763111314Snyan error = copyout(&sc->key, ifr->ifr_data, sizeof(sc->key)); 764111314Snyan break; 765111314Snyan 766111314Snyan default: 767111314Snyan error = EINVAL; 768111314Snyan break; 769111314Snyan } 770111314Snyan 771111314Snyan splx(s); 772111314Snyan return (error); 773111314Snyan} 774111314Snyan 775111314Snyan/* 776111314Snyan * computes a route to our destination that is not the one 777111314Snyan * which would be taken by ip_output(), as this one will loop back to 778111314Snyan * us. If the interface is p2p as a--->b, then a routing entry exists 779111314Snyan * If we now send a packet to b (e.g. ping b), this will come down here 780111314Snyan * gets src=a, dst=b tacked on and would from ip_output() sent back to 781111314Snyan * if_gre. 782111314Snyan * Goal here is to compute a route to b that is less specific than 783111314Snyan * a-->b. We know that this one exists as in normal operation we have 784111314Snyan * at least a default route which matches. 785111314Snyan */ 786111314Snyanstatic int 787111314Snyangre_compute_route(struct gre_softc *sc) 788111314Snyan{ 789111314Snyan struct route *ro; 790111314Snyan 791111314Snyan ro = &sc->route; 792111314Snyan 793111314Snyan memset(ro, 0, sizeof(struct route)); 794111314Snyan ((struct sockaddr_in *)&ro->ro_dst)->sin_addr = sc->g_dst; 795111314Snyan ro->ro_dst.sa_family = AF_INET; 796111314Snyan ro->ro_dst.sa_len = sizeof(ro->ro_dst); 797111314Snyan 798111314Snyan /* 799111314Snyan * toggle last bit, so our interface is not found, but a less 800111314Snyan * specific route. I'd rather like to specify a shorter mask, 801111314Snyan * but this is not possible. Should work though. XXX 802111314Snyan * XXX MRT Use a different FIB for the tunnel to solve this problem. 803111314Snyan */ 804111314Snyan if ((GRE2IFP(sc)->if_flags & IFF_LINK1) == 0) { 805111314Snyan ((struct sockaddr_in *)&ro->ro_dst)->sin_addr.s_addr ^= 806111314Snyan htonl(0x01); 807111314Snyan } 808111314Snyan 809111314Snyan#ifdef DIAGNOSTIC 810111314Snyan printf("%s: searching for a route to %s", if_name(GRE2IFP(sc)), 811111314Snyan inet_ntoa(((struct sockaddr_in *)&ro->ro_dst)->sin_addr)); 812111314Snyan#endif 813111314Snyan 814111314Snyan rtalloc_fib(ro, sc->gre_fibnum); 815111314Snyan 816111314Snyan /* 817111314Snyan * check if this returned a route at all and this route is no 818111314Snyan * recursion to ourself 819111314Snyan */ 820111314Snyan if (ro->ro_rt == NULL || ro->ro_rt->rt_ifp->if_softc == sc) { 821111314Snyan#ifdef DIAGNOSTIC 822111314Snyan if (ro->ro_rt == NULL) 823111314Snyan printf(" - no route found!\n"); 824111314Snyan else 825111314Snyan printf(" - route loops back to ourself!\n"); 826111314Snyan#endif 827111314Snyan return EADDRNOTAVAIL; 828111314Snyan } 829111314Snyan 830111314Snyan /* 831111314Snyan * now change it back - else ip_output will just drop 832111314Snyan * the route and search one to this interface ... 833111314Snyan */ 834111314Snyan if ((GRE2IFP(sc)->if_flags & IFF_LINK1) == 0) 835111314Snyan ((struct sockaddr_in *)&ro->ro_dst)->sin_addr = sc->g_dst; 836111314Snyan 837111314Snyan#ifdef DIAGNOSTIC 838111314Snyan printf(", choosing %s with gateway %s", if_name(ro->ro_rt->rt_ifp), 839111314Snyan inet_ntoa(((struct sockaddr_in *)(ro->ro_rt->rt_gateway))->sin_addr)); 840111314Snyan printf("\n"); 841111314Snyan#endif 842111314Snyan 843111314Snyan return 0; 844111314Snyan} 845111314Snyan 846111314Snyan/* 847111314Snyan * do a checksum of a buffer - much like in_cksum, which operates on 848111314Snyan * mbufs. 849111314Snyan */ 850111314Snyanu_int16_t 851111314Snyangre_in_cksum(u_int16_t *p, u_int len) 852111314Snyan{ 853111314Snyan u_int32_t sum = 0; 854111314Snyan int nwords = len >> 1; 855111314Snyan 856111314Snyan while (nwords-- != 0) 857111314Snyan sum += *p++; 858111314Snyan 859111314Snyan if (len & 1) { 860111314Snyan union { 861111314Snyan u_short w; 862111314Snyan u_char c[2]; 863111314Snyan } u; 864111314Snyan u.c[0] = *(u_char *)p; 865111314Snyan u.c[1] = 0; 866111314Snyan sum += u.w; 867111314Snyan } 868111314Snyan 869111314Snyan /* end-around-carry */ 870111314Snyan sum = (sum >> 16) + (sum & 0xffff); 871111314Snyan sum += (sum >> 16); 872111314Snyan return (~sum); 873111314Snyan} 874111314Snyan 875111314Snyanstatic int 876111314Snyangremodevent(module_t mod, int type, void *data) 877111314Snyan{ 878111314Snyan 879111314Snyan switch (type) { 880111314Snyan case MOD_LOAD: 881111314Snyan greattach(); 882111314Snyan break; 883111314Snyan case MOD_UNLOAD: 884111314Snyan if_clone_detach(&gre_cloner); 885111314Snyan mtx_destroy(&gre_mtx); 886111314Snyan break; 887111314Snyan default: 888111314Snyan return EOPNOTSUPP; 889111314Snyan } 890111314Snyan return 0; 891111314Snyan} 892111314Snyan 893111314Snyanstatic moduledata_t gre_mod = { 894111314Snyan "if_gre", 895111314Snyan gremodevent, 896111314Snyan 0 897111314Snyan}; 898111314Snyan 899111314SnyanDECLARE_MODULE(if_gre, gre_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 900111314SnyanMODULE_VERSION(if_gre, 1); 901111314Snyan