1 1.49 yamaguch /* $NetBSD: if_l2tp.c,v 1.49 2023/11/02 09:43:46 yamaguchi Exp $ */ 2 1.1 knakahar 3 1.1 knakahar /* 4 1.1 knakahar * Copyright (c) 2017 Internet Initiative Japan Inc. 5 1.1 knakahar * All rights reserved. 6 1.1 knakahar * 7 1.1 knakahar * Redistribution and use in source and binary forms, with or without 8 1.1 knakahar * modification, are permitted provided that the following conditions 9 1.1 knakahar * are met: 10 1.1 knakahar * 1. Redistributions of source code must retain the above copyright 11 1.1 knakahar * notice, this list of conditions and the following disclaimer. 12 1.1 knakahar * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 knakahar * notice, this list of conditions and the following disclaimer in the 14 1.1 knakahar * documentation and/or other materials provided with the distribution. 15 1.1 knakahar * 16 1.1 knakahar * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 1.1 knakahar * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 1.1 knakahar * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 1.1 knakahar * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 1.1 knakahar * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 1.1 knakahar * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 1.1 knakahar * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 1.1 knakahar * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 1.1 knakahar * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 1.1 knakahar * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 1.1 knakahar * POSSIBILITY OF SUCH DAMAGE. 27 1.1 knakahar */ 28 1.1 knakahar 29 1.1 knakahar /* 30 1.1 knakahar * L2TPv3 kernel interface 31 1.1 knakahar */ 32 1.1 knakahar 33 1.1 knakahar #include <sys/cdefs.h> 34 1.49 yamaguch __KERNEL_RCSID(0, "$NetBSD: if_l2tp.c,v 1.49 2023/11/02 09:43:46 yamaguchi Exp $"); 35 1.1 knakahar 36 1.1 knakahar #ifdef _KERNEL_OPT 37 1.1 knakahar #include "opt_inet.h" 38 1.17 ozaki #include "opt_net_mpsafe.h" 39 1.1 knakahar #endif 40 1.1 knakahar 41 1.1 knakahar #include <sys/param.h> 42 1.1 knakahar #include <sys/systm.h> 43 1.1 knakahar #include <sys/kernel.h> 44 1.1 knakahar #include <sys/mbuf.h> 45 1.1 knakahar #include <sys/socket.h> 46 1.1 knakahar #include <sys/sockio.h> 47 1.1 knakahar #include <sys/errno.h> 48 1.1 knakahar #include <sys/ioctl.h> 49 1.1 knakahar #include <sys/time.h> 50 1.1 knakahar #include <sys/syslog.h> 51 1.1 knakahar #include <sys/proc.h> 52 1.1 knakahar #include <sys/conf.h> 53 1.1 knakahar #include <sys/kauth.h> 54 1.1 knakahar #include <sys/cpu.h> 55 1.1 knakahar #include <sys/cprng.h> 56 1.1 knakahar #include <sys/intr.h> 57 1.1 knakahar #include <sys/kmem.h> 58 1.1 knakahar #include <sys/mutex.h> 59 1.1 knakahar #include <sys/atomic.h> 60 1.1 knakahar #include <sys/pserialize.h> 61 1.1 knakahar #include <sys/device.h> 62 1.1 knakahar #include <sys/module.h> 63 1.1 knakahar 64 1.1 knakahar #include <net/if.h> 65 1.1 knakahar #include <net/if_dl.h> 66 1.1 knakahar #include <net/if_ether.h> 67 1.1 knakahar #include <net/if_types.h> 68 1.1 knakahar #include <net/route.h> 69 1.1 knakahar #include <net/bpf.h> 70 1.7 sevan #include <net/if_vlanvar.h> 71 1.1 knakahar 72 1.1 knakahar #include <netinet/in.h> 73 1.1 knakahar #include <netinet/in_systm.h> 74 1.1 knakahar #include <netinet/ip.h> 75 1.1 knakahar #include <netinet/ip_encap.h> 76 1.1 knakahar #ifdef INET 77 1.1 knakahar #include <netinet/in_var.h> 78 1.1 knakahar #include <netinet/in_l2tp.h> 79 1.1 knakahar #endif /* INET */ 80 1.1 knakahar #ifdef INET6 81 1.1 knakahar #include <netinet6/in6_l2tp.h> 82 1.1 knakahar #endif 83 1.1 knakahar 84 1.1 knakahar #include <net/if_l2tp.h> 85 1.1 knakahar 86 1.1 knakahar #include <net/if_vlanvar.h> 87 1.1 knakahar 88 1.1 knakahar /* TODO: IP_TCPMSS support */ 89 1.1 knakahar #undef IP_TCPMSS 90 1.1 knakahar #ifdef IP_TCPMSS 91 1.1 knakahar #include <netinet/ip_tcpmss.h> 92 1.1 knakahar #endif 93 1.1 knakahar 94 1.1 knakahar /* 95 1.1 knakahar * l2tp global variable definitions 96 1.1 knakahar */ 97 1.1 knakahar static struct { 98 1.35 msaitoh LIST_HEAD(l2tp_sclist, l2tp_softc) list; 99 1.1 knakahar kmutex_t lock; 100 1.1 knakahar } l2tp_softcs __cacheline_aligned; 101 1.1 knakahar 102 1.1 knakahar 103 1.1 knakahar #if !defined(L2TP_ID_HASH_SIZE) 104 1.1 knakahar #define L2TP_ID_HASH_SIZE 64 105 1.1 knakahar #endif 106 1.1 knakahar static struct { 107 1.1 knakahar kmutex_t lock; 108 1.1 knakahar struct pslist_head *lists; 109 1.9 knakahar u_long mask; 110 1.1 knakahar } l2tp_hash __cacheline_aligned = { 111 1.1 knakahar .lists = NULL, 112 1.1 knakahar }; 113 1.1 knakahar 114 1.1 knakahar pserialize_t l2tp_psz __read_mostly; 115 1.1 knakahar struct psref_class *lv_psref_class __read_mostly; 116 1.1 knakahar 117 1.37 knakahar static void l2tp_ifq_init_pc(void *, void *, struct cpu_info *); 118 1.39 knakahar static void l2tp_ifq_fini_pc(void *, void *, struct cpu_info *); 119 1.37 knakahar 120 1.1 knakahar static int l2tp_clone_create(struct if_clone *, int); 121 1.1 knakahar static int l2tp_clone_destroy(struct ifnet *); 122 1.1 knakahar 123 1.1 knakahar struct if_clone l2tp_cloner = 124 1.1 knakahar IF_CLONE_INITIALIZER("l2tp", l2tp_clone_create, l2tp_clone_destroy); 125 1.1 knakahar 126 1.37 knakahar static int l2tp_tx_enqueue(struct l2tp_variant *, struct mbuf *); 127 1.1 knakahar static int l2tp_output(struct ifnet *, struct mbuf *, 128 1.1 knakahar const struct sockaddr *, const struct rtentry *); 129 1.37 knakahar static void l2tp_sendit(struct l2tp_variant *, struct mbuf *); 130 1.1 knakahar static void l2tpintr(struct l2tp_variant *); 131 1.37 knakahar static void l2tpintr_softint(void *); 132 1.1 knakahar 133 1.1 knakahar static void l2tp_hash_init(void); 134 1.1 knakahar static int l2tp_hash_fini(void); 135 1.1 knakahar 136 1.1 knakahar static void l2tp_start(struct ifnet *); 137 1.1 knakahar static int l2tp_transmit(struct ifnet *, struct mbuf *); 138 1.1 knakahar 139 1.1 knakahar static int l2tp_set_tunnel(struct ifnet *, struct sockaddr *, 140 1.1 knakahar struct sockaddr *); 141 1.1 knakahar static void l2tp_delete_tunnel(struct ifnet *); 142 1.1 knakahar 143 1.9 knakahar static int id_hash_func(uint32_t, u_long); 144 1.1 knakahar 145 1.1 knakahar static void l2tp_variant_update(struct l2tp_softc *, struct l2tp_variant *); 146 1.1 knakahar static int l2tp_set_session(struct l2tp_softc *, uint32_t, uint32_t); 147 1.1 knakahar static int l2tp_clear_session(struct l2tp_softc *); 148 1.1 knakahar static int l2tp_set_cookie(struct l2tp_softc *, uint64_t, u_int, uint64_t, u_int); 149 1.1 knakahar static void l2tp_clear_cookie(struct l2tp_softc *); 150 1.1 knakahar static void l2tp_set_state(struct l2tp_softc *, int); 151 1.1 knakahar static int l2tp_encap_attach(struct l2tp_variant *); 152 1.1 knakahar static int l2tp_encap_detach(struct l2tp_variant *); 153 1.1 knakahar 154 1.39 knakahar static inline struct ifqueue * 155 1.39 knakahar l2tp_ifq_percpu_getref(percpu_t *pc) 156 1.39 knakahar { 157 1.39 knakahar 158 1.39 knakahar return *(struct ifqueue **)percpu_getref(pc); 159 1.39 knakahar } 160 1.39 knakahar 161 1.39 knakahar static inline void 162 1.39 knakahar l2tp_ifq_percpu_putref(percpu_t *pc) 163 1.39 knakahar { 164 1.39 knakahar 165 1.39 knakahar percpu_putref(pc); 166 1.39 knakahar } 167 1.39 knakahar 168 1.1 knakahar #ifndef MAX_L2TP_NEST 169 1.1 knakahar /* 170 1.1 knakahar * This macro controls the upper limitation on nesting of l2tp tunnels. 171 1.1 knakahar * Since, setting a large value to this macro with a careless configuration 172 1.1 knakahar * may introduce system crash, we don't allow any nestings by default. 173 1.1 knakahar * If you need to configure nested l2tp tunnels, you can define this macro 174 1.1 knakahar * in your kernel configuration file. However, if you do so, please be 175 1.1 knakahar * careful to configure the tunnels so that it won't make a loop. 176 1.1 knakahar */ 177 1.1 knakahar /* 178 1.1 knakahar * XXX 179 1.1 knakahar * Currently, if in_l2tp_output recursively calls, it causes locking against 180 1.1 knakahar * myself of struct l2tp_ro->lr_lock. So, nested l2tp tunnels is prohibited. 181 1.1 knakahar */ 182 1.1 knakahar #define MAX_L2TP_NEST 0 183 1.1 knakahar #endif 184 1.1 knakahar 185 1.1 knakahar static int max_l2tp_nesting = MAX_L2TP_NEST; 186 1.1 knakahar 187 1.1 knakahar /* ARGSUSED */ 188 1.1 knakahar void 189 1.1 knakahar l2tpattach(int count) 190 1.1 knakahar { 191 1.1 knakahar /* 192 1.1 knakahar * Nothing to do here, initialization is handled by the 193 1.1 knakahar * module initialization code in l2tpinit() below). 194 1.1 knakahar */ 195 1.1 knakahar } 196 1.1 knakahar 197 1.1 knakahar static void 198 1.1 knakahar l2tpinit(void) 199 1.1 knakahar { 200 1.1 knakahar 201 1.1 knakahar mutex_init(&l2tp_softcs.lock, MUTEX_DEFAULT, IPL_NONE); 202 1.1 knakahar LIST_INIT(&l2tp_softcs.list); 203 1.1 knakahar 204 1.1 knakahar mutex_init(&l2tp_hash.lock, MUTEX_DEFAULT, IPL_NONE); 205 1.1 knakahar l2tp_psz = pserialize_create(); 206 1.1 knakahar lv_psref_class = psref_class_create("l2tpvar", IPL_SOFTNET); 207 1.1 knakahar if_clone_attach(&l2tp_cloner); 208 1.1 knakahar 209 1.1 knakahar l2tp_hash_init(); 210 1.1 knakahar } 211 1.1 knakahar 212 1.1 knakahar static int 213 1.1 knakahar l2tpdetach(void) 214 1.1 knakahar { 215 1.1 knakahar int error; 216 1.1 knakahar 217 1.1 knakahar mutex_enter(&l2tp_softcs.lock); 218 1.1 knakahar if (!LIST_EMPTY(&l2tp_softcs.list)) { 219 1.1 knakahar mutex_exit(&l2tp_softcs.lock); 220 1.1 knakahar return EBUSY; 221 1.1 knakahar } 222 1.1 knakahar mutex_exit(&l2tp_softcs.lock); 223 1.1 knakahar 224 1.1 knakahar error = l2tp_hash_fini(); 225 1.1 knakahar if (error) 226 1.1 knakahar return error; 227 1.1 knakahar 228 1.1 knakahar if_clone_detach(&l2tp_cloner); 229 1.1 knakahar psref_class_destroy(lv_psref_class); 230 1.1 knakahar pserialize_destroy(l2tp_psz); 231 1.1 knakahar mutex_destroy(&l2tp_hash.lock); 232 1.1 knakahar 233 1.4 knakahar mutex_destroy(&l2tp_softcs.lock); 234 1.4 knakahar 235 1.1 knakahar return error; 236 1.1 knakahar } 237 1.1 knakahar 238 1.1 knakahar static int 239 1.1 knakahar l2tp_clone_create(struct if_clone *ifc, int unit) 240 1.1 knakahar { 241 1.1 knakahar struct l2tp_softc *sc; 242 1.1 knakahar struct l2tp_variant *var; 243 1.13 knakahar int rv; 244 1.37 knakahar u_int si_flags = SOFTINT_NET; 245 1.37 knakahar #ifdef NET_MPSAFE 246 1.37 knakahar si_flags |= SOFTINT_MPSAFE; 247 1.37 knakahar #endif 248 1.1 knakahar sc = kmem_zalloc(sizeof(struct l2tp_softc), KM_SLEEP); 249 1.13 knakahar if_initname(&sc->l2tp_ec.ec_if, ifc->ifc_name, unit); 250 1.13 knakahar rv = l2tpattach0(sc); 251 1.13 knakahar if (rv != 0) { 252 1.13 knakahar kmem_free(sc, sizeof(struct l2tp_softc)); 253 1.13 knakahar return rv; 254 1.13 knakahar } 255 1.13 knakahar 256 1.1 knakahar var = kmem_zalloc(sizeof(struct l2tp_variant), KM_SLEEP); 257 1.1 knakahar var->lv_softc = sc; 258 1.1 knakahar var->lv_state = L2TP_STATE_DOWN; 259 1.1 knakahar var->lv_use_cookie = L2TP_COOKIE_OFF; 260 1.1 knakahar psref_target_init(&var->lv_psref, lv_psref_class); 261 1.1 knakahar 262 1.1 knakahar sc->l2tp_var = var; 263 1.1 knakahar mutex_init(&sc->l2tp_lock, MUTEX_DEFAULT, IPL_NONE); 264 1.30 knakahar sc->l2tp_psz = pserialize_create(); 265 1.1 knakahar PSLIST_ENTRY_INIT(sc, l2tp_hash); 266 1.1 knakahar 267 1.38 knakahar sc->l2tp_ro_percpu = if_tunnel_alloc_ro_percpu(); 268 1.1 knakahar 269 1.43 riastrad sc->l2tp_ifq_percpu = percpu_create(sizeof(struct ifqueue *), 270 1.43 riastrad l2tp_ifq_init_pc, l2tp_ifq_fini_pc, NULL); 271 1.37 knakahar sc->l2tp_si = softint_establish(si_flags, l2tpintr_softint, sc); 272 1.37 knakahar 273 1.1 knakahar mutex_enter(&l2tp_softcs.lock); 274 1.1 knakahar LIST_INSERT_HEAD(&l2tp_softcs.list, sc, l2tp_list); 275 1.1 knakahar mutex_exit(&l2tp_softcs.lock); 276 1.1 knakahar 277 1.1 knakahar return (0); 278 1.1 knakahar } 279 1.1 knakahar 280 1.13 knakahar int 281 1.1 knakahar l2tpattach0(struct l2tp_softc *sc) 282 1.1 knakahar { 283 1.1 knakahar 284 1.49 yamaguch sc->l2tp_ec.ec_capabilities = 0; 285 1.49 yamaguch sc->l2tp_ec.ec_capabilities |= ETHERCAP_VLAN_MTU; 286 1.49 yamaguch sc->l2tp_ec.ec_capabilities |= ETHERCAP_JUMBO_MTU; 287 1.49 yamaguch 288 1.49 yamaguch ether_ifattach(&sc->l2tp_ec.ec_if, NULL); 289 1.49 yamaguch 290 1.1 knakahar sc->l2tp_ec.ec_if.if_addrlen = 0; 291 1.1 knakahar sc->l2tp_ec.ec_if.if_mtu = L2TP_MTU; 292 1.1 knakahar sc->l2tp_ec.ec_if.if_flags = IFF_POINTOPOINT|IFF_MULTICAST|IFF_SIMPLEX; 293 1.17 ozaki #ifdef NET_MPSAFE 294 1.44 roy sc->l2tp_ec.ec_if.if_extflags = IFEF_MPSAFE; 295 1.17 ozaki #endif 296 1.1 knakahar sc->l2tp_ec.ec_if.if_ioctl = l2tp_ioctl; 297 1.1 knakahar sc->l2tp_ec.ec_if.if_output = l2tp_output; 298 1.1 knakahar sc->l2tp_ec.ec_if.if_type = IFT_L2TP; 299 1.1 knakahar sc->l2tp_ec.ec_if.if_dlt = DLT_NULL; 300 1.1 knakahar sc->l2tp_ec.ec_if.if_start = l2tp_start; 301 1.1 knakahar sc->l2tp_ec.ec_if.if_transmit = l2tp_transmit; 302 1.1 knakahar sc->l2tp_ec.ec_if._if_input = ether_input; 303 1.1 knakahar IFQ_SET_READY(&sc->l2tp_ec.ec_if.if_snd); 304 1.36 ozaki 305 1.13 knakahar /* XXX 306 1.13 knakahar * It may improve performance to use if_initialize()/if_register() 307 1.13 knakahar * so that l2tp_input() calls if_input() instead of 308 1.13 knakahar * if_percpuq_enqueue(). However, that causes recursive softnet_lock 309 1.13 knakahar * when NET_MPSAFE is not set. 310 1.13 knakahar */ 311 1.47 riastrad if_attach(&sc->l2tp_ec.ec_if); 312 1.46 roy if_link_state_change(&sc->l2tp_ec.ec_if, LINK_STATE_DOWN); 313 1.1 knakahar if_alloc_sadl(&sc->l2tp_ec.ec_if); 314 1.13 knakahar 315 1.13 knakahar return 0; 316 1.1 knakahar } 317 1.1 knakahar 318 1.1 knakahar void 319 1.37 knakahar l2tp_ifq_init_pc(void *p, void *arg __unused, struct cpu_info *ci __unused) 320 1.37 knakahar { 321 1.39 knakahar struct ifqueue **ifqp = p; 322 1.37 knakahar 323 1.39 knakahar *ifqp = kmem_zalloc(sizeof(**ifqp), KM_SLEEP); 324 1.39 knakahar (*ifqp)->ifq_maxlen = IFQ_MAXLEN; 325 1.39 knakahar } 326 1.39 knakahar 327 1.39 knakahar void 328 1.39 knakahar l2tp_ifq_fini_pc(void *p, void *arg __unused, struct cpu_info *ci __unused) 329 1.39 knakahar { 330 1.39 knakahar struct ifqueue **ifqp = p; 331 1.39 knakahar 332 1.39 knakahar kmem_free(*ifqp, sizeof(**ifqp)); 333 1.37 knakahar } 334 1.37 knakahar 335 1.1 knakahar static int 336 1.1 knakahar l2tp_clone_destroy(struct ifnet *ifp) 337 1.1 knakahar { 338 1.5 knakahar struct l2tp_variant *var; 339 1.1 knakahar struct l2tp_softc *sc = container_of(ifp, struct l2tp_softc, 340 1.1 knakahar l2tp_ec.ec_if); 341 1.1 knakahar 342 1.49 yamaguch ether_ifdetach(ifp); 343 1.49 yamaguch 344 1.1 knakahar l2tp_clear_session(sc); 345 1.1 knakahar l2tp_delete_tunnel(&sc->l2tp_ec.ec_if); 346 1.3 knakahar /* 347 1.37 knakahar * To avoid for l2tp_transmit() and l2tpintr_softint() to access 348 1.37 knakahar * sc->l2tp_var after free it. 349 1.3 knakahar */ 350 1.3 knakahar mutex_enter(&sc->l2tp_lock); 351 1.5 knakahar var = sc->l2tp_var; 352 1.3 knakahar l2tp_variant_update(sc, NULL); 353 1.3 knakahar mutex_exit(&sc->l2tp_lock); 354 1.1 knakahar 355 1.37 knakahar softint_disestablish(sc->l2tp_si); 356 1.39 knakahar percpu_free(sc->l2tp_ifq_percpu, sizeof(struct ifqueue *)); 357 1.37 knakahar 358 1.1 knakahar mutex_enter(&l2tp_softcs.lock); 359 1.1 knakahar LIST_REMOVE(sc, l2tp_list); 360 1.1 knakahar mutex_exit(&l2tp_softcs.lock); 361 1.1 knakahar 362 1.1 knakahar if_detach(ifp); 363 1.1 knakahar 364 1.38 knakahar if_tunnel_free_ro_percpu(sc->l2tp_ro_percpu); 365 1.1 knakahar 366 1.5 knakahar kmem_free(var, sizeof(struct l2tp_variant)); 367 1.30 knakahar pserialize_destroy(sc->l2tp_psz); 368 1.1 knakahar mutex_destroy(&sc->l2tp_lock); 369 1.1 knakahar kmem_free(sc, sizeof(struct l2tp_softc)); 370 1.1 knakahar 371 1.1 knakahar return 0; 372 1.1 knakahar } 373 1.1 knakahar 374 1.1 knakahar static int 375 1.37 knakahar l2tp_tx_enqueue(struct l2tp_variant *var, struct mbuf *m) 376 1.37 knakahar { 377 1.37 knakahar struct l2tp_softc *sc; 378 1.37 knakahar struct ifnet *ifp; 379 1.37 knakahar struct ifqueue *ifq; 380 1.37 knakahar int s; 381 1.37 knakahar 382 1.37 knakahar KASSERT(psref_held(&var->lv_psref, lv_psref_class)); 383 1.37 knakahar 384 1.37 knakahar sc = var->lv_softc; 385 1.37 knakahar ifp = &sc->l2tp_ec.ec_if; 386 1.37 knakahar 387 1.37 knakahar s = splsoftnet(); 388 1.39 knakahar ifq = l2tp_ifq_percpu_getref(sc->l2tp_ifq_percpu); 389 1.37 knakahar if (IF_QFULL(ifq)) { 390 1.41 thorpej if_statinc(ifp, if_oerrors); 391 1.39 knakahar l2tp_ifq_percpu_putref(sc->l2tp_ifq_percpu); 392 1.37 knakahar splx(s); 393 1.37 knakahar m_freem(m); 394 1.37 knakahar return ENOBUFS; 395 1.37 knakahar } 396 1.37 knakahar 397 1.37 knakahar IF_ENQUEUE(ifq, m); 398 1.37 knakahar percpu_putref(sc->l2tp_ifq_percpu); 399 1.37 knakahar softint_schedule(sc->l2tp_si); 400 1.37 knakahar /* counter is incremented in l2tpintr() */ 401 1.37 knakahar splx(s); 402 1.37 knakahar return 0; 403 1.37 knakahar } 404 1.37 knakahar 405 1.37 knakahar static int 406 1.1 knakahar l2tp_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, 407 1.1 knakahar const struct rtentry *rt) 408 1.1 knakahar { 409 1.1 knakahar struct l2tp_softc *sc = container_of(ifp, struct l2tp_softc, 410 1.1 knakahar l2tp_ec.ec_if); 411 1.1 knakahar struct l2tp_variant *var; 412 1.1 knakahar struct psref psref; 413 1.1 knakahar int error = 0; 414 1.1 knakahar 415 1.1 knakahar var = l2tp_getref_variant(sc, &psref); 416 1.1 knakahar if (var == NULL) { 417 1.1 knakahar m_freem(m); 418 1.1 knakahar return ENETDOWN; 419 1.1 knakahar } 420 1.1 knakahar 421 1.1 knakahar IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family); 422 1.1 knakahar 423 1.1 knakahar m->m_flags &= ~(M_BCAST|M_MCAST); 424 1.1 knakahar 425 1.1 knakahar if ((ifp->if_flags & IFF_UP) == 0) { 426 1.1 knakahar m_freem(m); 427 1.1 knakahar error = ENETDOWN; 428 1.1 knakahar goto end; 429 1.1 knakahar } 430 1.1 knakahar 431 1.1 knakahar if (var->lv_psrc == NULL || var->lv_pdst == NULL) { 432 1.1 knakahar m_freem(m); 433 1.1 knakahar error = ENETDOWN; 434 1.1 knakahar goto end; 435 1.1 knakahar } 436 1.1 knakahar 437 1.1 knakahar /* XXX should we check if our outer source is legal? */ 438 1.1 knakahar 439 1.1 knakahar /* use DLT_NULL encapsulation here to pass inner af type */ 440 1.1 knakahar M_PREPEND(m, sizeof(int), M_DONTWAIT); 441 1.1 knakahar if (!m) { 442 1.1 knakahar error = ENOBUFS; 443 1.1 knakahar goto end; 444 1.1 knakahar } 445 1.1 knakahar *mtod(m, int *) = dst->sa_family; 446 1.1 knakahar 447 1.37 knakahar error = l2tp_tx_enqueue(var, m); 448 1.1 knakahar end: 449 1.1 knakahar l2tp_putref_variant(var, &psref); 450 1.1 knakahar if (error) 451 1.41 thorpej if_statinc(ifp, if_oerrors); 452 1.1 knakahar 453 1.1 knakahar return error; 454 1.1 knakahar } 455 1.1 knakahar 456 1.1 knakahar static void 457 1.37 knakahar l2tp_sendit(struct l2tp_variant *var, struct mbuf *m) 458 1.37 knakahar { 459 1.37 knakahar int len; 460 1.37 knakahar int error; 461 1.37 knakahar struct l2tp_softc *sc; 462 1.37 knakahar struct ifnet *ifp; 463 1.37 knakahar 464 1.37 knakahar KASSERT(psref_held(&var->lv_psref, lv_psref_class)); 465 1.37 knakahar 466 1.37 knakahar sc = var->lv_softc; 467 1.37 knakahar ifp = &sc->l2tp_ec.ec_if; 468 1.37 knakahar 469 1.37 knakahar len = m->m_pkthdr.len; 470 1.37 knakahar m->m_flags &= ~(M_BCAST|M_MCAST); 471 1.37 knakahar bpf_mtap(ifp, m, BPF_D_OUT); 472 1.37 knakahar 473 1.37 knakahar switch (var->lv_psrc->sa_family) { 474 1.37 knakahar #ifdef INET 475 1.37 knakahar case AF_INET: 476 1.37 knakahar error = in_l2tp_output(var, m); 477 1.37 knakahar break; 478 1.37 knakahar #endif 479 1.37 knakahar #ifdef INET6 480 1.37 knakahar case AF_INET6: 481 1.37 knakahar error = in6_l2tp_output(var, m); 482 1.37 knakahar break; 483 1.37 knakahar #endif 484 1.37 knakahar default: 485 1.37 knakahar m_freem(m); 486 1.37 knakahar error = ENETDOWN; 487 1.37 knakahar break; 488 1.37 knakahar } 489 1.37 knakahar if (error) { 490 1.41 thorpej if_statinc(ifp, if_oerrors); 491 1.37 knakahar } else { 492 1.41 thorpej if_statadd2(ifp, if_opackets, 1, if_obytes, len); 493 1.37 knakahar } 494 1.37 knakahar } 495 1.37 knakahar 496 1.37 knakahar static void 497 1.1 knakahar l2tpintr(struct l2tp_variant *var) 498 1.1 knakahar { 499 1.1 knakahar struct l2tp_softc *sc; 500 1.1 knakahar struct ifnet *ifp; 501 1.1 knakahar struct mbuf *m; 502 1.37 knakahar struct ifqueue *ifq; 503 1.37 knakahar u_int cpuid = cpu_index(curcpu()); 504 1.1 knakahar 505 1.1 knakahar KASSERT(psref_held(&var->lv_psref, lv_psref_class)); 506 1.1 knakahar 507 1.1 knakahar sc = var->lv_softc; 508 1.1 knakahar ifp = &sc->l2tp_ec.ec_if; 509 1.1 knakahar 510 1.1 knakahar /* output processing */ 511 1.1 knakahar if (var->lv_my_sess_id == 0 || var->lv_peer_sess_id == 0) { 512 1.39 knakahar ifq = l2tp_ifq_percpu_getref(sc->l2tp_ifq_percpu); 513 1.37 knakahar IF_PURGE(ifq); 514 1.39 knakahar l2tp_ifq_percpu_putref(sc->l2tp_ifq_percpu); 515 1.37 knakahar if (cpuid == 0) 516 1.37 knakahar IFQ_PURGE(&ifp->if_snd); 517 1.1 knakahar return; 518 1.1 knakahar } 519 1.1 knakahar 520 1.37 knakahar /* Currently, l2tpintr() is always called in softint context. */ 521 1.39 knakahar ifq = l2tp_ifq_percpu_getref(sc->l2tp_ifq_percpu); 522 1.1 knakahar for (;;) { 523 1.37 knakahar IF_DEQUEUE(ifq, m); 524 1.37 knakahar if (m != NULL) 525 1.37 knakahar l2tp_sendit(var, m); 526 1.37 knakahar else 527 1.1 knakahar break; 528 1.37 knakahar } 529 1.39 knakahar l2tp_ifq_percpu_putref(sc->l2tp_ifq_percpu); 530 1.1 knakahar 531 1.37 knakahar if (cpuid == 0) { 532 1.37 knakahar for (;;) { 533 1.37 knakahar IFQ_DEQUEUE(&ifp->if_snd, m); 534 1.37 knakahar if (m != NULL) 535 1.37 knakahar l2tp_sendit(var, m); 536 1.37 knakahar else 537 1.37 knakahar break; 538 1.1 knakahar } 539 1.1 knakahar } 540 1.1 knakahar } 541 1.1 knakahar 542 1.37 knakahar static void 543 1.37 knakahar l2tpintr_softint(void *arg) 544 1.37 knakahar { 545 1.37 knakahar struct l2tp_variant *var; 546 1.37 knakahar struct psref psref; 547 1.37 knakahar struct l2tp_softc *sc = arg; 548 1.37 knakahar 549 1.37 knakahar var = l2tp_getref_variant(sc, &psref); 550 1.37 knakahar if (var == NULL) 551 1.37 knakahar return; 552 1.37 knakahar 553 1.37 knakahar l2tpintr(var); 554 1.37 knakahar l2tp_putref_variant(var, &psref); 555 1.37 knakahar } 556 1.37 knakahar 557 1.1 knakahar void 558 1.1 knakahar l2tp_input(struct mbuf *m, struct ifnet *ifp) 559 1.1 knakahar { 560 1.21 knakahar vaddr_t addr; 561 1.1 knakahar 562 1.1 knakahar KASSERT(ifp != NULL); 563 1.1 knakahar 564 1.21 knakahar /* 565 1.21 knakahar * Currently, l2tp(4) supports only ethernet as inner protocol. 566 1.21 knakahar */ 567 1.21 knakahar if (m->m_pkthdr.len < sizeof(struct ether_header)) { 568 1.19 maxv m_freem(m); 569 1.19 maxv return; 570 1.19 maxv } 571 1.19 maxv 572 1.22 knakahar /* 573 1.22 knakahar * If the head of the payload is not aligned, align it. 574 1.22 knakahar */ 575 1.21 knakahar addr = mtod(m, vaddr_t); 576 1.23 knakahar if ((addr & 0x03) != 0x2) { 577 1.1 knakahar /* copy and align head of payload */ 578 1.1 knakahar struct mbuf *m_head; 579 1.1 knakahar int copy_length; 580 1.23 knakahar u_int pad = roundup(sizeof(struct ether_header), 4) 581 1.23 knakahar - sizeof(struct ether_header); 582 1.1 knakahar 583 1.1 knakahar #define L2TP_COPY_LENGTH 60 584 1.1 knakahar 585 1.1 knakahar if (m->m_pkthdr.len < L2TP_COPY_LENGTH) { 586 1.1 knakahar copy_length = m->m_pkthdr.len; 587 1.1 knakahar } else { 588 1.1 knakahar copy_length = L2TP_COPY_LENGTH; 589 1.1 knakahar } 590 1.1 knakahar 591 1.1 knakahar if (m->m_len < copy_length) { 592 1.1 knakahar m = m_pullup(m, copy_length); 593 1.1 knakahar if (m == NULL) 594 1.1 knakahar return; 595 1.1 knakahar } 596 1.1 knakahar 597 1.1 knakahar MGETHDR(m_head, M_DONTWAIT, MT_HEADER); 598 1.1 knakahar if (m_head == NULL) { 599 1.1 knakahar m_freem(m); 600 1.1 knakahar return; 601 1.1 knakahar } 602 1.31 maxv m_move_pkthdr(m_head, m); 603 1.1 knakahar 604 1.23 knakahar /* 605 1.23 knakahar * m_head should be: 606 1.23 knakahar * L2TP_COPY_LENGTH 607 1.23 knakahar * <- + roundup(pad, 4) - pad -> 608 1.23 knakahar * +-------+--------+-----+--------------+-------------+ 609 1.23 knakahar * | m_hdr | pkthdr | ... | ether header | payload | 610 1.23 knakahar * +-------+--------+-----+--------------+-------------+ 611 1.23 knakahar * ^ ^ 612 1.23 knakahar * m_data 4 byte aligned 613 1.23 knakahar */ 614 1.32 maxv m_align(m_head, L2TP_COPY_LENGTH + roundup(pad, 4)); 615 1.23 knakahar m_head->m_data += pad; 616 1.23 knakahar 617 1.18 maxv memcpy(mtod(m_head, void *), mtod(m, void *), copy_length); 618 1.1 knakahar m_head->m_len = copy_length; 619 1.1 knakahar m->m_data += copy_length; 620 1.1 knakahar m->m_len -= copy_length; 621 1.1 knakahar 622 1.1 knakahar /* construct chain */ 623 1.1 knakahar if (m->m_len == 0) { 624 1.18 maxv m_head->m_next = m_free(m); 625 1.1 knakahar } else { 626 1.1 knakahar m_head->m_next = m; 627 1.1 knakahar } 628 1.1 knakahar 629 1.1 knakahar /* override m */ 630 1.1 knakahar m = m_head; 631 1.1 knakahar } 632 1.1 knakahar 633 1.1 knakahar m_set_rcvif(m, ifp); 634 1.1 knakahar 635 1.1 knakahar /* 636 1.1 knakahar * bpf_mtap() and ifp->if_ipackets++ is done in if_input() 637 1.1 knakahar * 638 1.1 knakahar * obytes is incremented at ether_output() or bridge_enqueue(). 639 1.1 knakahar */ 640 1.1 knakahar if_percpuq_enqueue(ifp->if_percpuq, m); 641 1.1 knakahar } 642 1.1 knakahar 643 1.1 knakahar void 644 1.1 knakahar l2tp_start(struct ifnet *ifp) 645 1.1 knakahar { 646 1.1 knakahar struct psref psref; 647 1.1 knakahar struct l2tp_variant *var; 648 1.1 knakahar struct l2tp_softc *sc = container_of(ifp, struct l2tp_softc, 649 1.1 knakahar l2tp_ec.ec_if); 650 1.1 knakahar 651 1.1 knakahar var = l2tp_getref_variant(sc, &psref); 652 1.1 knakahar if (var == NULL) 653 1.1 knakahar return; 654 1.1 knakahar 655 1.1 knakahar if (var->lv_psrc == NULL || var->lv_pdst == NULL) 656 1.1 knakahar return; 657 1.1 knakahar 658 1.40 knakahar kpreempt_disable(); 659 1.37 knakahar softint_schedule(sc->l2tp_si); 660 1.40 knakahar kpreempt_enable(); 661 1.1 knakahar l2tp_putref_variant(var, &psref); 662 1.1 knakahar } 663 1.1 knakahar 664 1.1 knakahar int 665 1.1 knakahar l2tp_transmit(struct ifnet *ifp, struct mbuf *m) 666 1.1 knakahar { 667 1.1 knakahar int error; 668 1.1 knakahar struct psref psref; 669 1.1 knakahar struct l2tp_variant *var; 670 1.1 knakahar struct l2tp_softc *sc = container_of(ifp, struct l2tp_softc, 671 1.1 knakahar l2tp_ec.ec_if); 672 1.1 knakahar 673 1.1 knakahar var = l2tp_getref_variant(sc, &psref); 674 1.1 knakahar if (var == NULL) { 675 1.1 knakahar m_freem(m); 676 1.1 knakahar return ENETDOWN; 677 1.1 knakahar } 678 1.1 knakahar 679 1.1 knakahar if (var->lv_psrc == NULL || var->lv_pdst == NULL) { 680 1.1 knakahar m_freem(m); 681 1.1 knakahar error = ENETDOWN; 682 1.1 knakahar goto out; 683 1.1 knakahar } 684 1.1 knakahar 685 1.1 knakahar m->m_flags &= ~(M_BCAST|M_MCAST); 686 1.1 knakahar 687 1.37 knakahar error = l2tp_tx_enqueue(var, m); 688 1.1 knakahar out: 689 1.1 knakahar l2tp_putref_variant(var, &psref); 690 1.1 knakahar return error; 691 1.1 knakahar } 692 1.1 knakahar 693 1.1 knakahar /* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */ 694 1.1 knakahar int 695 1.1 knakahar l2tp_ioctl(struct ifnet *ifp, u_long cmd, void *data) 696 1.1 knakahar { 697 1.1 knakahar struct l2tp_softc *sc = container_of(ifp, struct l2tp_softc, 698 1.1 knakahar l2tp_ec.ec_if); 699 1.1 knakahar struct l2tp_variant *var, *var_tmp; 700 1.1 knakahar struct ifreq *ifr = data; 701 1.1 knakahar int error = 0, size; 702 1.1 knakahar struct sockaddr *dst, *src; 703 1.1 knakahar struct l2tp_req l2tpr; 704 1.1 knakahar u_long mtu; 705 1.1 knakahar int bound; 706 1.1 knakahar struct psref psref; 707 1.1 knakahar 708 1.1 knakahar switch (cmd) { 709 1.1 knakahar case SIOCSIFADDR: 710 1.1 knakahar ifp->if_flags |= IFF_UP; 711 1.1 knakahar break; 712 1.1 knakahar 713 1.1 knakahar case SIOCSIFDSTADDR: 714 1.1 knakahar break; 715 1.1 knakahar 716 1.1 knakahar case SIOCADDMULTI: 717 1.1 knakahar case SIOCDELMULTI: 718 1.1 knakahar switch (ifr->ifr_addr.sa_family) { 719 1.1 knakahar #ifdef INET 720 1.1 knakahar case AF_INET: /* IP supports Multicast */ 721 1.1 knakahar break; 722 1.1 knakahar #endif /* INET */ 723 1.1 knakahar #ifdef INET6 724 1.1 knakahar case AF_INET6: /* IP6 supports Multicast */ 725 1.1 knakahar break; 726 1.1 knakahar #endif /* INET6 */ 727 1.1 knakahar default: /* Other protocols doesn't support Multicast */ 728 1.1 knakahar error = EAFNOSUPPORT; 729 1.1 knakahar break; 730 1.1 knakahar } 731 1.1 knakahar break; 732 1.1 knakahar 733 1.1 knakahar case SIOCSIFMTU: 734 1.1 knakahar mtu = ifr->ifr_mtu; 735 1.1 knakahar if (mtu < L2TP_MTU_MIN || mtu > L2TP_MTU_MAX) 736 1.1 knakahar return (EINVAL); 737 1.1 knakahar ifp->if_mtu = mtu; 738 1.1 knakahar break; 739 1.1 knakahar 740 1.1 knakahar #ifdef INET 741 1.1 knakahar case SIOCSIFPHYADDR: 742 1.1 knakahar src = (struct sockaddr *) 743 1.1 knakahar &(((struct in_aliasreq *)data)->ifra_addr); 744 1.1 knakahar dst = (struct sockaddr *) 745 1.1 knakahar &(((struct in_aliasreq *)data)->ifra_dstaddr); 746 1.1 knakahar if (src->sa_family != AF_INET || dst->sa_family != AF_INET) 747 1.1 knakahar return EAFNOSUPPORT; 748 1.1 knakahar else if (src->sa_len != sizeof(struct sockaddr_in) 749 1.1 knakahar || dst->sa_len != sizeof(struct sockaddr_in)) 750 1.1 knakahar return EINVAL; 751 1.1 knakahar 752 1.1 knakahar error = l2tp_set_tunnel(&sc->l2tp_ec.ec_if, src, dst); 753 1.1 knakahar break; 754 1.1 knakahar 755 1.1 knakahar #endif /* INET */ 756 1.1 knakahar #ifdef INET6 757 1.1 knakahar case SIOCSIFPHYADDR_IN6: 758 1.1 knakahar src = (struct sockaddr *) 759 1.1 knakahar &(((struct in6_aliasreq *)data)->ifra_addr); 760 1.1 knakahar dst = (struct sockaddr *) 761 1.1 knakahar &(((struct in6_aliasreq *)data)->ifra_dstaddr); 762 1.1 knakahar if (src->sa_family != AF_INET6 || dst->sa_family != AF_INET6) 763 1.1 knakahar return EAFNOSUPPORT; 764 1.1 knakahar else if (src->sa_len != sizeof(struct sockaddr_in6) 765 1.1 knakahar || dst->sa_len != sizeof(struct sockaddr_in6)) 766 1.1 knakahar return EINVAL; 767 1.1 knakahar 768 1.1 knakahar error = l2tp_set_tunnel(&sc->l2tp_ec.ec_if, src, dst); 769 1.1 knakahar break; 770 1.1 knakahar 771 1.1 knakahar #endif /* INET6 */ 772 1.1 knakahar case SIOCSLIFPHYADDR: 773 1.1 knakahar src = (struct sockaddr *) 774 1.1 knakahar &(((struct if_laddrreq *)data)->addr); 775 1.1 knakahar dst = (struct sockaddr *) 776 1.1 knakahar &(((struct if_laddrreq *)data)->dstaddr); 777 1.1 knakahar if (src->sa_family != dst->sa_family) 778 1.1 knakahar return EINVAL; 779 1.1 knakahar else if (src->sa_family == AF_INET 780 1.1 knakahar && src->sa_len != sizeof(struct sockaddr_in)) 781 1.1 knakahar return EINVAL; 782 1.1 knakahar else if (src->sa_family == AF_INET6 783 1.1 knakahar && src->sa_len != sizeof(struct sockaddr_in6)) 784 1.1 knakahar return EINVAL; 785 1.1 knakahar else if (dst->sa_family == AF_INET 786 1.1 knakahar && dst->sa_len != sizeof(struct sockaddr_in)) 787 1.1 knakahar return EINVAL; 788 1.1 knakahar else if (dst->sa_family == AF_INET6 789 1.1 knakahar && dst->sa_len != sizeof(struct sockaddr_in6)) 790 1.1 knakahar return EINVAL; 791 1.1 knakahar 792 1.1 knakahar error = l2tp_set_tunnel(&sc->l2tp_ec.ec_if, src, dst); 793 1.1 knakahar break; 794 1.1 knakahar 795 1.1 knakahar case SIOCDIFPHYADDR: 796 1.1 knakahar l2tp_delete_tunnel(&sc->l2tp_ec.ec_if); 797 1.1 knakahar break; 798 1.1 knakahar 799 1.1 knakahar case SIOCGIFPSRCADDR: 800 1.1 knakahar #ifdef INET6 801 1.1 knakahar case SIOCGIFPSRCADDR_IN6: 802 1.1 knakahar #endif /* INET6 */ 803 1.1 knakahar bound = curlwp_bind(); 804 1.1 knakahar var = l2tp_getref_variant(sc, &psref); 805 1.1 knakahar if (var == NULL) { 806 1.1 knakahar curlwp_bindx(bound); 807 1.1 knakahar error = EADDRNOTAVAIL; 808 1.1 knakahar goto bad; 809 1.1 knakahar } 810 1.1 knakahar if (var->lv_psrc == NULL) { 811 1.1 knakahar l2tp_putref_variant(var, &psref); 812 1.1 knakahar curlwp_bindx(bound); 813 1.1 knakahar error = EADDRNOTAVAIL; 814 1.1 knakahar goto bad; 815 1.1 knakahar } 816 1.1 knakahar src = var->lv_psrc; 817 1.1 knakahar switch (cmd) { 818 1.1 knakahar #ifdef INET 819 1.1 knakahar case SIOCGIFPSRCADDR: 820 1.1 knakahar dst = &ifr->ifr_addr; 821 1.1 knakahar size = sizeof(ifr->ifr_addr); 822 1.1 knakahar break; 823 1.1 knakahar #endif /* INET */ 824 1.1 knakahar #ifdef INET6 825 1.1 knakahar case SIOCGIFPSRCADDR_IN6: 826 1.1 knakahar dst = (struct sockaddr *) 827 1.1 knakahar &(((struct in6_ifreq *)data)->ifr_addr); 828 1.1 knakahar size = sizeof(((struct in6_ifreq *)data)->ifr_addr); 829 1.1 knakahar break; 830 1.1 knakahar #endif /* INET6 */ 831 1.1 knakahar default: 832 1.1 knakahar l2tp_putref_variant(var, &psref); 833 1.1 knakahar curlwp_bindx(bound); 834 1.1 knakahar error = EADDRNOTAVAIL; 835 1.1 knakahar goto bad; 836 1.1 knakahar } 837 1.1 knakahar if (src->sa_len > size) { 838 1.1 knakahar l2tp_putref_variant(var, &psref); 839 1.1 knakahar curlwp_bindx(bound); 840 1.1 knakahar return EINVAL; 841 1.1 knakahar } 842 1.1 knakahar sockaddr_copy(dst, src->sa_len, src); 843 1.1 knakahar l2tp_putref_variant(var, &psref); 844 1.1 knakahar curlwp_bindx(bound); 845 1.1 knakahar break; 846 1.1 knakahar 847 1.1 knakahar case SIOCGIFPDSTADDR: 848 1.1 knakahar #ifdef INET6 849 1.1 knakahar case SIOCGIFPDSTADDR_IN6: 850 1.1 knakahar #endif /* INET6 */ 851 1.1 knakahar bound = curlwp_bind(); 852 1.1 knakahar var = l2tp_getref_variant(sc, &psref); 853 1.1 knakahar if (var == NULL) { 854 1.1 knakahar curlwp_bindx(bound); 855 1.1 knakahar error = EADDRNOTAVAIL; 856 1.1 knakahar goto bad; 857 1.1 knakahar } 858 1.1 knakahar if (var->lv_pdst == NULL) { 859 1.1 knakahar l2tp_putref_variant(var, &psref); 860 1.1 knakahar curlwp_bindx(bound); 861 1.1 knakahar error = EADDRNOTAVAIL; 862 1.1 knakahar goto bad; 863 1.1 knakahar } 864 1.1 knakahar src = var->lv_pdst; 865 1.1 knakahar switch (cmd) { 866 1.1 knakahar #ifdef INET 867 1.1 knakahar case SIOCGIFPDSTADDR: 868 1.1 knakahar dst = &ifr->ifr_addr; 869 1.1 knakahar size = sizeof(ifr->ifr_addr); 870 1.1 knakahar break; 871 1.1 knakahar #endif /* INET */ 872 1.1 knakahar #ifdef INET6 873 1.1 knakahar case SIOCGIFPDSTADDR_IN6: 874 1.1 knakahar dst = (struct sockaddr *) 875 1.1 knakahar &(((struct in6_ifreq *)data)->ifr_addr); 876 1.1 knakahar size = sizeof(((struct in6_ifreq *)data)->ifr_addr); 877 1.1 knakahar break; 878 1.1 knakahar #endif /* INET6 */ 879 1.1 knakahar default: 880 1.1 knakahar l2tp_putref_variant(var, &psref); 881 1.1 knakahar curlwp_bindx(bound); 882 1.1 knakahar error = EADDRNOTAVAIL; 883 1.1 knakahar goto bad; 884 1.1 knakahar } 885 1.1 knakahar if (src->sa_len > size) { 886 1.1 knakahar l2tp_putref_variant(var, &psref); 887 1.1 knakahar curlwp_bindx(bound); 888 1.1 knakahar return EINVAL; 889 1.1 knakahar } 890 1.1 knakahar sockaddr_copy(dst, src->sa_len, src); 891 1.1 knakahar l2tp_putref_variant(var, &psref); 892 1.1 knakahar curlwp_bindx(bound); 893 1.1 knakahar break; 894 1.1 knakahar 895 1.1 knakahar case SIOCGLIFPHYADDR: 896 1.1 knakahar bound = curlwp_bind(); 897 1.1 knakahar var = l2tp_getref_variant(sc, &psref); 898 1.1 knakahar if (var == NULL) { 899 1.1 knakahar curlwp_bindx(bound); 900 1.1 knakahar error = EADDRNOTAVAIL; 901 1.1 knakahar goto bad; 902 1.1 knakahar } 903 1.1 knakahar if (var->lv_psrc == NULL || var->lv_pdst == NULL) { 904 1.1 knakahar l2tp_putref_variant(var, &psref); 905 1.1 knakahar curlwp_bindx(bound); 906 1.1 knakahar error = EADDRNOTAVAIL; 907 1.1 knakahar goto bad; 908 1.1 knakahar } 909 1.1 knakahar 910 1.1 knakahar /* copy src */ 911 1.1 knakahar src = var->lv_psrc; 912 1.1 knakahar dst = (struct sockaddr *) 913 1.1 knakahar &(((struct if_laddrreq *)data)->addr); 914 1.1 knakahar size = sizeof(((struct if_laddrreq *)data)->addr); 915 1.1 knakahar if (src->sa_len > size) { 916 1.1 knakahar l2tp_putref_variant(var, &psref); 917 1.1 knakahar curlwp_bindx(bound); 918 1.1 knakahar return EINVAL; 919 1.1 knakahar } 920 1.1 knakahar sockaddr_copy(dst, src->sa_len, src); 921 1.1 knakahar 922 1.1 knakahar /* copy dst */ 923 1.1 knakahar src = var->lv_pdst; 924 1.1 knakahar dst = (struct sockaddr *) 925 1.1 knakahar &(((struct if_laddrreq *)data)->dstaddr); 926 1.1 knakahar size = sizeof(((struct if_laddrreq *)data)->dstaddr); 927 1.1 knakahar if (src->sa_len > size) { 928 1.1 knakahar l2tp_putref_variant(var, &psref); 929 1.1 knakahar curlwp_bindx(bound); 930 1.1 knakahar return EINVAL; 931 1.1 knakahar } 932 1.1 knakahar sockaddr_copy(dst, src->sa_len, src); 933 1.1 knakahar l2tp_putref_variant(var, &psref); 934 1.1 knakahar curlwp_bindx(bound); 935 1.1 knakahar break; 936 1.1 knakahar 937 1.1 knakahar case SIOCSL2TPSESSION: 938 1.1 knakahar if ((error = copyin(ifr->ifr_data, &l2tpr, sizeof(l2tpr))) != 0) 939 1.1 knakahar break; 940 1.1 knakahar 941 1.1 knakahar /* session id must not zero */ 942 1.1 knakahar if (l2tpr.my_sess_id == 0 || l2tpr.peer_sess_id == 0) 943 1.1 knakahar return EINVAL; 944 1.1 knakahar 945 1.1 knakahar bound = curlwp_bind(); 946 1.1 knakahar var_tmp = l2tp_lookup_session_ref(l2tpr.my_sess_id, &psref); 947 1.1 knakahar if (var_tmp != NULL) { 948 1.1 knakahar /* duplicate session id */ 949 1.1 knakahar log(LOG_WARNING, "%s: duplicate session id %" PRIu32 " of %s\n", 950 1.1 knakahar sc->l2tp_ec.ec_if.if_xname, l2tpr.my_sess_id, 951 1.1 knakahar var_tmp->lv_softc->l2tp_ec.ec_if.if_xname); 952 1.1 knakahar psref_release(&psref, &var_tmp->lv_psref, 953 1.1 knakahar lv_psref_class); 954 1.1 knakahar curlwp_bindx(bound); 955 1.1 knakahar return EINVAL; 956 1.1 knakahar } 957 1.1 knakahar curlwp_bindx(bound); 958 1.1 knakahar 959 1.1 knakahar error = l2tp_set_session(sc, l2tpr.my_sess_id, l2tpr.peer_sess_id); 960 1.1 knakahar break; 961 1.1 knakahar case SIOCDL2TPSESSION: 962 1.1 knakahar l2tp_clear_session(sc); 963 1.1 knakahar break; 964 1.1 knakahar case SIOCSL2TPCOOKIE: 965 1.1 knakahar if ((error = copyin(ifr->ifr_data, &l2tpr, sizeof(l2tpr))) != 0) 966 1.1 knakahar break; 967 1.1 knakahar 968 1.1 knakahar error = l2tp_set_cookie(sc, l2tpr.my_cookie, l2tpr.my_cookie_len, 969 1.1 knakahar l2tpr.peer_cookie, l2tpr.peer_cookie_len); 970 1.1 knakahar break; 971 1.1 knakahar case SIOCDL2TPCOOKIE: 972 1.1 knakahar l2tp_clear_cookie(sc); 973 1.1 knakahar break; 974 1.1 knakahar case SIOCSL2TPSTATE: 975 1.1 knakahar if ((error = copyin(ifr->ifr_data, &l2tpr, sizeof(l2tpr))) != 0) 976 1.1 knakahar break; 977 1.1 knakahar 978 1.1 knakahar l2tp_set_state(sc, l2tpr.state); 979 1.1 knakahar break; 980 1.1 knakahar case SIOCGL2TP: 981 1.1 knakahar /* get L2TPV3 session info */ 982 1.1 knakahar memset(&l2tpr, 0, sizeof(l2tpr)); 983 1.1 knakahar 984 1.1 knakahar bound = curlwp_bind(); 985 1.1 knakahar var = l2tp_getref_variant(sc, &psref); 986 1.1 knakahar if (var == NULL) { 987 1.1 knakahar curlwp_bindx(bound); 988 1.1 knakahar error = EADDRNOTAVAIL; 989 1.1 knakahar goto bad; 990 1.1 knakahar } 991 1.1 knakahar 992 1.1 knakahar l2tpr.state = var->lv_state; 993 1.1 knakahar l2tpr.my_sess_id = var->lv_my_sess_id; 994 1.1 knakahar l2tpr.peer_sess_id = var->lv_peer_sess_id; 995 1.1 knakahar l2tpr.my_cookie = var->lv_my_cookie; 996 1.1 knakahar l2tpr.my_cookie_len = var->lv_my_cookie_len; 997 1.1 knakahar l2tpr.peer_cookie = var->lv_peer_cookie; 998 1.1 knakahar l2tpr.peer_cookie_len = var->lv_peer_cookie_len; 999 1.1 knakahar l2tp_putref_variant(var, &psref); 1000 1.1 knakahar curlwp_bindx(bound); 1001 1.1 knakahar 1002 1.1 knakahar error = copyout(&l2tpr, ifr->ifr_data, sizeof(l2tpr)); 1003 1.1 knakahar break; 1004 1.1 knakahar 1005 1.1 knakahar default: 1006 1.1 knakahar error = ifioctl_common(ifp, cmd, data); 1007 1.1 knakahar break; 1008 1.1 knakahar } 1009 1.1 knakahar bad: 1010 1.1 knakahar return error; 1011 1.1 knakahar } 1012 1.1 knakahar 1013 1.1 knakahar static int 1014 1.1 knakahar l2tp_set_tunnel(struct ifnet *ifp, struct sockaddr *src, struct sockaddr *dst) 1015 1.1 knakahar { 1016 1.1 knakahar struct l2tp_softc *sc = container_of(ifp, struct l2tp_softc, 1017 1.1 knakahar l2tp_ec.ec_if); 1018 1.1 knakahar struct sockaddr *osrc, *odst; 1019 1.1 knakahar struct sockaddr *nsrc, *ndst; 1020 1.1 knakahar struct l2tp_variant *ovar, *nvar; 1021 1.1 knakahar int error; 1022 1.1 knakahar 1023 1.1 knakahar nsrc = sockaddr_dup(src, M_WAITOK); 1024 1.1 knakahar ndst = sockaddr_dup(dst, M_WAITOK); 1025 1.1 knakahar 1026 1.1 knakahar nvar = kmem_alloc(sizeof(*nvar), KM_SLEEP); 1027 1.1 knakahar 1028 1.1 knakahar error = encap_lock_enter(); 1029 1.1 knakahar if (error) 1030 1.1 knakahar goto error; 1031 1.1 knakahar 1032 1.1 knakahar mutex_enter(&sc->l2tp_lock); 1033 1.1 knakahar 1034 1.1 knakahar ovar = sc->l2tp_var; 1035 1.1 knakahar osrc = ovar->lv_psrc; 1036 1.1 knakahar odst = ovar->lv_pdst; 1037 1.1 knakahar *nvar = *ovar; 1038 1.1 knakahar psref_target_init(&nvar->lv_psref, lv_psref_class); 1039 1.1 knakahar nvar->lv_psrc = nsrc; 1040 1.1 knakahar nvar->lv_pdst = ndst; 1041 1.1 knakahar error = l2tp_encap_attach(nvar); 1042 1.1 knakahar if (error) { 1043 1.1 knakahar mutex_exit(&sc->l2tp_lock); 1044 1.1 knakahar encap_lock_exit(); 1045 1.1 knakahar goto error; 1046 1.1 knakahar } 1047 1.1 knakahar l2tp_variant_update(sc, nvar); 1048 1.1 knakahar 1049 1.1 knakahar mutex_exit(&sc->l2tp_lock); 1050 1.1 knakahar 1051 1.1 knakahar (void)l2tp_encap_detach(ovar); 1052 1.1 knakahar encap_lock_exit(); 1053 1.1 knakahar 1054 1.1 knakahar if (osrc) 1055 1.1 knakahar sockaddr_free(osrc); 1056 1.1 knakahar if (odst) 1057 1.1 knakahar sockaddr_free(odst); 1058 1.1 knakahar kmem_free(ovar, sizeof(*ovar)); 1059 1.1 knakahar return 0; 1060 1.1 knakahar 1061 1.1 knakahar error: 1062 1.1 knakahar sockaddr_free(nsrc); 1063 1.1 knakahar sockaddr_free(ndst); 1064 1.1 knakahar kmem_free(nvar, sizeof(*nvar)); 1065 1.1 knakahar 1066 1.1 knakahar return error; 1067 1.1 knakahar } 1068 1.1 knakahar 1069 1.1 knakahar static void 1070 1.1 knakahar l2tp_delete_tunnel(struct ifnet *ifp) 1071 1.1 knakahar { 1072 1.1 knakahar struct l2tp_softc *sc = container_of(ifp, struct l2tp_softc, 1073 1.1 knakahar l2tp_ec.ec_if); 1074 1.1 knakahar struct sockaddr *osrc, *odst; 1075 1.1 knakahar struct l2tp_variant *ovar, *nvar; 1076 1.1 knakahar int error; 1077 1.1 knakahar 1078 1.1 knakahar nvar = kmem_alloc(sizeof(*nvar), KM_SLEEP); 1079 1.1 knakahar 1080 1.1 knakahar error = encap_lock_enter(); 1081 1.1 knakahar if (error) { 1082 1.1 knakahar kmem_free(nvar, sizeof(*nvar)); 1083 1.1 knakahar return; 1084 1.1 knakahar } 1085 1.1 knakahar mutex_enter(&sc->l2tp_lock); 1086 1.1 knakahar 1087 1.1 knakahar ovar = sc->l2tp_var; 1088 1.1 knakahar osrc = ovar->lv_psrc; 1089 1.1 knakahar odst = ovar->lv_pdst; 1090 1.1 knakahar *nvar = *ovar; 1091 1.1 knakahar psref_target_init(&nvar->lv_psref, lv_psref_class); 1092 1.1 knakahar nvar->lv_psrc = NULL; 1093 1.1 knakahar nvar->lv_pdst = NULL; 1094 1.1 knakahar l2tp_variant_update(sc, nvar); 1095 1.1 knakahar 1096 1.1 knakahar mutex_exit(&sc->l2tp_lock); 1097 1.1 knakahar 1098 1.1 knakahar (void)l2tp_encap_detach(ovar); 1099 1.1 knakahar encap_lock_exit(); 1100 1.1 knakahar 1101 1.1 knakahar if (osrc) 1102 1.1 knakahar sockaddr_free(osrc); 1103 1.1 knakahar if (odst) 1104 1.1 knakahar sockaddr_free(odst); 1105 1.1 knakahar kmem_free(ovar, sizeof(*ovar)); 1106 1.1 knakahar } 1107 1.1 knakahar 1108 1.2 knakahar static int 1109 1.9 knakahar id_hash_func(uint32_t id, u_long mask) 1110 1.1 knakahar { 1111 1.1 knakahar uint32_t hash; 1112 1.1 knakahar 1113 1.1 knakahar hash = (id >> 16) ^ id; 1114 1.1 knakahar hash = (hash >> 4) ^ hash; 1115 1.1 knakahar 1116 1.9 knakahar return hash & mask; 1117 1.1 knakahar } 1118 1.1 knakahar 1119 1.1 knakahar static void 1120 1.1 knakahar l2tp_hash_init(void) 1121 1.1 knakahar { 1122 1.1 knakahar 1123 1.1 knakahar l2tp_hash.lists = hashinit(L2TP_ID_HASH_SIZE, HASH_PSLIST, true, 1124 1.9 knakahar &l2tp_hash.mask); 1125 1.1 knakahar } 1126 1.1 knakahar 1127 1.1 knakahar static int 1128 1.1 knakahar l2tp_hash_fini(void) 1129 1.1 knakahar { 1130 1.1 knakahar int i; 1131 1.1 knakahar 1132 1.1 knakahar mutex_enter(&l2tp_hash.lock); 1133 1.1 knakahar 1134 1.9 knakahar for (i = 0; i < l2tp_hash.mask + 1; i++) { 1135 1.1 knakahar if (PSLIST_WRITER_FIRST(&l2tp_hash.lists[i], struct l2tp_softc, 1136 1.1 knakahar l2tp_hash) != NULL) { 1137 1.1 knakahar mutex_exit(&l2tp_hash.lock); 1138 1.1 knakahar return EBUSY; 1139 1.1 knakahar } 1140 1.1 knakahar } 1141 1.9 knakahar for (i = 0; i < l2tp_hash.mask + 1; i++) 1142 1.1 knakahar PSLIST_DESTROY(&l2tp_hash.lists[i]); 1143 1.1 knakahar 1144 1.1 knakahar mutex_exit(&l2tp_hash.lock); 1145 1.1 knakahar 1146 1.9 knakahar hashdone(l2tp_hash.lists, HASH_PSLIST, l2tp_hash.mask); 1147 1.1 knakahar 1148 1.1 knakahar return 0; 1149 1.1 knakahar } 1150 1.1 knakahar 1151 1.1 knakahar static int 1152 1.1 knakahar l2tp_set_session(struct l2tp_softc *sc, uint32_t my_sess_id, 1153 1.1 knakahar uint32_t peer_sess_id) 1154 1.1 knakahar { 1155 1.1 knakahar uint32_t idx; 1156 1.1 knakahar struct l2tp_variant *nvar; 1157 1.1 knakahar struct l2tp_variant *ovar; 1158 1.1 knakahar struct ifnet *ifp = &sc->l2tp_ec.ec_if; 1159 1.1 knakahar 1160 1.1 knakahar nvar = kmem_alloc(sizeof(*nvar), KM_SLEEP); 1161 1.1 knakahar 1162 1.1 knakahar mutex_enter(&sc->l2tp_lock); 1163 1.1 knakahar ovar = sc->l2tp_var; 1164 1.1 knakahar *nvar = *ovar; 1165 1.1 knakahar psref_target_init(&nvar->lv_psref, lv_psref_class); 1166 1.1 knakahar nvar->lv_my_sess_id = my_sess_id; 1167 1.1 knakahar nvar->lv_peer_sess_id = peer_sess_id; 1168 1.1 knakahar 1169 1.1 knakahar mutex_enter(&l2tp_hash.lock); 1170 1.1 knakahar if (ovar->lv_my_sess_id > 0 && ovar->lv_peer_sess_id > 0) { 1171 1.1 knakahar PSLIST_WRITER_REMOVE(sc, l2tp_hash); 1172 1.1 knakahar pserialize_perform(l2tp_psz); 1173 1.1 knakahar } 1174 1.1 knakahar mutex_exit(&l2tp_hash.lock); 1175 1.12 knakahar PSLIST_ENTRY_DESTROY(sc, l2tp_hash); 1176 1.1 knakahar 1177 1.1 knakahar l2tp_variant_update(sc, nvar); 1178 1.1 knakahar mutex_exit(&sc->l2tp_lock); 1179 1.1 knakahar 1180 1.9 knakahar idx = id_hash_func(nvar->lv_my_sess_id, l2tp_hash.mask); 1181 1.1 knakahar if ((ifp->if_flags & IFF_DEBUG) != 0) 1182 1.1 knakahar log(LOG_DEBUG, "%s: add hash entry: sess_id=%" PRIu32 ", idx=%" PRIu32 "\n", 1183 1.1 knakahar sc->l2tp_ec.ec_if.if_xname, nvar->lv_my_sess_id, idx); 1184 1.1 knakahar 1185 1.12 knakahar PSLIST_ENTRY_INIT(sc, l2tp_hash); 1186 1.1 knakahar mutex_enter(&l2tp_hash.lock); 1187 1.1 knakahar PSLIST_WRITER_INSERT_HEAD(&l2tp_hash.lists[idx], sc, l2tp_hash); 1188 1.1 knakahar mutex_exit(&l2tp_hash.lock); 1189 1.1 knakahar 1190 1.1 knakahar kmem_free(ovar, sizeof(*ovar)); 1191 1.1 knakahar return 0; 1192 1.1 knakahar } 1193 1.1 knakahar 1194 1.1 knakahar static int 1195 1.1 knakahar l2tp_clear_session(struct l2tp_softc *sc) 1196 1.1 knakahar { 1197 1.1 knakahar struct l2tp_variant *nvar; 1198 1.1 knakahar struct l2tp_variant *ovar; 1199 1.1 knakahar 1200 1.1 knakahar nvar = kmem_alloc(sizeof(*nvar), KM_SLEEP); 1201 1.1 knakahar 1202 1.1 knakahar mutex_enter(&sc->l2tp_lock); 1203 1.1 knakahar ovar = sc->l2tp_var; 1204 1.1 knakahar *nvar = *ovar; 1205 1.1 knakahar psref_target_init(&nvar->lv_psref, lv_psref_class); 1206 1.1 knakahar nvar->lv_my_sess_id = 0; 1207 1.1 knakahar nvar->lv_peer_sess_id = 0; 1208 1.1 knakahar 1209 1.1 knakahar mutex_enter(&l2tp_hash.lock); 1210 1.1 knakahar if (ovar->lv_my_sess_id > 0 && ovar->lv_peer_sess_id > 0) { 1211 1.1 knakahar PSLIST_WRITER_REMOVE(sc, l2tp_hash); 1212 1.1 knakahar pserialize_perform(l2tp_psz); 1213 1.1 knakahar } 1214 1.1 knakahar mutex_exit(&l2tp_hash.lock); 1215 1.1 knakahar 1216 1.1 knakahar l2tp_variant_update(sc, nvar); 1217 1.1 knakahar mutex_exit(&sc->l2tp_lock); 1218 1.1 knakahar kmem_free(ovar, sizeof(*ovar)); 1219 1.1 knakahar return 0; 1220 1.1 knakahar } 1221 1.1 knakahar 1222 1.1 knakahar struct l2tp_variant * 1223 1.1 knakahar l2tp_lookup_session_ref(uint32_t id, struct psref *psref) 1224 1.1 knakahar { 1225 1.1 knakahar int idx; 1226 1.1 knakahar int s; 1227 1.1 knakahar struct l2tp_softc *sc; 1228 1.1 knakahar 1229 1.9 knakahar idx = id_hash_func(id, l2tp_hash.mask); 1230 1.1 knakahar 1231 1.1 knakahar s = pserialize_read_enter(); 1232 1.1 knakahar PSLIST_READER_FOREACH(sc, &l2tp_hash.lists[idx], struct l2tp_softc, 1233 1.1 knakahar l2tp_hash) { 1234 1.42 riastrad struct l2tp_variant *var = atomic_load_consume(&sc->l2tp_var); 1235 1.1 knakahar if (var == NULL) 1236 1.1 knakahar continue; 1237 1.1 knakahar if (var->lv_my_sess_id != id) 1238 1.1 knakahar continue; 1239 1.1 knakahar psref_acquire(psref, &var->lv_psref, lv_psref_class); 1240 1.1 knakahar pserialize_read_exit(s); 1241 1.1 knakahar return var; 1242 1.1 knakahar } 1243 1.1 knakahar pserialize_read_exit(s); 1244 1.1 knakahar return NULL; 1245 1.1 knakahar } 1246 1.1 knakahar 1247 1.1 knakahar /* 1248 1.1 knakahar * l2tp_variant update API. 1249 1.1 knakahar * 1250 1.1 knakahar * Assumption: 1251 1.1 knakahar * reader side dereferences sc->l2tp_var in reader critical section only, 1252 1.1 knakahar * that is, all of reader sides do not reader the sc->l2tp_var after 1253 1.1 knakahar * pserialize_perform(). 1254 1.1 knakahar */ 1255 1.1 knakahar static void 1256 1.1 knakahar l2tp_variant_update(struct l2tp_softc *sc, struct l2tp_variant *nvar) 1257 1.1 knakahar { 1258 1.1 knakahar struct ifnet *ifp = &sc->l2tp_ec.ec_if; 1259 1.1 knakahar struct l2tp_variant *ovar = sc->l2tp_var; 1260 1.1 knakahar 1261 1.1 knakahar KASSERT(mutex_owned(&sc->l2tp_lock)); 1262 1.1 knakahar 1263 1.42 riastrad atomic_store_release(&sc->l2tp_var, nvar); 1264 1.30 knakahar pserialize_perform(sc->l2tp_psz); 1265 1.1 knakahar psref_target_destroy(&ovar->lv_psref, lv_psref_class); 1266 1.1 knakahar 1267 1.42 riastrad if (nvar != NULL) { 1268 1.42 riastrad if (nvar->lv_psrc != NULL && nvar->lv_pdst != NULL) 1269 1.5 knakahar ifp->if_flags |= IFF_RUNNING; 1270 1.5 knakahar else 1271 1.5 knakahar ifp->if_flags &= ~IFF_RUNNING; 1272 1.5 knakahar } 1273 1.1 knakahar } 1274 1.1 knakahar 1275 1.1 knakahar static int 1276 1.1 knakahar l2tp_set_cookie(struct l2tp_softc *sc, uint64_t my_cookie, u_int my_cookie_len, 1277 1.1 knakahar uint64_t peer_cookie, u_int peer_cookie_len) 1278 1.1 knakahar { 1279 1.1 knakahar struct l2tp_variant *nvar; 1280 1.1 knakahar 1281 1.1 knakahar if (my_cookie == 0 || peer_cookie == 0) 1282 1.1 knakahar return EINVAL; 1283 1.1 knakahar 1284 1.1 knakahar if (my_cookie_len != 4 && my_cookie_len != 8 1285 1.1 knakahar && peer_cookie_len != 4 && peer_cookie_len != 8) 1286 1.1 knakahar return EINVAL; 1287 1.1 knakahar 1288 1.1 knakahar nvar = kmem_alloc(sizeof(*nvar), KM_SLEEP); 1289 1.1 knakahar 1290 1.1 knakahar mutex_enter(&sc->l2tp_lock); 1291 1.1 knakahar 1292 1.1 knakahar *nvar = *sc->l2tp_var; 1293 1.1 knakahar psref_target_init(&nvar->lv_psref, lv_psref_class); 1294 1.1 knakahar nvar->lv_my_cookie = my_cookie; 1295 1.1 knakahar nvar->lv_my_cookie_len = my_cookie_len; 1296 1.1 knakahar nvar->lv_peer_cookie = peer_cookie; 1297 1.1 knakahar nvar->lv_peer_cookie_len = peer_cookie_len; 1298 1.1 knakahar nvar->lv_use_cookie = L2TP_COOKIE_ON; 1299 1.1 knakahar l2tp_variant_update(sc, nvar); 1300 1.1 knakahar 1301 1.1 knakahar mutex_exit(&sc->l2tp_lock); 1302 1.1 knakahar 1303 1.1 knakahar struct ifnet *ifp = &sc->l2tp_ec.ec_if; 1304 1.1 knakahar if ((ifp->if_flags & IFF_DEBUG) != 0) { 1305 1.1 knakahar log(LOG_DEBUG, 1306 1.1 knakahar "%s: set cookie: " 1307 1.1 knakahar "local cookie_len=%u local cookie=%" PRIu64 ", " 1308 1.1 knakahar "remote cookie_len=%u remote cookie=%" PRIu64 "\n", 1309 1.1 knakahar ifp->if_xname, my_cookie_len, my_cookie, 1310 1.1 knakahar peer_cookie_len, peer_cookie); 1311 1.1 knakahar } 1312 1.1 knakahar 1313 1.1 knakahar return 0; 1314 1.1 knakahar } 1315 1.1 knakahar 1316 1.1 knakahar static void 1317 1.1 knakahar l2tp_clear_cookie(struct l2tp_softc *sc) 1318 1.1 knakahar { 1319 1.1 knakahar struct l2tp_variant *nvar; 1320 1.1 knakahar 1321 1.1 knakahar nvar = kmem_alloc(sizeof(*nvar), KM_SLEEP); 1322 1.1 knakahar 1323 1.1 knakahar mutex_enter(&sc->l2tp_lock); 1324 1.1 knakahar 1325 1.1 knakahar *nvar = *sc->l2tp_var; 1326 1.1 knakahar psref_target_init(&nvar->lv_psref, lv_psref_class); 1327 1.1 knakahar nvar->lv_my_cookie = 0; 1328 1.1 knakahar nvar->lv_my_cookie_len = 0; 1329 1.1 knakahar nvar->lv_peer_cookie = 0; 1330 1.1 knakahar nvar->lv_peer_cookie_len = 0; 1331 1.1 knakahar nvar->lv_use_cookie = L2TP_COOKIE_OFF; 1332 1.1 knakahar l2tp_variant_update(sc, nvar); 1333 1.1 knakahar 1334 1.1 knakahar mutex_exit(&sc->l2tp_lock); 1335 1.1 knakahar } 1336 1.1 knakahar 1337 1.1 knakahar static void 1338 1.1 knakahar l2tp_set_state(struct l2tp_softc *sc, int state) 1339 1.1 knakahar { 1340 1.1 knakahar struct ifnet *ifp = &sc->l2tp_ec.ec_if; 1341 1.1 knakahar struct l2tp_variant *nvar; 1342 1.46 roy int ostate; 1343 1.1 knakahar 1344 1.1 knakahar nvar = kmem_alloc(sizeof(*nvar), KM_SLEEP); 1345 1.1 knakahar 1346 1.1 knakahar mutex_enter(&sc->l2tp_lock); 1347 1.1 knakahar 1348 1.1 knakahar *nvar = *sc->l2tp_var; 1349 1.1 knakahar psref_target_init(&nvar->lv_psref, lv_psref_class); 1350 1.46 roy ostate = nvar->lv_state; 1351 1.1 knakahar nvar->lv_state = state; 1352 1.1 knakahar l2tp_variant_update(sc, nvar); 1353 1.46 roy mutex_exit(&sc->l2tp_lock); 1354 1.46 roy 1355 1.46 roy if (ostate != state) { 1356 1.46 roy int lstate; 1357 1.46 roy 1358 1.46 roy if (state == L2TP_STATE_UP) 1359 1.46 roy lstate = LINK_STATE_UP; 1360 1.46 roy else 1361 1.46 roy lstate = LINK_STATE_DOWN; 1362 1.1 knakahar 1363 1.46 roy if_link_state_change(ifp, lstate); 1364 1.1 knakahar } 1365 1.1 knakahar 1366 1.1 knakahar #ifdef NOTYET 1367 1.1 knakahar vlan_linkstate_notify(ifp, ifp->if_link_state); 1368 1.1 knakahar #endif 1369 1.1 knakahar } 1370 1.1 knakahar 1371 1.1 knakahar static int 1372 1.1 knakahar l2tp_encap_attach(struct l2tp_variant *var) 1373 1.1 knakahar { 1374 1.1 knakahar int error; 1375 1.1 knakahar 1376 1.1 knakahar if (var == NULL || var->lv_psrc == NULL) 1377 1.1 knakahar return EINVAL; 1378 1.1 knakahar 1379 1.1 knakahar switch (var->lv_psrc->sa_family) { 1380 1.1 knakahar #ifdef INET 1381 1.1 knakahar case AF_INET: 1382 1.1 knakahar error = in_l2tp_attach(var); 1383 1.1 knakahar break; 1384 1.1 knakahar #endif 1385 1.1 knakahar #ifdef INET6 1386 1.1 knakahar case AF_INET6: 1387 1.1 knakahar error = in6_l2tp_attach(var); 1388 1.1 knakahar break; 1389 1.1 knakahar #endif 1390 1.1 knakahar default: 1391 1.1 knakahar error = EINVAL; 1392 1.1 knakahar break; 1393 1.1 knakahar } 1394 1.1 knakahar 1395 1.1 knakahar return error; 1396 1.1 knakahar } 1397 1.1 knakahar 1398 1.1 knakahar static int 1399 1.1 knakahar l2tp_encap_detach(struct l2tp_variant *var) 1400 1.1 knakahar { 1401 1.1 knakahar int error; 1402 1.1 knakahar 1403 1.1 knakahar if (var == NULL || var->lv_psrc == NULL) 1404 1.1 knakahar return EINVAL; 1405 1.1 knakahar 1406 1.1 knakahar switch (var->lv_psrc->sa_family) { 1407 1.1 knakahar #ifdef INET 1408 1.1 knakahar case AF_INET: 1409 1.1 knakahar error = in_l2tp_detach(var); 1410 1.1 knakahar break; 1411 1.1 knakahar #endif 1412 1.1 knakahar #ifdef INET6 1413 1.1 knakahar case AF_INET6: 1414 1.1 knakahar error = in6_l2tp_detach(var); 1415 1.1 knakahar break; 1416 1.1 knakahar #endif 1417 1.1 knakahar default: 1418 1.1 knakahar error = EINVAL; 1419 1.1 knakahar break; 1420 1.1 knakahar } 1421 1.1 knakahar 1422 1.1 knakahar return error; 1423 1.1 knakahar } 1424 1.1 knakahar 1425 1.1 knakahar int 1426 1.1 knakahar l2tp_check_nesting(struct ifnet *ifp, struct mbuf *m) 1427 1.1 knakahar { 1428 1.1 knakahar 1429 1.16 knakahar return if_tunnel_check_nesting(ifp, m, max_l2tp_nesting); 1430 1.1 knakahar } 1431 1.1 knakahar 1432 1.1 knakahar /* 1433 1.1 knakahar * Module infrastructure 1434 1.1 knakahar */ 1435 1.1 knakahar #include "if_module.h" 1436 1.1 knakahar 1437 1.34 pgoyette IF_MODULE(MODULE_CLASS_DRIVER, l2tp, NULL) 1438 1.1 knakahar 1439 1.1 knakahar 1440 1.1 knakahar /* TODO: IP_TCPMSS support */ 1441 1.1 knakahar #ifdef IP_TCPMSS 1442 1.1 knakahar static int l2tp_need_tcpmss_clamp(struct ifnet *); 1443 1.1 knakahar #ifdef INET 1444 1.1 knakahar static struct mbuf *l2tp_tcpmss4_clamp(struct ifnet *, struct mbuf *); 1445 1.1 knakahar #endif 1446 1.1 knakahar #ifdef INET6 1447 1.1 knakahar static struct mbuf *l2tp_tcpmss6_clamp(struct ifnet *, struct mbuf *); 1448 1.1 knakahar #endif 1449 1.1 knakahar 1450 1.1 knakahar struct mbuf * 1451 1.18 maxv l2tp_tcpmss_clamp(struct ifnet *ifp, struct mbuf *m) 1452 1.1 knakahar { 1453 1.18 maxv struct ether_header *eh; 1454 1.18 maxv struct ether_vlan_header evh; 1455 1.1 knakahar 1456 1.18 maxv if (!l2tp_need_tcpmss_clamp(ifp)) { 1457 1.18 maxv return m; 1458 1.18 maxv } 1459 1.18 maxv 1460 1.19 maxv if (m->m_pkthdr.len < sizeof(evh)) { 1461 1.19 maxv m_freem(m); 1462 1.19 maxv return NULL; 1463 1.19 maxv } 1464 1.19 maxv 1465 1.18 maxv /* save ether header */ 1466 1.18 maxv m_copydata(m, 0, sizeof(evh), (void *)&evh); 1467 1.18 maxv eh = (struct ether_header *)&evh; 1468 1.18 maxv 1469 1.18 maxv switch (ntohs(eh->ether_type)) { 1470 1.18 maxv case ETHERTYPE_VLAN: /* Ether + VLAN */ 1471 1.18 maxv if (m->m_pkthdr.len <= sizeof(struct ether_vlan_header)) 1472 1.1 knakahar break; 1473 1.18 maxv m_adj(m, sizeof(struct ether_vlan_header)); 1474 1.18 maxv switch (ntohs(evh.evl_proto)) { 1475 1.1 knakahar #ifdef INET 1476 1.18 maxv case ETHERTYPE_IP: /* Ether + VLAN + IPv4 */ 1477 1.1 knakahar m = l2tp_tcpmss4_clamp(ifp, m); 1478 1.1 knakahar if (m == NULL) 1479 1.1 knakahar return NULL; 1480 1.1 knakahar break; 1481 1.1 knakahar #endif /* INET */ 1482 1.1 knakahar #ifdef INET6 1483 1.18 maxv case ETHERTYPE_IPV6: /* Ether + VLAN + IPv6 */ 1484 1.1 knakahar m = l2tp_tcpmss6_clamp(ifp, m); 1485 1.1 knakahar if (m == NULL) 1486 1.1 knakahar return NULL; 1487 1.1 knakahar break; 1488 1.1 knakahar #endif /* INET6 */ 1489 1.1 knakahar default: 1490 1.1 knakahar break; 1491 1.1 knakahar } 1492 1.18 maxv 1493 1.18 maxv /* restore ether header */ 1494 1.18 maxv M_PREPEND(m, sizeof(struct ether_vlan_header), 1495 1.18 maxv M_DONTWAIT); 1496 1.18 maxv if (m == NULL) 1497 1.18 maxv return NULL; 1498 1.18 maxv *mtod(m, struct ether_vlan_header *) = evh; 1499 1.18 maxv break; 1500 1.18 maxv 1501 1.18 maxv #ifdef INET 1502 1.18 maxv case ETHERTYPE_IP: /* Ether + IPv4 */ 1503 1.18 maxv if (m->m_pkthdr.len <= sizeof(struct ether_header)) 1504 1.18 maxv break; 1505 1.18 maxv m_adj(m, sizeof(struct ether_header)); 1506 1.18 maxv m = l2tp_tcpmss4_clamp(ifp, m); 1507 1.18 maxv if (m == NULL) 1508 1.18 maxv return NULL; 1509 1.18 maxv /* restore ether header */ 1510 1.18 maxv M_PREPEND(m, sizeof(struct ether_header), M_DONTWAIT); 1511 1.18 maxv if (m == NULL) 1512 1.18 maxv return NULL; 1513 1.18 maxv *mtod(m, struct ether_header *) = *eh; 1514 1.18 maxv break; 1515 1.18 maxv #endif /* INET */ 1516 1.18 maxv 1517 1.18 maxv #ifdef INET6 1518 1.18 maxv case ETHERTYPE_IPV6: /* Ether + IPv6 */ 1519 1.18 maxv if (m->m_pkthdr.len <= sizeof(struct ether_header)) 1520 1.18 maxv break; 1521 1.18 maxv m_adj(m, sizeof(struct ether_header)); 1522 1.18 maxv m = l2tp_tcpmss6_clamp(ifp, m); 1523 1.18 maxv if (m == NULL) 1524 1.18 maxv return NULL; 1525 1.18 maxv /* restore ether header */ 1526 1.18 maxv M_PREPEND(m, sizeof(struct ether_header), M_DONTWAIT); 1527 1.18 maxv if (m == NULL) 1528 1.18 maxv return NULL; 1529 1.18 maxv *mtod(m, struct ether_header *) = *eh; 1530 1.18 maxv break; 1531 1.18 maxv #endif /* INET6 */ 1532 1.18 maxv 1533 1.18 maxv default: 1534 1.18 maxv break; 1535 1.1 knakahar } 1536 1.1 knakahar 1537 1.1 knakahar return m; 1538 1.1 knakahar } 1539 1.1 knakahar 1540 1.1 knakahar static int 1541 1.1 knakahar l2tp_need_tcpmss_clamp(struct ifnet *ifp) 1542 1.1 knakahar { 1543 1.1 knakahar int ret = 0; 1544 1.1 knakahar 1545 1.1 knakahar #ifdef INET 1546 1.1 knakahar if (ifp->if_tcpmss != 0) 1547 1.1 knakahar ret = 1; 1548 1.18 maxv #endif 1549 1.1 knakahar 1550 1.1 knakahar #ifdef INET6 1551 1.1 knakahar if (ifp->if_tcpmss6 != 0) 1552 1.1 knakahar ret = 1; 1553 1.18 maxv #endif 1554 1.1 knakahar 1555 1.1 knakahar return ret; 1556 1.1 knakahar } 1557 1.1 knakahar 1558 1.1 knakahar #ifdef INET 1559 1.1 knakahar static struct mbuf * 1560 1.1 knakahar l2tp_tcpmss4_clamp(struct ifnet *ifp, struct mbuf *m) 1561 1.1 knakahar { 1562 1.1 knakahar 1563 1.1 knakahar if (ifp->if_tcpmss != 0) { 1564 1.1 knakahar return ip_tcpmss(m, (ifp->if_tcpmss < 0) ? 1565 1.1 knakahar ifp->if_mtu - IP_TCPMSS_EXTLEN : 1566 1.1 knakahar ifp->if_tcpmss); 1567 1.1 knakahar } 1568 1.1 knakahar return m; 1569 1.1 knakahar } 1570 1.1 knakahar #endif /* INET */ 1571 1.1 knakahar 1572 1.1 knakahar #ifdef INET6 1573 1.1 knakahar static struct mbuf * 1574 1.1 knakahar l2tp_tcpmss6_clamp(struct ifnet *ifp, struct mbuf *m) 1575 1.1 knakahar { 1576 1.1 knakahar int ip6hdrlen; 1577 1.1 knakahar 1578 1.1 knakahar if (ifp->if_tcpmss6 != 0 && 1579 1.1 knakahar ip6_tcpmss_applicable(m, &ip6hdrlen)) { 1580 1.1 knakahar return ip6_tcpmss(m, ip6hdrlen, 1581 1.1 knakahar (ifp->if_tcpmss6 < 0) ? 1582 1.1 knakahar ifp->if_mtu - IP6_TCPMSS_EXTLEN : 1583 1.1 knakahar ifp->if_tcpmss6); 1584 1.1 knakahar } 1585 1.1 knakahar return m; 1586 1.1 knakahar } 1587 1.1 knakahar #endif /* INET6 */ 1588 1.1 knakahar 1589 1.1 knakahar #endif /* IP_TCPMSS */ 1590