1 1.159 skrll /* $NetBSD: if_gif.c,v 1.159 2024/09/15 09:46:45 skrll Exp $ */ 2 1.34 itojun /* $KAME: if_gif.c,v 1.76 2001/08/20 02:01:02 kjc Exp $ */ 3 1.3 itojun 4 1.2 itojun /* 5 1.2 itojun * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 6 1.2 itojun * All rights reserved. 7 1.9 itojun * 8 1.2 itojun * Redistribution and use in source and binary forms, with or without 9 1.2 itojun * modification, are permitted provided that the following conditions 10 1.2 itojun * are met: 11 1.2 itojun * 1. Redistributions of source code must retain the above copyright 12 1.2 itojun * notice, this list of conditions and the following disclaimer. 13 1.2 itojun * 2. Redistributions in binary form must reproduce the above copyright 14 1.2 itojun * notice, this list of conditions and the following disclaimer in the 15 1.2 itojun * documentation and/or other materials provided with the distribution. 16 1.2 itojun * 3. Neither the name of the project nor the names of its contributors 17 1.2 itojun * may be used to endorse or promote products derived from this software 18 1.2 itojun * without specific prior written permission. 19 1.9 itojun * 20 1.2 itojun * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21 1.2 itojun * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 1.2 itojun * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 1.2 itojun * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24 1.2 itojun * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 1.2 itojun * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 1.2 itojun * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 1.2 itojun * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 1.2 itojun * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 1.2 itojun * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 1.2 itojun * SUCH DAMAGE. 31 1.2 itojun */ 32 1.36 lukem 33 1.36 lukem #include <sys/cdefs.h> 34 1.159 skrll __KERNEL_RCSID(0, "$NetBSD: if_gif.c,v 1.159 2024/09/15 09:46:45 skrll Exp $"); 35 1.2 itojun 36 1.88 pooka #ifdef _KERNEL_OPT 37 1.2 itojun #include "opt_inet.h" 38 1.118 knakahar #include "opt_net_mpsafe.h" 39 1.88 pooka #endif 40 1.2 itojun 41 1.2 itojun #include <sys/param.h> 42 1.2 itojun #include <sys/systm.h> 43 1.152 riastrad #include <sys/atomic.h> 44 1.2 itojun #include <sys/kernel.h> 45 1.2 itojun #include <sys/mbuf.h> 46 1.2 itojun #include <sys/socket.h> 47 1.2 itojun #include <sys/sockio.h> 48 1.2 itojun #include <sys/errno.h> 49 1.2 itojun #include <sys/ioctl.h> 50 1.2 itojun #include <sys/time.h> 51 1.86 martin #include <sys/socketvar.h> 52 1.2 itojun #include <sys/syslog.h> 53 1.17 martin #include <sys/proc.h> 54 1.72 ad #include <sys/cpu.h> 55 1.72 ad #include <sys/intr.h> 56 1.98 knakahar #include <sys/kmem.h> 57 1.104 knakahar #include <sys/sysctl.h> 58 1.114 knakahar #include <sys/xcall.h> 59 1.120 christos #include <sys/device.h> 60 1.120 christos #include <sys/module.h> 61 1.133 knakahar #include <sys/mutex.h> 62 1.133 knakahar #include <sys/pserialize.h> 63 1.133 knakahar #include <sys/psref.h> 64 1.2 itojun 65 1.2 itojun #include <net/if.h> 66 1.2 itojun #include <net/if_types.h> 67 1.2 itojun #include <net/route.h> 68 1.2 itojun #include <net/bpf.h> 69 1.2 itojun 70 1.2 itojun #include <netinet/in.h> 71 1.2 itojun #include <netinet/in_systm.h> 72 1.15 itojun #include <netinet/ip.h> 73 1.15 itojun #ifdef INET 74 1.2 itojun #include <netinet/in_var.h> 75 1.57 christos #endif /* INET */ 76 1.2 itojun #include <netinet/in_gif.h> 77 1.2 itojun 78 1.2 itojun #ifdef INET6 79 1.2 itojun #ifndef INET 80 1.2 itojun #include <netinet/in.h> 81 1.2 itojun #endif 82 1.2 itojun #include <netinet6/in6_var.h> 83 1.2 itojun #include <netinet/ip6.h> 84 1.2 itojun #include <netinet6/ip6_var.h> 85 1.2 itojun #include <netinet6/in6_gif.h> 86 1.2 itojun #endif /* INET6 */ 87 1.2 itojun 88 1.9 itojun #include <netinet/ip_encap.h> 89 1.2 itojun #include <net/if_gif.h> 90 1.2 itojun 91 1.87 christos #include "ioconf.h" 92 1.4 itojun 93 1.118 knakahar #ifdef NET_MPSAFE 94 1.118 knakahar #define GIF_MPSAFE 1 95 1.118 knakahar #endif 96 1.118 knakahar 97 1.2 itojun /* 98 1.2 itojun * gif global variable definitions 99 1.2 itojun */ 100 1.130 knakahar static struct { 101 1.148 msaitoh LIST_HEAD(gif_sclist, gif_softc) list; 102 1.130 knakahar kmutex_t lock; 103 1.130 knakahar } gif_softcs __cacheline_aligned; 104 1.12 thorpej 105 1.133 knakahar struct psref_class *gv_psref_class __read_mostly; 106 1.133 knakahar 107 1.156 knakahar static pktq_rps_hash_func_t gif_pktq_rps_hash_p; 108 1.156 knakahar 109 1.131 msaitoh static int gifattach0(struct gif_softc *); 110 1.109 knakahar static int gif_output(struct ifnet *, struct mbuf *, 111 1.109 knakahar const struct sockaddr *, const struct rtentry *); 112 1.111 knakahar static void gif_start(struct ifnet *); 113 1.119 knakahar static int gif_transmit(struct ifnet *, struct mbuf *); 114 1.133 knakahar static int gif_transmit_direct(struct gif_variant *, struct mbuf *); 115 1.109 knakahar static int gif_ioctl(struct ifnet *, u_long, void *); 116 1.109 knakahar static int gif_set_tunnel(struct ifnet *, struct sockaddr *, 117 1.109 knakahar struct sockaddr *); 118 1.109 knakahar static void gif_delete_tunnel(struct ifnet *); 119 1.109 knakahar 120 1.56 thorpej static int gif_clone_create(struct if_clone *, int); 121 1.56 thorpej static int gif_clone_destroy(struct ifnet *); 122 1.95 knakahar static int gif_check_nesting(struct ifnet *, struct mbuf *); 123 1.12 thorpej 124 1.133 knakahar static int gif_encap_attach(struct gif_variant *); 125 1.133 knakahar static int gif_encap_detach(struct gif_variant *); 126 1.133 knakahar 127 1.133 knakahar static void gif_update_variant(struct gif_softc *, struct gif_variant *); 128 1.114 knakahar 129 1.56 thorpej static struct if_clone gif_cloner = 130 1.12 thorpej IF_CLONE_INITIALIZER("gif", gif_clone_create, gif_clone_destroy); 131 1.12 thorpej 132 1.9 itojun #ifndef MAX_GIF_NEST 133 1.9 itojun /* 134 1.9 itojun * This macro controls the upper limitation on nesting of gif tunnels. 135 1.9 itojun * Since, setting a large value to this macro with a careless configuration 136 1.9 itojun * may introduce system crash, we don't allow any nestings by default. 137 1.9 itojun * If you need to configure nested gif tunnels, you can define this macro 138 1.31 itojun * in your kernel configuration file. However, if you do so, please be 139 1.9 itojun * careful to configure the tunnels so that it won't make a loop. 140 1.9 itojun */ 141 1.9 itojun #define MAX_GIF_NEST 1 142 1.9 itojun #endif 143 1.9 itojun static int max_gif_nesting = MAX_GIF_NEST; 144 1.2 itojun 145 1.120 christos static struct sysctllog *gif_sysctl; 146 1.120 christos 147 1.150 knakahar #ifdef INET6 148 1.150 knakahar static int 149 1.150 knakahar sysctl_gif_pmtu_global(SYSCTLFN_ARGS) 150 1.150 knakahar { 151 1.150 knakahar int error, pmtu; 152 1.150 knakahar struct sysctlnode node = *rnode; 153 1.150 knakahar 154 1.150 knakahar pmtu = ip6_gif_pmtu; 155 1.150 knakahar node.sysctl_data = &pmtu; 156 1.150 knakahar error = sysctl_lookup(SYSCTLFN_CALL(&node)); 157 1.150 knakahar if (error || newp == NULL) 158 1.150 knakahar return error; 159 1.150 knakahar 160 1.150 knakahar switch (pmtu) { 161 1.150 knakahar case GIF_PMTU_MINMTU: 162 1.150 knakahar case GIF_PMTU_OUTERMTU: 163 1.150 knakahar ip6_gif_pmtu = pmtu; 164 1.150 knakahar break; 165 1.150 knakahar default: 166 1.150 knakahar return EINVAL; 167 1.150 knakahar } 168 1.150 knakahar 169 1.150 knakahar return 0; 170 1.150 knakahar } 171 1.150 knakahar 172 1.150 knakahar static int 173 1.150 knakahar sysctl_gif_pmtu_perif(SYSCTLFN_ARGS) 174 1.150 knakahar { 175 1.150 knakahar int error, pmtu; 176 1.150 knakahar struct sysctlnode node = *rnode; 177 1.150 knakahar struct gif_softc *sc = (struct gif_softc *)node.sysctl_data; 178 1.150 knakahar 179 1.150 knakahar pmtu = sc->gif_pmtu; 180 1.150 knakahar node.sysctl_data = &pmtu; 181 1.150 knakahar error = sysctl_lookup(SYSCTLFN_CALL(&node)); 182 1.150 knakahar if (error || newp == NULL) 183 1.150 knakahar return error; 184 1.150 knakahar 185 1.150 knakahar switch (pmtu) { 186 1.150 knakahar case GIF_PMTU_SYSDEFAULT: 187 1.150 knakahar case GIF_PMTU_MINMTU: 188 1.150 knakahar case GIF_PMTU_OUTERMTU: 189 1.150 knakahar sc->gif_pmtu = pmtu; 190 1.150 knakahar break; 191 1.150 knakahar default: 192 1.150 knakahar return EINVAL; 193 1.150 knakahar } 194 1.150 knakahar 195 1.150 knakahar return 0; 196 1.150 knakahar } 197 1.150 knakahar #endif 198 1.150 knakahar 199 1.104 knakahar static void 200 1.120 christos gif_sysctl_setup(void) 201 1.104 knakahar { 202 1.156 knakahar const struct sysctlnode *node = NULL; 203 1.156 knakahar 204 1.120 christos gif_sysctl = NULL; 205 1.104 knakahar 206 1.104 knakahar #ifdef INET 207 1.121 knakahar /* 208 1.121 knakahar * Previously create "net.inet.ip" entry to avoid sysctl_createv error. 209 1.121 knakahar */ 210 1.121 knakahar sysctl_createv(NULL, 0, NULL, NULL, 211 1.121 knakahar CTLFLAG_PERMANENT, 212 1.121 knakahar CTLTYPE_NODE, "inet", 213 1.121 knakahar SYSCTL_DESCR("PF_INET related settings"), 214 1.121 knakahar NULL, 0, NULL, 0, 215 1.121 knakahar CTL_NET, PF_INET, CTL_EOL); 216 1.121 knakahar sysctl_createv(NULL, 0, NULL, NULL, 217 1.121 knakahar CTLFLAG_PERMANENT, 218 1.121 knakahar CTLTYPE_NODE, "ip", 219 1.121 knakahar SYSCTL_DESCR("IPv4 related settings"), 220 1.121 knakahar NULL, 0, NULL, 0, 221 1.121 knakahar CTL_NET, PF_INET, IPPROTO_IP, CTL_EOL); 222 1.121 knakahar 223 1.120 christos sysctl_createv(&gif_sysctl, 0, NULL, NULL, 224 1.147 msaitoh CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 225 1.104 knakahar CTLTYPE_INT, "gifttl", 226 1.104 knakahar SYSCTL_DESCR("Default TTL for a gif tunnel datagram"), 227 1.104 knakahar NULL, 0, &ip_gif_ttl, 0, 228 1.104 knakahar CTL_NET, PF_INET, IPPROTO_IP, 229 1.104 knakahar IPCTL_GIF_TTL, CTL_EOL); 230 1.104 knakahar #endif 231 1.104 knakahar #ifdef INET6 232 1.121 knakahar /* 233 1.121 knakahar * Previously create "net.inet6.ip6" entry to avoid sysctl_createv error. 234 1.121 knakahar */ 235 1.121 knakahar sysctl_createv(NULL, 0, NULL, NULL, 236 1.121 knakahar CTLFLAG_PERMANENT, 237 1.121 knakahar CTLTYPE_NODE, "inet6", 238 1.121 knakahar SYSCTL_DESCR("PF_INET6 related settings"), 239 1.121 knakahar NULL, 0, NULL, 0, 240 1.121 knakahar CTL_NET, PF_INET6, CTL_EOL); 241 1.121 knakahar sysctl_createv(NULL, 0, NULL, NULL, 242 1.121 knakahar CTLFLAG_PERMANENT, 243 1.121 knakahar CTLTYPE_NODE, "ip6", 244 1.121 knakahar SYSCTL_DESCR("IPv6 related settings"), 245 1.121 knakahar NULL, 0, NULL, 0, 246 1.121 knakahar CTL_NET, PF_INET6, IPPROTO_IPV6, CTL_EOL); 247 1.121 knakahar 248 1.120 christos sysctl_createv(&gif_sysctl, 0, NULL, NULL, 249 1.147 msaitoh CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 250 1.104 knakahar CTLTYPE_INT, "gifhlim", 251 1.104 knakahar SYSCTL_DESCR("Default hop limit for a gif tunnel datagram"), 252 1.104 knakahar NULL, 0, &ip6_gif_hlim, 0, 253 1.104 knakahar CTL_NET, PF_INET6, IPPROTO_IPV6, 254 1.104 knakahar IPV6CTL_GIF_HLIM, CTL_EOL); 255 1.150 knakahar 256 1.150 knakahar sysctl_createv(&gif_sysctl, 0, NULL, NULL, 257 1.150 knakahar CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 258 1.150 knakahar CTLTYPE_INT, "gifpmtu", 259 1.150 knakahar SYSCTL_DESCR("Default Path MTU setting for gif tunnels"), 260 1.150 knakahar sysctl_gif_pmtu_global, 0, NULL, 0, 261 1.150 knakahar CTL_NET, PF_INET6, IPPROTO_IPV6, 262 1.150 knakahar IPV6CTL_GIF_PMTU, CTL_EOL); 263 1.150 knakahar #endif 264 1.156 knakahar 265 1.156 knakahar sysctl_createv(&gif_sysctl, 0, NULL, &node, 266 1.156 knakahar CTLFLAG_PERMANENT, 267 1.156 knakahar CTLTYPE_NODE, "gif", 268 1.156 knakahar SYSCTL_DESCR("gif global control"), 269 1.156 knakahar NULL, 0, NULL, 0, 270 1.156 knakahar CTL_NET, CTL_CREATE, CTL_EOL); 271 1.156 knakahar 272 1.156 knakahar sysctl_createv(&gif_sysctl, 0, &node, NULL, 273 1.156 knakahar CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 274 1.156 knakahar CTLTYPE_STRING, "rps_hash", 275 1.156 knakahar SYSCTL_DESCR("Interface rps hash function control"), 276 1.156 knakahar sysctl_pktq_rps_hash_handler, 0, (void *)&gif_pktq_rps_hash_p, 277 1.156 knakahar PKTQ_RPS_HASH_NAME_LEN, 278 1.156 knakahar CTL_CREATE, CTL_EOL); 279 1.150 knakahar } 280 1.150 knakahar 281 1.150 knakahar static void 282 1.150 knakahar gif_perif_sysctl_setup(struct sysctllog **clog, struct gif_softc *sc) 283 1.150 knakahar { 284 1.150 knakahar #ifdef INET6 285 1.150 knakahar const struct sysctlnode *cnode, *rnode; 286 1.150 knakahar struct ifnet *ifp = &sc->gif_if; 287 1.150 knakahar const char *ifname = ifp->if_xname; 288 1.150 knakahar int rv; 289 1.150 knakahar 290 1.150 knakahar /* 291 1.150 knakahar * Already created in sysctl_sndq_setup(). 292 1.150 knakahar */ 293 1.150 knakahar sysctl_createv(clog, 0, NULL, &rnode, 294 1.150 knakahar CTLFLAG_PERMANENT, 295 1.150 knakahar CTLTYPE_NODE, "interfaces", 296 1.150 knakahar SYSCTL_DESCR("Per-interface controls"), 297 1.150 knakahar NULL, 0, NULL, 0, 298 1.150 knakahar CTL_NET, CTL_CREATE, CTL_EOL); 299 1.150 knakahar sysctl_createv(clog, 0, &rnode, &rnode, 300 1.150 knakahar CTLFLAG_PERMANENT, 301 1.150 knakahar CTLTYPE_NODE, ifname, 302 1.150 knakahar SYSCTL_DESCR("Interface controls"), 303 1.150 knakahar NULL, 0, NULL, 0, 304 1.150 knakahar CTL_CREATE, CTL_EOL); 305 1.150 knakahar 306 1.150 knakahar rv = sysctl_createv(clog, 0, &rnode, &cnode, 307 1.150 knakahar CTLFLAG_PERMANENT, 308 1.150 knakahar CTLTYPE_INT, "pmtu", 309 1.150 knakahar SYSCTL_DESCR("Path MTU setting for this gif tunnel"), 310 1.150 knakahar sysctl_gif_pmtu_perif, 0, (void *)sc, 0, 311 1.150 knakahar CTL_CREATE, CTL_EOL); 312 1.150 knakahar if (rv != 0) 313 1.150 knakahar log(LOG_WARNING, "%s: could not attach sysctl node pmtu\n", ifname); 314 1.150 knakahar 315 1.150 knakahar sc->gif_pmtu = GIF_PMTU_SYSDEFAULT; 316 1.104 knakahar #endif 317 1.104 knakahar } 318 1.104 knakahar 319 1.12 thorpej /* ARGSUSED */ 320 1.2 itojun void 321 1.63 christos gifattach(int count) 322 1.12 thorpej { 323 1.120 christos /* 324 1.120 christos * Nothing to do here, initialization is handled by the 325 1.120 christos * module initialization code in gifinit() below). 326 1.120 christos */ 327 1.120 christos } 328 1.120 christos 329 1.120 christos static void 330 1.120 christos gifinit(void) 331 1.120 christos { 332 1.12 thorpej 333 1.130 knakahar mutex_init(&gif_softcs.lock, MUTEX_DEFAULT, IPL_NONE); 334 1.130 knakahar LIST_INIT(&gif_softcs.list); 335 1.12 thorpej if_clone_attach(&gif_cloner); 336 1.104 knakahar 337 1.133 knakahar gv_psref_class = psref_class_create("gifvar", IPL_SOFTNET); 338 1.133 knakahar 339 1.156 knakahar gif_pktq_rps_hash_p = pktq_rps_hash_default; 340 1.120 christos gif_sysctl_setup(); 341 1.120 christos } 342 1.120 christos 343 1.120 christos static int 344 1.120 christos gifdetach(void) 345 1.120 christos { 346 1.120 christos 347 1.130 knakahar mutex_enter(&gif_softcs.lock); 348 1.130 knakahar if (!LIST_EMPTY(&gif_softcs.list)) { 349 1.130 knakahar mutex_exit(&gif_softcs.lock); 350 1.153 christos return EBUSY; 351 1.130 knakahar } 352 1.120 christos 353 1.153 christos psref_class_destroy(gv_psref_class); 354 1.133 knakahar 355 1.153 christos if_clone_detach(&gif_cloner); 356 1.153 christos sysctl_teardown(&gif_sysctl); 357 1.153 christos mutex_exit(&gif_softcs.lock); 358 1.153 christos mutex_destroy(&gif_softcs.lock); 359 1.153 christos return 0; 360 1.12 thorpej } 361 1.12 thorpej 362 1.56 thorpej static int 363 1.56 thorpej gif_clone_create(struct if_clone *ifc, int unit) 364 1.2 itojun { 365 1.12 thorpej struct gif_softc *sc; 366 1.133 knakahar struct gif_variant *var; 367 1.150 knakahar struct ifnet *ifp; 368 1.131 msaitoh int rv; 369 1.12 thorpej 370 1.98 knakahar sc = kmem_zalloc(sizeof(struct gif_softc), KM_SLEEP); 371 1.2 itojun 372 1.75 christos if_initname(&sc->gif_if, ifc->ifc_name, unit); 373 1.9 itojun 374 1.131 msaitoh rv = gifattach0(sc); 375 1.131 msaitoh if (rv != 0) { 376 1.131 msaitoh kmem_free(sc, sizeof(struct gif_softc)); 377 1.131 msaitoh return rv; 378 1.131 msaitoh } 379 1.31 itojun 380 1.150 knakahar ifp = &sc->gif_if; 381 1.150 knakahar gif_perif_sysctl_setup(&ifp->if_sysctl_log, sc); 382 1.150 knakahar 383 1.133 knakahar var = kmem_zalloc(sizeof(*var), KM_SLEEP); 384 1.133 knakahar var->gv_softc = sc; 385 1.133 knakahar psref_target_init(&var->gv_psref, gv_psref_class); 386 1.133 knakahar 387 1.133 knakahar sc->gif_var = var; 388 1.133 knakahar mutex_init(&sc->gif_lock, MUTEX_DEFAULT, IPL_NONE); 389 1.144 knakahar sc->gif_psz = pserialize_create(); 390 1.144 knakahar 391 1.149 knakahar sc->gif_ro_percpu = if_tunnel_alloc_ro_percpu(); 392 1.130 knakahar mutex_enter(&gif_softcs.lock); 393 1.130 knakahar LIST_INSERT_HEAD(&gif_softcs.list, sc, gif_list); 394 1.130 knakahar mutex_exit(&gif_softcs.lock); 395 1.131 msaitoh return 0; 396 1.31 itojun } 397 1.31 itojun 398 1.131 msaitoh static int 399 1.56 thorpej gifattach0(struct gif_softc *sc) 400 1.31 itojun { 401 1.31 itojun 402 1.31 itojun sc->gif_if.if_addrlen = 0; 403 1.12 thorpej sc->gif_if.if_mtu = GIF_MTU; 404 1.12 thorpej sc->gif_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST; 405 1.122 knakahar #ifdef GIF_MPSAFE 406 1.132 ozaki sc->gif_if.if_extflags |= IFEF_MPSAFE; 407 1.122 knakahar #endif 408 1.12 thorpej sc->gif_if.if_ioctl = gif_ioctl; 409 1.12 thorpej sc->gif_if.if_output = gif_output; 410 1.119 knakahar sc->gif_if.if_start = gif_start; 411 1.119 knakahar sc->gif_if.if_transmit = gif_transmit; 412 1.12 thorpej sc->gif_if.if_type = IFT_GIF; 413 1.19 thorpej sc->gif_if.if_dlt = DLT_NULL; 414 1.76 dyoung sc->gif_if.if_softc = sc; 415 1.34 itojun IFQ_SET_READY(&sc->gif_if.if_snd); 416 1.155 riastrad if_initialize(&sc->gif_if); 417 1.131 msaitoh 418 1.154 roy sc->gif_if.if_link_state = LINK_STATE_DOWN; 419 1.20 thorpej if_alloc_sadl(&sc->gif_if); 420 1.78 joerg bpf_attach(&sc->gif_if, DLT_NULL, sizeof(u_int)); 421 1.142 ozaki if_register(&sc->gif_if); 422 1.131 msaitoh return 0; 423 1.12 thorpej } 424 1.12 thorpej 425 1.56 thorpej static int 426 1.56 thorpej gif_clone_destroy(struct ifnet *ifp) 427 1.12 thorpej { 428 1.12 thorpej struct gif_softc *sc = (void *) ifp; 429 1.133 knakahar struct gif_variant *var; 430 1.12 thorpej 431 1.12 thorpej LIST_REMOVE(sc, gif_list); 432 1.12 thorpej 433 1.94 knakahar gif_delete_tunnel(&sc->gif_if); 434 1.78 joerg bpf_detach(ifp); 435 1.69 dyoung if_detach(ifp); 436 1.129 knakahar 437 1.149 knakahar if_tunnel_free_ro_percpu(sc->gif_ro_percpu); 438 1.129 knakahar 439 1.144 knakahar pserialize_destroy(sc->gif_psz); 440 1.133 knakahar mutex_destroy(&sc->gif_lock); 441 1.133 knakahar 442 1.133 knakahar var = sc->gif_var; 443 1.133 knakahar kmem_free(var, sizeof(*var)); 444 1.98 knakahar kmem_free(sc, sizeof(struct gif_softc)); 445 1.47 peter 446 1.131 msaitoh return 0; 447 1.9 itojun } 448 1.9 itojun 449 1.42 itojun #ifdef GIF_ENCAPCHECK 450 1.31 itojun int 451 1.56 thorpej gif_encapcheck(struct mbuf *m, int off, int proto, void *arg) 452 1.9 itojun { 453 1.9 itojun struct ip ip; 454 1.9 itojun struct gif_softc *sc; 455 1.133 knakahar struct gif_variant *var; 456 1.133 knakahar struct psref psref; 457 1.133 knakahar int ret = 0; 458 1.9 itojun 459 1.76 dyoung sc = arg; 460 1.9 itojun if (sc == NULL) 461 1.9 itojun return 0; 462 1.9 itojun 463 1.134 knakahar if ((sc->gif_if.if_flags & IFF_UP) == 0) 464 1.9 itojun return 0; 465 1.9 itojun 466 1.133 knakahar var = gif_getref_variant(sc, &psref); 467 1.137 knakahar /* no physical address */ 468 1.133 knakahar if (var->gv_psrc == NULL || var->gv_pdst == NULL) 469 1.133 knakahar goto out; 470 1.133 knakahar 471 1.9 itojun switch (proto) { 472 1.9 itojun #ifdef INET 473 1.9 itojun case IPPROTO_IPV4: 474 1.9 itojun break; 475 1.9 itojun #endif 476 1.9 itojun #ifdef INET6 477 1.9 itojun case IPPROTO_IPV6: 478 1.9 itojun break; 479 1.9 itojun #endif 480 1.9 itojun default: 481 1.133 knakahar goto out; 482 1.9 itojun } 483 1.40 christos 484 1.40 christos /* Bail on short packets */ 485 1.40 christos KASSERT(m->m_flags & M_PKTHDR); 486 1.40 christos if (m->m_pkthdr.len < sizeof(ip)) 487 1.133 knakahar goto out; 488 1.9 itojun 489 1.76 dyoung m_copydata(m, 0, sizeof(ip), &ip); 490 1.9 itojun 491 1.9 itojun switch (ip.ip_v) { 492 1.9 itojun #ifdef INET 493 1.9 itojun case 4: 494 1.133 knakahar if (var->gv_psrc->sa_family != AF_INET || 495 1.133 knakahar var->gv_pdst->sa_family != AF_INET) 496 1.133 knakahar goto out; 497 1.133 knakahar ret = gif_encapcheck4(m, off, proto, var); 498 1.133 knakahar break; 499 1.9 itojun #endif 500 1.9 itojun #ifdef INET6 501 1.9 itojun case 6: 502 1.41 itojun if (m->m_pkthdr.len < sizeof(struct ip6_hdr)) 503 1.133 knakahar goto out; 504 1.133 knakahar if (var->gv_psrc->sa_family != AF_INET6 || 505 1.133 knakahar var->gv_pdst->sa_family != AF_INET6) 506 1.133 knakahar goto out; 507 1.133 knakahar ret = gif_encapcheck6(m, off, proto, var); 508 1.133 knakahar break; 509 1.9 itojun #endif 510 1.9 itojun default: 511 1.133 knakahar goto out; 512 1.2 itojun } 513 1.133 knakahar 514 1.133 knakahar out: 515 1.133 knakahar gif_putref_variant(var, &psref); 516 1.133 knakahar return ret; 517 1.2 itojun } 518 1.42 itojun #endif 519 1.2 itojun 520 1.95 knakahar /* 521 1.95 knakahar * gif may cause infinite recursion calls when misconfigured. 522 1.95 knakahar * We'll prevent this by introducing upper limit. 523 1.95 knakahar */ 524 1.95 knakahar static int 525 1.95 knakahar gif_check_nesting(struct ifnet *ifp, struct mbuf *m) 526 1.95 knakahar { 527 1.95 knakahar 528 1.135 knakahar return if_tunnel_check_nesting(ifp, m, max_gif_nesting); 529 1.95 knakahar } 530 1.95 knakahar 531 1.109 knakahar static int 532 1.65 dyoung gif_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, 533 1.108 ozaki const struct rtentry *rt) 534 1.2 itojun { 535 1.76 dyoung struct gif_softc *sc = ifp->if_softc; 536 1.133 knakahar struct gif_variant *var = NULL; 537 1.133 knakahar struct psref psref; 538 1.2 itojun int error = 0; 539 1.33 itojun 540 1.107 knakahar IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family); 541 1.2 itojun 542 1.95 knakahar if ((error = gif_check_nesting(ifp, m)) != 0) { 543 1.139 maxv m_freem(m); 544 1.2 itojun goto end; 545 1.2 itojun } 546 1.2 itojun 547 1.134 knakahar if ((ifp->if_flags & IFF_UP) == 0) { 548 1.2 itojun m_freem(m); 549 1.2 itojun error = ENETDOWN; 550 1.2 itojun goto end; 551 1.2 itojun } 552 1.2 itojun 553 1.133 knakahar var = gif_getref_variant(sc, &psref); 554 1.133 knakahar if (var->gv_psrc == NULL || var->gv_pdst == NULL) { 555 1.133 knakahar m_freem(m); 556 1.133 knakahar error = ENETDOWN; 557 1.133 knakahar goto end; 558 1.133 knakahar } 559 1.9 itojun /* XXX should we check if our outer source is legal? */ 560 1.2 itojun 561 1.147 msaitoh m->m_flags &= ~(M_BCAST | M_MCAST); 562 1.133 knakahar 563 1.33 itojun /* use DLT_NULL encapsulation here to pass inner af type */ 564 1.33 itojun M_PREPEND(m, sizeof(int), M_DONTWAIT); 565 1.33 itojun if (!m) { 566 1.33 itojun error = ENOBUFS; 567 1.33 itojun goto end; 568 1.33 itojun } 569 1.33 itojun *mtod(m, int *) = dst->sa_family; 570 1.33 itojun 571 1.79 dyoung /* Clear checksum-offload flags. */ 572 1.79 dyoung m->m_pkthdr.csum_flags = 0; 573 1.79 dyoung m->m_pkthdr.csum_data = 0; 574 1.79 dyoung 575 1.145 knakahar error = if_transmit_lock(ifp, m); 576 1.145 knakahar 577 1.133 knakahar end: 578 1.133 knakahar if (var != NULL) 579 1.133 knakahar gif_putref_variant(var, &psref); 580 1.31 itojun if (error) 581 1.151 thorpej if_statinc(ifp, if_oerrors); 582 1.2 itojun return error; 583 1.2 itojun } 584 1.2 itojun 585 1.56 thorpej static void 586 1.111 knakahar gif_start(struct ifnet *ifp) 587 1.33 itojun { 588 1.33 itojun struct gif_softc *sc; 589 1.133 knakahar struct gif_variant *var; 590 1.33 itojun struct mbuf *m; 591 1.133 knakahar struct psref psref; 592 1.33 itojun int family; 593 1.33 itojun int len; 594 1.33 itojun int error; 595 1.33 itojun 596 1.111 knakahar sc = ifp->if_softc; 597 1.133 knakahar var = gif_getref_variant(sc, &psref); 598 1.133 knakahar 599 1.133 knakahar KASSERT(var->gv_output != NULL); 600 1.102 knakahar 601 1.33 itojun /* output processing */ 602 1.33 itojun while (1) { 603 1.34 itojun IFQ_DEQUEUE(&sc->gif_if.if_snd, m); 604 1.33 itojun if (m == NULL) 605 1.33 itojun break; 606 1.33 itojun 607 1.33 itojun /* grab and chop off inner af type */ 608 1.33 itojun if (sizeof(int) > m->m_len) { 609 1.33 itojun m = m_pullup(m, sizeof(int)); 610 1.33 itojun if (!m) { 611 1.151 thorpej if_statinc(ifp, if_oerrors); 612 1.33 itojun continue; 613 1.33 itojun } 614 1.33 itojun } 615 1.33 itojun family = *mtod(m, int *); 616 1.143 msaitoh bpf_mtap(ifp, m, BPF_D_OUT); 617 1.33 itojun m_adj(m, sizeof(int)); 618 1.33 itojun 619 1.33 itojun len = m->m_pkthdr.len; 620 1.33 itojun 621 1.133 knakahar error = var->gv_output(var, family, m); 622 1.33 itojun if (error) 623 1.151 thorpej if_statinc(ifp, if_oerrors); 624 1.151 thorpej else 625 1.151 thorpej if_statadd2(ifp, if_opackets, 1, if_obytes, len); 626 1.33 itojun } 627 1.133 knakahar 628 1.133 knakahar gif_putref_variant(var, &psref); 629 1.33 itojun } 630 1.33 itojun 631 1.119 knakahar static int 632 1.119 knakahar gif_transmit(struct ifnet *ifp, struct mbuf *m) 633 1.119 knakahar { 634 1.119 knakahar struct gif_softc *sc; 635 1.133 knakahar struct gif_variant *var; 636 1.133 knakahar struct psref psref; 637 1.119 knakahar int error; 638 1.119 knakahar 639 1.119 knakahar sc = ifp->if_softc; 640 1.119 knakahar 641 1.119 knakahar /* output processing */ 642 1.119 knakahar if (m == NULL) 643 1.119 knakahar return EINVAL; 644 1.119 knakahar 645 1.133 knakahar var = gif_getref_variant(sc, &psref); 646 1.133 knakahar error = gif_transmit_direct(var, m); 647 1.133 knakahar gif_putref_variant(var, &psref); 648 1.133 knakahar 649 1.133 knakahar return error; 650 1.133 knakahar } 651 1.133 knakahar 652 1.133 knakahar static int 653 1.133 knakahar gif_transmit_direct(struct gif_variant *var, struct mbuf *m) 654 1.133 knakahar { 655 1.133 knakahar struct ifnet *ifp = &var->gv_softc->gif_if; 656 1.133 knakahar int error; 657 1.133 knakahar int family; 658 1.133 knakahar int len; 659 1.133 knakahar 660 1.133 knakahar KASSERT(gif_heldref_variant(var)); 661 1.133 knakahar KASSERT(var->gv_output != NULL); 662 1.133 knakahar 663 1.119 knakahar /* grab and chop off inner af type */ 664 1.119 knakahar if (sizeof(int) > m->m_len) { 665 1.119 knakahar m = m_pullup(m, sizeof(int)); 666 1.119 knakahar if (!m) { 667 1.151 thorpej if_statinc(ifp, if_oerrors); 668 1.119 knakahar return ENOBUFS; 669 1.119 knakahar } 670 1.119 knakahar } 671 1.119 knakahar family = *mtod(m, int *); 672 1.143 msaitoh bpf_mtap(ifp, m, BPF_D_OUT); 673 1.119 knakahar m_adj(m, sizeof(int)); 674 1.119 knakahar 675 1.119 knakahar len = m->m_pkthdr.len; 676 1.119 knakahar 677 1.133 knakahar error = var->gv_output(var, family, m); 678 1.119 knakahar if (error) 679 1.151 thorpej if_statinc(ifp, if_oerrors); 680 1.151 thorpej else 681 1.151 thorpej if_statadd2(ifp, if_opackets, 1, if_obytes, len); 682 1.119 knakahar 683 1.119 knakahar return error; 684 1.119 knakahar } 685 1.119 knakahar 686 1.33 itojun void 687 1.56 thorpej gif_input(struct mbuf *m, int af, struct ifnet *ifp) 688 1.2 itojun { 689 1.83 rmind pktqueue_t *pktq; 690 1.83 rmind size_t pktlen; 691 1.2 itojun 692 1.33 itojun if (ifp == NULL) { 693 1.2 itojun /* just in case */ 694 1.2 itojun m_freem(m); 695 1.2 itojun return; 696 1.2 itojun } 697 1.2 itojun 698 1.110 ozaki m_set_rcvif(m, ifp); 699 1.83 rmind pktlen = m->m_pkthdr.len; 700 1.50 perry 701 1.143 msaitoh bpf_mtap_af(ifp, af, m, BPF_D_IN); 702 1.2 itojun 703 1.2 itojun /* 704 1.2 itojun * Put the packet to the network layer input queue according to the 705 1.83 rmind * specified address family. Note: we avoid direct call to the 706 1.83 rmind * input function of the network layer in order to avoid recursion. 707 1.83 rmind * This may be revisited in the future. 708 1.2 itojun */ 709 1.2 itojun switch (af) { 710 1.2 itojun #ifdef INET 711 1.2 itojun case AF_INET: 712 1.83 rmind pktq = ip_pktq; 713 1.2 itojun break; 714 1.2 itojun #endif 715 1.2 itojun #ifdef INET6 716 1.2 itojun case AF_INET6: 717 1.83 rmind pktq = ip6_pktq; 718 1.2 itojun break; 719 1.2 itojun #endif 720 1.2 itojun default: 721 1.2 itojun m_freem(m); 722 1.2 itojun return; 723 1.2 itojun } 724 1.2 itojun 725 1.156 knakahar const uint32_t h = pktq_rps_hash(&gif_pktq_rps_hash_p, m); 726 1.127 knakahar if (__predict_true(pktq_enqueue(pktq, m, h))) { 727 1.151 thorpej if_statadd2(ifp, if_ibytes, pktlen, if_ipackets, 1); 728 1.83 rmind } else { 729 1.2 itojun m_freem(m); 730 1.2 itojun } 731 1.2 itojun } 732 1.2 itojun 733 1.9 itojun /* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */ 734 1.109 knakahar static int 735 1.67 christos gif_ioctl(struct ifnet *ifp, u_long cmd, void *data) 736 1.2 itojun { 737 1.76 dyoung struct gif_softc *sc = ifp->if_softc; 738 1.2 itojun struct ifreq *ifr = (struct ifreq*)data; 739 1.84 roy struct ifaddr *ifa = (struct ifaddr*)data; 740 1.133 knakahar int error = 0, size, bound; 741 1.9 itojun struct sockaddr *dst, *src; 742 1.133 knakahar struct gif_variant *var; 743 1.133 knakahar struct psref psref; 744 1.31 itojun 745 1.2 itojun switch (cmd) { 746 1.76 dyoung case SIOCINITIFADDR: 747 1.32 itojun ifp->if_flags |= IFF_UP; 748 1.84 roy ifa->ifa_rtrequest = p2p_rtrequest; 749 1.2 itojun break; 750 1.50 perry 751 1.2 itojun case SIOCADDMULTI: 752 1.2 itojun case SIOCDELMULTI: 753 1.2 itojun switch (ifr->ifr_addr.sa_family) { 754 1.2 itojun #ifdef INET 755 1.2 itojun case AF_INET: /* IP supports Multicast */ 756 1.2 itojun break; 757 1.2 itojun #endif /* INET */ 758 1.2 itojun #ifdef INET6 759 1.2 itojun case AF_INET6: /* IP6 supports Multicast */ 760 1.2 itojun break; 761 1.2 itojun #endif /* INET6 */ 762 1.2 itojun default: /* Other protocols doesn't support Multicast */ 763 1.2 itojun error = EAFNOSUPPORT; 764 1.2 itojun break; 765 1.2 itojun } 766 1.2 itojun break; 767 1.2 itojun 768 1.2 itojun case SIOCSIFMTU: 769 1.73 dyoung if (ifr->ifr_mtu < GIF_MTU_MIN || ifr->ifr_mtu > GIF_MTU_MAX) 770 1.73 dyoung return EINVAL; 771 1.73 dyoung else if ((error = ifioctl_common(ifp, cmd, data)) == ENETRESET) 772 1.73 dyoung error = 0; 773 1.2 itojun break; 774 1.2 itojun 775 1.31 itojun #ifdef INET 776 1.2 itojun case SIOCSIFPHYADDR: 777 1.31 itojun #endif 778 1.2 itojun #ifdef INET6 779 1.2 itojun case SIOCSIFPHYADDR_IN6: 780 1.2 itojun #endif /* INET6 */ 781 1.25 itojun case SIOCSLIFPHYADDR: 782 1.11 itojun switch (cmd) { 783 1.15 itojun #ifdef INET 784 1.11 itojun case SIOCSIFPHYADDR: 785 1.11 itojun src = (struct sockaddr *) 786 1.11 itojun &(((struct in_aliasreq *)data)->ifra_addr); 787 1.11 itojun dst = (struct sockaddr *) 788 1.11 itojun &(((struct in_aliasreq *)data)->ifra_dstaddr); 789 1.11 itojun break; 790 1.15 itojun #endif 791 1.11 itojun #ifdef INET6 792 1.11 itojun case SIOCSIFPHYADDR_IN6: 793 1.11 itojun src = (struct sockaddr *) 794 1.11 itojun &(((struct in6_aliasreq *)data)->ifra_addr); 795 1.11 itojun dst = (struct sockaddr *) 796 1.11 itojun &(((struct in6_aliasreq *)data)->ifra_dstaddr); 797 1.25 itojun break; 798 1.25 itojun #endif 799 1.25 itojun case SIOCSLIFPHYADDR: 800 1.25 itojun src = (struct sockaddr *) 801 1.25 itojun &(((struct if_laddrreq *)data)->addr); 802 1.25 itojun dst = (struct sockaddr *) 803 1.25 itojun &(((struct if_laddrreq *)data)->dstaddr); 804 1.31 itojun break; 805 1.31 itojun default: 806 1.31 itojun return EINVAL; 807 1.25 itojun } 808 1.25 itojun 809 1.25 itojun /* sa_family must be equal */ 810 1.25 itojun if (src->sa_family != dst->sa_family) 811 1.25 itojun return EINVAL; 812 1.25 itojun 813 1.25 itojun /* validate sa_len */ 814 1.25 itojun switch (src->sa_family) { 815 1.25 itojun #ifdef INET 816 1.25 itojun case AF_INET: 817 1.25 itojun if (src->sa_len != sizeof(struct sockaddr_in)) 818 1.16 itojun return EINVAL; 819 1.11 itojun break; 820 1.11 itojun #endif 821 1.25 itojun #ifdef INET6 822 1.25 itojun case AF_INET6: 823 1.25 itojun if (src->sa_len != sizeof(struct sockaddr_in6)) 824 1.25 itojun return EINVAL; 825 1.25 itojun break; 826 1.25 itojun #endif 827 1.25 itojun default: 828 1.25 itojun return EAFNOSUPPORT; 829 1.25 itojun } 830 1.25 itojun switch (dst->sa_family) { 831 1.25 itojun #ifdef INET 832 1.25 itojun case AF_INET: 833 1.25 itojun if (dst->sa_len != sizeof(struct sockaddr_in)) 834 1.25 itojun return EINVAL; 835 1.25 itojun break; 836 1.25 itojun #endif 837 1.25 itojun #ifdef INET6 838 1.25 itojun case AF_INET6: 839 1.25 itojun if (dst->sa_len != sizeof(struct sockaddr_in6)) 840 1.25 itojun return EINVAL; 841 1.25 itojun break; 842 1.25 itojun #endif 843 1.25 itojun default: 844 1.25 itojun return EAFNOSUPPORT; 845 1.25 itojun } 846 1.25 itojun 847 1.25 itojun /* check sa_family looks sane for the cmd */ 848 1.25 itojun switch (cmd) { 849 1.25 itojun case SIOCSIFPHYADDR: 850 1.25 itojun if (src->sa_family == AF_INET) 851 1.25 itojun break; 852 1.25 itojun return EAFNOSUPPORT; 853 1.25 itojun #ifdef INET6 854 1.25 itojun case SIOCSIFPHYADDR_IN6: 855 1.25 itojun if (src->sa_family == AF_INET6) 856 1.25 itojun break; 857 1.25 itojun return EAFNOSUPPORT; 858 1.25 itojun #endif /* INET6 */ 859 1.25 itojun case SIOCSLIFPHYADDR: 860 1.25 itojun /* checks done in the above */ 861 1.25 itojun break; 862 1.11 itojun } 863 1.154 roy 864 1.133 knakahar /* 865 1.133 knakahar * calls gif_getref_variant() for other softcs to check 866 1.158 andvar * address pair duplication 867 1.133 knakahar */ 868 1.133 knakahar bound = curlwp_bind(); 869 1.31 itojun error = gif_set_tunnel(&sc->gif_if, src, dst); 870 1.154 roy if (error == 0) 871 1.154 roy if_link_state_change(&sc->gif_if, LINK_STATE_UP); 872 1.133 knakahar curlwp_bindx(bound); 873 1.154 roy 874 1.9 itojun break; 875 1.9 itojun 876 1.9 itojun #ifdef SIOCDIFPHYADDR 877 1.9 itojun case SIOCDIFPHYADDR: 878 1.133 knakahar bound = curlwp_bind(); 879 1.31 itojun gif_delete_tunnel(&sc->gif_if); 880 1.154 roy if_link_state_change(&sc->gif_if, LINK_STATE_DOWN); 881 1.133 knakahar curlwp_bindx(bound); 882 1.2 itojun break; 883 1.9 itojun #endif 884 1.50 perry 885 1.2 itojun case SIOCGIFPSRCADDR: 886 1.2 itojun #ifdef INET6 887 1.2 itojun case SIOCGIFPSRCADDR_IN6: 888 1.2 itojun #endif /* INET6 */ 889 1.133 knakahar bound = curlwp_bind(); 890 1.133 knakahar var = gif_getref_variant(sc, &psref); 891 1.133 knakahar if (var->gv_psrc == NULL) { 892 1.133 knakahar gif_putref_variant(var, &psref); 893 1.133 knakahar curlwp_bindx(bound); 894 1.2 itojun error = EADDRNOTAVAIL; 895 1.2 itojun goto bad; 896 1.2 itojun } 897 1.133 knakahar src = var->gv_psrc; 898 1.16 itojun switch (cmd) { 899 1.2 itojun #ifdef INET 900 1.16 itojun case SIOCGIFPSRCADDR: 901 1.2 itojun dst = &ifr->ifr_addr; 902 1.16 itojun size = sizeof(ifr->ifr_addr); 903 1.2 itojun break; 904 1.2 itojun #endif /* INET */ 905 1.2 itojun #ifdef INET6 906 1.16 itojun case SIOCGIFPSRCADDR_IN6: 907 1.2 itojun dst = (struct sockaddr *) 908 1.2 itojun &(((struct in6_ifreq *)data)->ifr_addr); 909 1.16 itojun size = sizeof(((struct in6_ifreq *)data)->ifr_addr); 910 1.2 itojun break; 911 1.2 itojun #endif /* INET6 */ 912 1.2 itojun default: 913 1.133 knakahar gif_putref_variant(var, &psref); 914 1.133 knakahar curlwp_bindx(bound); 915 1.2 itojun error = EADDRNOTAVAIL; 916 1.2 itojun goto bad; 917 1.2 itojun } 918 1.133 knakahar if (src->sa_len > size) { 919 1.133 knakahar gif_putref_variant(var, &psref); 920 1.133 knakahar curlwp_bindx(bound); 921 1.16 itojun return EINVAL; 922 1.133 knakahar } 923 1.68 dyoung memcpy(dst, src, src->sa_len); 924 1.133 knakahar gif_putref_variant(var, &psref); 925 1.133 knakahar curlwp_bindx(bound); 926 1.2 itojun break; 927 1.50 perry 928 1.2 itojun case SIOCGIFPDSTADDR: 929 1.2 itojun #ifdef INET6 930 1.2 itojun case SIOCGIFPDSTADDR_IN6: 931 1.2 itojun #endif /* INET6 */ 932 1.133 knakahar bound = curlwp_bind(); 933 1.133 knakahar var = gif_getref_variant(sc, &psref); 934 1.133 knakahar if (var->gv_pdst == NULL) { 935 1.133 knakahar gif_putref_variant(var, &psref); 936 1.133 knakahar curlwp_bindx(bound); 937 1.2 itojun error = EADDRNOTAVAIL; 938 1.2 itojun goto bad; 939 1.2 itojun } 940 1.133 knakahar src = var->gv_pdst; 941 1.16 itojun switch (cmd) { 942 1.2 itojun #ifdef INET 943 1.16 itojun case SIOCGIFPDSTADDR: 944 1.2 itojun dst = &ifr->ifr_addr; 945 1.16 itojun size = sizeof(ifr->ifr_addr); 946 1.2 itojun break; 947 1.2 itojun #endif /* INET */ 948 1.2 itojun #ifdef INET6 949 1.16 itojun case SIOCGIFPDSTADDR_IN6: 950 1.2 itojun dst = (struct sockaddr *) 951 1.2 itojun &(((struct in6_ifreq *)data)->ifr_addr); 952 1.16 itojun size = sizeof(((struct in6_ifreq *)data)->ifr_addr); 953 1.2 itojun break; 954 1.2 itojun #endif /* INET6 */ 955 1.2 itojun default: 956 1.133 knakahar gif_putref_variant(var, &psref); 957 1.133 knakahar curlwp_bindx(bound); 958 1.2 itojun error = EADDRNOTAVAIL; 959 1.2 itojun goto bad; 960 1.2 itojun } 961 1.133 knakahar if (src->sa_len > size) { 962 1.133 knakahar gif_putref_variant(var, &psref); 963 1.133 knakahar curlwp_bindx(bound); 964 1.25 itojun return EINVAL; 965 1.133 knakahar } 966 1.68 dyoung memcpy(dst, src, src->sa_len); 967 1.133 knakahar gif_putref_variant(var, &psref); 968 1.133 knakahar curlwp_bindx(bound); 969 1.25 itojun break; 970 1.25 itojun 971 1.25 itojun case SIOCGLIFPHYADDR: 972 1.133 knakahar bound = curlwp_bind(); 973 1.133 knakahar var = gif_getref_variant(sc, &psref); 974 1.133 knakahar if (var->gv_psrc == NULL || var->gv_pdst == NULL) { 975 1.133 knakahar gif_putref_variant(var, &psref); 976 1.133 knakahar curlwp_bindx(bound); 977 1.25 itojun error = EADDRNOTAVAIL; 978 1.25 itojun goto bad; 979 1.25 itojun } 980 1.25 itojun 981 1.25 itojun /* copy src */ 982 1.133 knakahar src = var->gv_psrc; 983 1.25 itojun dst = (struct sockaddr *) 984 1.25 itojun &(((struct if_laddrreq *)data)->addr); 985 1.25 itojun size = sizeof(((struct if_laddrreq *)data)->addr); 986 1.133 knakahar if (src->sa_len > size) { 987 1.133 knakahar gif_putref_variant(var, &psref); 988 1.133 knakahar curlwp_bindx(bound); 989 1.25 itojun return EINVAL; 990 1.133 knakahar } 991 1.68 dyoung memcpy(dst, src, src->sa_len); 992 1.25 itojun 993 1.25 itojun /* copy dst */ 994 1.133 knakahar src = var->gv_pdst; 995 1.25 itojun dst = (struct sockaddr *) 996 1.25 itojun &(((struct if_laddrreq *)data)->dstaddr); 997 1.25 itojun size = sizeof(((struct if_laddrreq *)data)->dstaddr); 998 1.133 knakahar if (src->sa_len > size) { 999 1.133 knakahar gif_putref_variant(var, &psref); 1000 1.133 knakahar curlwp_bindx(bound); 1001 1.16 itojun return EINVAL; 1002 1.133 knakahar } 1003 1.68 dyoung memcpy(dst, src, src->sa_len); 1004 1.133 knakahar gif_putref_variant(var, &psref); 1005 1.133 knakahar curlwp_bindx(bound); 1006 1.2 itojun break; 1007 1.2 itojun 1008 1.2 itojun default: 1009 1.76 dyoung return ifioctl_common(ifp, cmd, data); 1010 1.2 itojun } 1011 1.2 itojun bad: 1012 1.2 itojun return error; 1013 1.12 thorpej } 1014 1.12 thorpej 1015 1.97 knakahar static int 1016 1.133 knakahar gif_encap_attach(struct gif_variant *var) 1017 1.97 knakahar { 1018 1.97 knakahar int error; 1019 1.97 knakahar 1020 1.133 knakahar if (var == NULL || var->gv_psrc == NULL) 1021 1.97 knakahar return EINVAL; 1022 1.97 knakahar 1023 1.133 knakahar switch (var->gv_psrc->sa_family) { 1024 1.97 knakahar #ifdef INET 1025 1.97 knakahar case AF_INET: 1026 1.133 knakahar error = in_gif_attach(var); 1027 1.97 knakahar break; 1028 1.97 knakahar #endif 1029 1.97 knakahar #ifdef INET6 1030 1.97 knakahar case AF_INET6: 1031 1.133 knakahar error = in6_gif_attach(var); 1032 1.97 knakahar break; 1033 1.97 knakahar #endif 1034 1.97 knakahar default: 1035 1.97 knakahar error = EINVAL; 1036 1.97 knakahar break; 1037 1.97 knakahar } 1038 1.97 knakahar 1039 1.97 knakahar return error; 1040 1.97 knakahar } 1041 1.97 knakahar 1042 1.97 knakahar static int 1043 1.133 knakahar gif_encap_detach(struct gif_variant *var) 1044 1.97 knakahar { 1045 1.97 knakahar int error; 1046 1.97 knakahar 1047 1.133 knakahar if (var == NULL || var->gv_psrc == NULL) 1048 1.97 knakahar return EINVAL; 1049 1.97 knakahar 1050 1.133 knakahar switch (var->gv_psrc->sa_family) { 1051 1.97 knakahar #ifdef INET 1052 1.97 knakahar case AF_INET: 1053 1.133 knakahar error = in_gif_detach(var); 1054 1.97 knakahar break; 1055 1.97 knakahar #endif 1056 1.97 knakahar #ifdef INET6 1057 1.97 knakahar case AF_INET6: 1058 1.133 knakahar error = in6_gif_detach(var); 1059 1.97 knakahar break; 1060 1.97 knakahar #endif 1061 1.97 knakahar default: 1062 1.97 knakahar error = EINVAL; 1063 1.97 knakahar break; 1064 1.97 knakahar } 1065 1.97 knakahar 1066 1.97 knakahar return error; 1067 1.97 knakahar } 1068 1.97 knakahar 1069 1.109 knakahar static int 1070 1.56 thorpej gif_set_tunnel(struct ifnet *ifp, struct sockaddr *src, struct sockaddr *dst) 1071 1.31 itojun { 1072 1.76 dyoung struct gif_softc *sc = ifp->if_softc; 1073 1.31 itojun struct gif_softc *sc2; 1074 1.133 knakahar struct gif_variant *ovar, *nvar; 1075 1.71 dyoung struct sockaddr *osrc, *odst; 1076 1.96 knakahar struct sockaddr *nsrc, *ndst; 1077 1.118 knakahar int error; 1078 1.118 knakahar #ifndef GIF_MPSAFE 1079 1.31 itojun int s; 1080 1.31 itojun 1081 1.31 itojun s = splsoftnet(); 1082 1.118 knakahar #endif 1083 1.117 knakahar error = encap_lock_enter(); 1084 1.117 knakahar if (error) { 1085 1.118 knakahar #ifndef GIF_MPSAFE 1086 1.117 knakahar splx(s); 1087 1.118 knakahar #endif 1088 1.117 knakahar return error; 1089 1.117 knakahar } 1090 1.31 itojun 1091 1.133 knakahar nsrc = sockaddr_dup(src, M_WAITOK); 1092 1.133 knakahar ndst = sockaddr_dup(dst, M_WAITOK); 1093 1.133 knakahar nvar = kmem_alloc(sizeof(*nvar), KM_SLEEP); 1094 1.133 knakahar 1095 1.133 knakahar mutex_enter(&sc->gif_lock); 1096 1.133 knakahar 1097 1.133 knakahar ovar = sc->gif_var; 1098 1.133 knakahar 1099 1.133 knakahar if ((ovar->gv_pdst && sockaddr_cmp(ovar->gv_pdst, dst) == 0) && 1100 1.133 knakahar (ovar->gv_psrc && sockaddr_cmp(ovar->gv_psrc, src) == 0)) { 1101 1.133 knakahar /* address and port pair not changed. */ 1102 1.133 knakahar error = 0; 1103 1.133 knakahar goto out; 1104 1.133 knakahar } 1105 1.133 knakahar 1106 1.130 knakahar mutex_enter(&gif_softcs.lock); 1107 1.130 knakahar LIST_FOREACH(sc2, &gif_softcs.list, gif_list) { 1108 1.133 knakahar struct gif_variant *var2; 1109 1.133 knakahar struct psref psref; 1110 1.133 knakahar 1111 1.31 itojun if (sc2 == sc) 1112 1.31 itojun continue; 1113 1.146 knakahar var2 = gif_getref_variant(sc2, &psref); 1114 1.133 knakahar if (!var2->gv_pdst || !var2->gv_psrc) { 1115 1.133 knakahar gif_putref_variant(var2, &psref); 1116 1.31 itojun continue; 1117 1.133 knakahar } 1118 1.31 itojun /* can't configure same pair of address onto two gifs */ 1119 1.133 knakahar if (sockaddr_cmp(var2->gv_pdst, dst) == 0 && 1120 1.133 knakahar sockaddr_cmp(var2->gv_psrc, src) == 0) { 1121 1.147 msaitoh /* continue to use the old configuration. */ 1122 1.133 knakahar gif_putref_variant(var2, &psref); 1123 1.130 knakahar mutex_exit(&gif_softcs.lock); 1124 1.118 knakahar error = EADDRNOTAVAIL; 1125 1.118 knakahar goto out; 1126 1.31 itojun } 1127 1.133 knakahar gif_putref_variant(var2, &psref); 1128 1.31 itojun /* XXX both end must be valid? (I mean, not 0.0.0.0) */ 1129 1.31 itojun } 1130 1.130 knakahar mutex_exit(&gif_softcs.lock); 1131 1.31 itojun 1132 1.133 knakahar osrc = ovar->gv_psrc; 1133 1.133 knakahar odst = ovar->gv_pdst; 1134 1.96 knakahar 1135 1.133 knakahar *nvar = *ovar; 1136 1.133 knakahar nvar->gv_psrc = nsrc; 1137 1.133 knakahar nvar->gv_pdst = ndst; 1138 1.133 knakahar nvar->gv_encap_cookie4 = NULL; 1139 1.133 knakahar nvar->gv_encap_cookie6 = NULL; 1140 1.133 knakahar error = gif_encap_attach(nvar); 1141 1.133 knakahar if (error) 1142 1.133 knakahar goto out; 1143 1.133 knakahar psref_target_init(&nvar->gv_psref, gv_psref_class); 1144 1.133 knakahar gif_update_variant(sc, nvar); 1145 1.114 knakahar 1146 1.133 knakahar mutex_exit(&sc->gif_lock); 1147 1.31 itojun 1148 1.133 knakahar (void)gif_encap_detach(ovar); 1149 1.133 knakahar encap_lock_exit(); 1150 1.31 itojun 1151 1.31 itojun if (osrc) 1152 1.71 dyoung sockaddr_free(osrc); 1153 1.31 itojun if (odst) 1154 1.71 dyoung sockaddr_free(odst); 1155 1.133 knakahar kmem_free(ovar, sizeof(*ovar)); 1156 1.31 itojun 1157 1.133 knakahar #ifndef GIF_MPSAFE 1158 1.133 knakahar splx(s); 1159 1.133 knakahar #endif 1160 1.133 knakahar return 0; 1161 1.92 knakahar 1162 1.118 knakahar out: 1163 1.159 skrll mutex_exit(&sc->gif_lock); 1164 1.159 skrll encap_lock_exit(); 1165 1.159 skrll 1166 1.133 knakahar sockaddr_free(nsrc); 1167 1.133 knakahar sockaddr_free(ndst); 1168 1.133 knakahar kmem_free(nvar, sizeof(*nvar)); 1169 1.133 knakahar 1170 1.118 knakahar #ifndef GIF_MPSAFE 1171 1.31 itojun splx(s); 1172 1.118 knakahar #endif 1173 1.31 itojun return error; 1174 1.31 itojun } 1175 1.31 itojun 1176 1.109 knakahar static void 1177 1.56 thorpej gif_delete_tunnel(struct ifnet *ifp) 1178 1.12 thorpej { 1179 1.76 dyoung struct gif_softc *sc = ifp->if_softc; 1180 1.133 knakahar struct gif_variant *ovar, *nvar; 1181 1.133 knakahar struct sockaddr *osrc, *odst; 1182 1.118 knakahar int error; 1183 1.118 knakahar #ifndef GIF_MPSAFE 1184 1.12 thorpej int s; 1185 1.12 thorpej 1186 1.12 thorpej s = splsoftnet(); 1187 1.118 knakahar #endif 1188 1.117 knakahar error = encap_lock_enter(); 1189 1.117 knakahar if (error) { 1190 1.118 knakahar #ifndef GIF_MPSAFE 1191 1.117 knakahar splx(s); 1192 1.118 knakahar #endif 1193 1.117 knakahar return; 1194 1.117 knakahar } 1195 1.12 thorpej 1196 1.133 knakahar nvar = kmem_alloc(sizeof(*nvar), KM_SLEEP); 1197 1.133 knakahar 1198 1.133 knakahar mutex_enter(&sc->gif_lock); 1199 1.133 knakahar 1200 1.133 knakahar ovar = sc->gif_var; 1201 1.133 knakahar osrc = ovar->gv_psrc; 1202 1.133 knakahar odst = ovar->gv_pdst; 1203 1.133 knakahar if (osrc == NULL || odst == NULL) { 1204 1.133 knakahar /* address pair not changed. */ 1205 1.133 knakahar mutex_exit(&sc->gif_lock); 1206 1.133 knakahar encap_lock_exit(); 1207 1.133 knakahar kmem_free(nvar, sizeof(*nvar)); 1208 1.138 maxv #ifndef GIF_MPSAFE 1209 1.138 maxv splx(s); 1210 1.138 maxv #endif 1211 1.133 knakahar return; 1212 1.12 thorpej } 1213 1.12 thorpej 1214 1.133 knakahar *nvar = *ovar; 1215 1.133 knakahar nvar->gv_psrc = NULL; 1216 1.133 knakahar nvar->gv_pdst = NULL; 1217 1.133 knakahar nvar->gv_encap_cookie4 = NULL; 1218 1.133 knakahar nvar->gv_encap_cookie6 = NULL; 1219 1.133 knakahar nvar->gv_output = NULL; 1220 1.133 knakahar psref_target_init(&nvar->gv_psref, gv_psref_class); 1221 1.133 knakahar gif_update_variant(sc, nvar); 1222 1.133 knakahar 1223 1.133 knakahar mutex_exit(&sc->gif_lock); 1224 1.114 knakahar 1225 1.133 knakahar gif_encap_detach(ovar); 1226 1.115 knakahar encap_lock_exit(); 1227 1.133 knakahar 1228 1.133 knakahar sockaddr_free(osrc); 1229 1.133 knakahar sockaddr_free(odst); 1230 1.133 knakahar kmem_free(ovar, sizeof(*ovar)); 1231 1.133 knakahar 1232 1.118 knakahar #ifndef GIF_MPSAFE 1233 1.12 thorpej splx(s); 1234 1.118 knakahar #endif 1235 1.2 itojun } 1236 1.120 christos 1237 1.120 christos /* 1238 1.133 knakahar * gif_variant update API. 1239 1.133 knakahar * 1240 1.133 knakahar * Assumption: 1241 1.133 knakahar * reader side dereferences sc->gif_var in reader critical section only, 1242 1.133 knakahar * that is, all of reader sides do not reader the sc->gif_var after 1243 1.133 knakahar * pserialize_perform(). 1244 1.133 knakahar */ 1245 1.133 knakahar static void 1246 1.133 knakahar gif_update_variant(struct gif_softc *sc, struct gif_variant *nvar) 1247 1.133 knakahar { 1248 1.133 knakahar struct ifnet *ifp = &sc->gif_if; 1249 1.133 knakahar struct gif_variant *ovar = sc->gif_var; 1250 1.133 knakahar 1251 1.133 knakahar KASSERT(mutex_owned(&sc->gif_lock)); 1252 1.133 knakahar 1253 1.152 riastrad atomic_store_release(&sc->gif_var, nvar); 1254 1.144 knakahar pserialize_perform(sc->gif_psz); 1255 1.133 knakahar psref_target_destroy(&ovar->gv_psref, gv_psref_class); 1256 1.133 knakahar 1257 1.133 knakahar if (nvar->gv_psrc != NULL && nvar->gv_pdst != NULL) 1258 1.133 knakahar ifp->if_flags |= IFF_RUNNING; 1259 1.133 knakahar else 1260 1.133 knakahar ifp->if_flags &= ~IFF_RUNNING; 1261 1.133 knakahar } 1262 1.133 knakahar 1263 1.133 knakahar /* 1264 1.120 christos * Module infrastructure 1265 1.120 christos */ 1266 1.120 christos #include "if_module.h" 1267 1.120 christos 1268 1.136 pgoyette IF_MODULE(MODULE_CLASS_DRIVER, gif, "ip_ecn") 1269