1 1.23 andvar /* $NetBSD: in6_l2tp.c,v 1.23 2023/09/01 11:23:39 andvar 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 #include <sys/cdefs.h> 30 1.23 andvar __KERNEL_RCSID(0, "$NetBSD: in6_l2tp.c,v 1.23 2023/09/01 11:23:39 andvar Exp $"); 31 1.1 knakahar 32 1.1 knakahar #ifdef _KERNEL_OPT 33 1.1 knakahar #include "opt_l2tp.h" 34 1.1 knakahar #endif 35 1.1 knakahar 36 1.1 knakahar #include <sys/param.h> 37 1.1 knakahar #include <sys/systm.h> 38 1.1 knakahar #include <sys/socket.h> 39 1.1 knakahar #include <sys/sockio.h> 40 1.1 knakahar #include <sys/mbuf.h> 41 1.1 knakahar #include <sys/errno.h> 42 1.1 knakahar #include <sys/ioctl.h> 43 1.1 knakahar #include <sys/syslog.h> 44 1.1 knakahar #include <sys/kernel.h> 45 1.1 knakahar 46 1.1 knakahar #include <net/if.h> 47 1.1 knakahar #include <net/route.h> 48 1.1 knakahar #include <net/if_ether.h> 49 1.1 knakahar 50 1.1 knakahar #include <netinet/in.h> 51 1.1 knakahar #include <netinet/in_systm.h> 52 1.1 knakahar #include <netinet/ip.h> 53 1.1 knakahar #include <netinet/ip_var.h> 54 1.1 knakahar #include <netinet/ip_private.h> 55 1.1 knakahar #include <netinet/in_l2tp.h> 56 1.1 knakahar #include <netinet/in_var.h> 57 1.1 knakahar #include <netinet/ip_encap.h> 58 1.1 knakahar 59 1.1 knakahar #include <netinet/ip6.h> 60 1.1 knakahar #include <netinet6/ip6_var.h> 61 1.20 christos #include <netinet6/ip6_private.h> 62 1.1 knakahar #include <netinet6/in6_l2tp.h> 63 1.1 knakahar 64 1.1 knakahar #ifdef ALTQ 65 1.1 knakahar #include <altq/altq.h> 66 1.1 knakahar #endif 67 1.1 knakahar 68 1.1 knakahar /* TODO: IP_TCPMSS support */ 69 1.1 knakahar #undef IP_TCPMSS 70 1.1 knakahar #ifdef IP_TCPMSS 71 1.1 knakahar #include <netinet/ip_tcpmss.h> 72 1.1 knakahar #endif 73 1.1 knakahar 74 1.1 knakahar #include <net/if_l2tp.h> 75 1.1 knakahar 76 1.1 knakahar #define L2TP_HLIM6 64 77 1.1 knakahar int ip6_l2tp_hlim = L2TP_HLIM6; 78 1.1 knakahar 79 1.7 knakahar static int in6_l2tp_input(struct mbuf **, int *, int, void *); 80 1.1 knakahar 81 1.1 knakahar static const struct encapsw in6_l2tp_encapsw = { 82 1.1 knakahar .encapsw6 = { 83 1.1 knakahar .pr_input = in6_l2tp_input, 84 1.1 knakahar .pr_ctlinput = NULL, 85 1.1 knakahar } 86 1.1 knakahar }; 87 1.1 knakahar 88 1.1 knakahar static int in6_l2tp_match(struct mbuf *, int, int, void *); 89 1.1 knakahar 90 1.1 knakahar int 91 1.1 knakahar in6_l2tp_output(struct l2tp_variant *var, struct mbuf *m) 92 1.1 knakahar { 93 1.1 knakahar struct rtentry *rt; 94 1.18 knakahar struct route *ro_pc; 95 1.18 knakahar kmutex_t *lock_pc; 96 1.1 knakahar struct l2tp_softc *sc; 97 1.1 knakahar struct ifnet *ifp; 98 1.1 knakahar struct sockaddr_in6 *sin6_src = satosin6(var->lv_psrc); 99 1.1 knakahar struct sockaddr_in6 *sin6_dst = satosin6(var->lv_pdst); 100 1.1 knakahar struct ip6_hdr ip6hdr; /* capsule IP header, host byte ordered */ 101 1.1 knakahar int error; 102 1.1 knakahar uint32_t sess_id; 103 1.1 knakahar 104 1.1 knakahar KASSERT(var != NULL); 105 1.1 knakahar KASSERT(l2tp_heldref_variant(var)); 106 1.1 knakahar KASSERT(sin6_src != NULL && sin6_dst != NULL); 107 1.1 knakahar KASSERT(sin6_src->sin6_family == AF_INET6 108 1.1 knakahar && sin6_dst->sin6_family == AF_INET6); 109 1.1 knakahar 110 1.1 knakahar sc = var->lv_softc; 111 1.1 knakahar ifp = &sc->l2tp_ec.ec_if; 112 1.1 knakahar error = l2tp_check_nesting(ifp, m); 113 1.6 knakahar if (error) { 114 1.6 knakahar m_freem(m); 115 1.1 knakahar goto looped; 116 1.6 knakahar } 117 1.1 knakahar 118 1.13 maxv /* bidirectional configured tunnel mode */ 119 1.13 maxv if (IN6_IS_ADDR_UNSPECIFIED(&sin6_dst->sin6_addr)) { 120 1.13 maxv m_freem(m); 121 1.13 maxv if ((ifp->if_flags & IFF_DEBUG) != 0) 122 1.13 maxv log(LOG_DEBUG, "%s: ENETUNREACH\n", __func__); 123 1.13 maxv return ENETUNREACH; 124 1.13 maxv } 125 1.13 maxv 126 1.1 knakahar #ifdef NOTYET 127 1.23 andvar /* TODO: support ALTQ for inner frame */ 128 1.1 knakahar #ifdef ALTQ 129 1.1 knakahar ALTQ_SAVE_PAYLOAD(m, AF_ETHER); 130 1.1 knakahar #endif 131 1.1 knakahar #endif 132 1.1 knakahar 133 1.1 knakahar memset(&ip6hdr, 0, sizeof(ip6hdr)); 134 1.1 knakahar ip6hdr.ip6_src = sin6_src->sin6_addr; 135 1.13 maxv ip6hdr.ip6_dst = sin6_dst->sin6_addr; 136 1.1 knakahar /* unlike IPv4, IP version must be filled by caller of ip6_output() */ 137 1.13 maxv ip6hdr.ip6_vfc = 0x60; 138 1.13 maxv ip6hdr.ip6_nxt = IPPROTO_L2TP; 139 1.1 knakahar ip6hdr.ip6_hlim = ip6_l2tp_hlim; 140 1.1 knakahar /* outer IP payload length */ 141 1.1 knakahar ip6hdr.ip6_plen = 0; 142 1.1 knakahar /* session-id length */ 143 1.1 knakahar ip6hdr.ip6_plen += sizeof(uint32_t); 144 1.1 knakahar if (var->lv_use_cookie == L2TP_COOKIE_ON) { 145 1.1 knakahar /* cookie length */ 146 1.1 knakahar ip6hdr.ip6_plen += var->lv_peer_cookie_len; 147 1.1 knakahar } 148 1.1 knakahar 149 1.1 knakahar /* TODO: IP_TCPMSS support */ 150 1.1 knakahar #ifdef IP_TCPMSS 151 1.1 knakahar m = l2tp_tcpmss_clamp(ifp, m); 152 1.1 knakahar if (m == NULL) 153 1.1 knakahar return EINVAL; 154 1.1 knakahar #endif 155 1.1 knakahar 156 1.1 knakahar /* 157 1.13 maxv * Payload length. 158 1.13 maxv * 159 1.13 maxv * NOTE: payload length may be changed in ip_tcpmss(). Typical case 160 1.13 maxv * is missing of TCP mss option in original TCP header. 161 1.1 knakahar */ 162 1.1 knakahar ip6hdr.ip6_plen += m->m_pkthdr.len; 163 1.1 knakahar HTONS(ip6hdr.ip6_plen); 164 1.1 knakahar 165 1.1 knakahar if (var->lv_use_cookie == L2TP_COOKIE_ON) { 166 1.1 knakahar /* prepend session cookie */ 167 1.1 knakahar uint32_t cookie_32; 168 1.1 knakahar uint64_t cookie_64; 169 1.1 knakahar M_PREPEND(m, var->lv_peer_cookie_len, M_DONTWAIT); 170 1.1 knakahar if (m && m->m_len < var->lv_peer_cookie_len) 171 1.1 knakahar m = m_pullup(m, var->lv_peer_cookie_len); 172 1.1 knakahar if (m == NULL) 173 1.1 knakahar return ENOBUFS; 174 1.1 knakahar if (var->lv_peer_cookie_len == 4) { 175 1.1 knakahar cookie_32 = htonl((uint32_t)var->lv_peer_cookie); 176 1.13 maxv memcpy(mtod(m, void *), &cookie_32, sizeof(uint32_t)); 177 1.1 knakahar } else { 178 1.1 knakahar cookie_64 = htobe64(var->lv_peer_cookie); 179 1.13 maxv memcpy(mtod(m, void *), &cookie_64, sizeof(uint64_t)); 180 1.1 knakahar } 181 1.1 knakahar } 182 1.1 knakahar 183 1.1 knakahar /* prepend session-ID */ 184 1.1 knakahar sess_id = htonl(var->lv_peer_sess_id); 185 1.1 knakahar M_PREPEND(m, sizeof(uint32_t), M_DONTWAIT); 186 1.1 knakahar if (m && m->m_len < sizeof(uint32_t)) 187 1.1 knakahar m = m_pullup(m, sizeof(uint32_t)); 188 1.1 knakahar if (m == NULL) 189 1.1 knakahar return ENOBUFS; 190 1.1 knakahar memcpy(mtod(m, uint32_t *), &sess_id, sizeof(uint32_t)); 191 1.1 knakahar 192 1.1 knakahar /* prepend new IP header */ 193 1.1 knakahar M_PREPEND(m, sizeof(struct ip6_hdr), M_DONTWAIT); 194 1.13 maxv if (m == NULL) 195 1.13 maxv return ENOBUFS; 196 1.21 christos if (M_GET_ALIGNED_HDR(&m, struct ip6_hdr, false) != 0) 197 1.1 knakahar return ENOBUFS; 198 1.1 knakahar memcpy(mtod(m, struct ip6_hdr *), &ip6hdr, sizeof(struct ip6_hdr)); 199 1.1 knakahar 200 1.18 knakahar if_tunnel_get_ro(sc->l2tp_ro_percpu, &ro_pc, &lock_pc); 201 1.18 knakahar if ((rt = rtcache_lookup(ro_pc, var->lv_pdst)) == NULL) { 202 1.18 knakahar if_tunnel_put_ro(sc->l2tp_ro_percpu, lock_pc); 203 1.1 knakahar m_freem(m); 204 1.1 knakahar return ENETUNREACH; 205 1.1 knakahar } 206 1.1 knakahar 207 1.1 knakahar /* If the route constitutes infinite encapsulation, punt. */ 208 1.1 knakahar if (rt->rt_ifp == ifp) { 209 1.18 knakahar rtcache_unref(rt, ro_pc); 210 1.18 knakahar rtcache_free(ro_pc); 211 1.18 knakahar if_tunnel_put_ro(sc->l2tp_ro_percpu, lock_pc); 212 1.1 knakahar m_freem(m); 213 1.1 knakahar return ENETUNREACH; /* XXX */ 214 1.1 knakahar } 215 1.18 knakahar rtcache_unref(rt, ro_pc); 216 1.1 knakahar 217 1.1 knakahar /* 218 1.1 knakahar * To avoid inappropriate rewrite of checksum, 219 1.1 knakahar * clear csum flags. 220 1.1 knakahar */ 221 1.1 knakahar m->m_pkthdr.csum_flags = 0; 222 1.1 knakahar 223 1.18 knakahar error = ip6_output(m, 0, ro_pc, 0, NULL, NULL, NULL); 224 1.18 knakahar if_tunnel_put_ro(sc->l2tp_ro_percpu, lock_pc); 225 1.1 knakahar return(error); 226 1.1 knakahar 227 1.1 knakahar looped: 228 1.1 knakahar if (error) 229 1.19 thorpej if_statinc(ifp, if_oerrors); 230 1.1 knakahar 231 1.1 knakahar return error; 232 1.1 knakahar } 233 1.1 knakahar 234 1.1 knakahar static int 235 1.7 knakahar in6_l2tp_input(struct mbuf **mp, int *offp, int proto, void *eparg __unused) 236 1.1 knakahar { 237 1.1 knakahar struct mbuf *m = *mp; 238 1.1 knakahar int off = *offp; 239 1.1 knakahar 240 1.1 knakahar struct ifnet *l2tpp = NULL; 241 1.1 knakahar struct l2tp_softc *sc; 242 1.1 knakahar struct l2tp_variant *var; 243 1.1 knakahar uint32_t sess_id; 244 1.1 knakahar uint32_t cookie_32; 245 1.1 knakahar uint64_t cookie_64; 246 1.1 knakahar struct psref psref; 247 1.1 knakahar 248 1.14 maxv KASSERT((m->m_flags & M_PKTHDR) != 0); 249 1.14 maxv 250 1.14 maxv if (m->m_pkthdr.len < off + sizeof(uint32_t)) { 251 1.14 maxv m_freem(m); 252 1.14 maxv return IPPROTO_DONE; 253 1.14 maxv } 254 1.1 knakahar 255 1.1 knakahar /* get L2TP session ID */ 256 1.1 knakahar m_copydata(m, off, sizeof(uint32_t), (void *)&sess_id); 257 1.1 knakahar NTOHL(sess_id); 258 1.1 knakahar #ifdef L2TP_DEBUG 259 1.1 knakahar log(LOG_DEBUG, "%s: sess_id = %" PRIu32 "\n", __func__, sess_id); 260 1.1 knakahar #endif 261 1.1 knakahar if (sess_id == 0) { 262 1.16 knakahar int rv; 263 1.1 knakahar /* 264 1.1 knakahar * L2TPv3 control packet received. 265 1.1 knakahar * userland daemon(l2tpd?) should process. 266 1.1 knakahar */ 267 1.16 knakahar SOFTNET_LOCK_IF_NET_MPSAFE(); 268 1.16 knakahar rv = rip6_input(mp, offp, proto); 269 1.16 knakahar SOFTNET_UNLOCK_IF_NET_MPSAFE(); 270 1.16 knakahar return rv; 271 1.1 knakahar } 272 1.1 knakahar 273 1.1 knakahar var = l2tp_lookup_session_ref(sess_id, &psref); 274 1.1 knakahar if (var == NULL) { 275 1.1 knakahar m_freem(m); 276 1.1 knakahar IP_STATINC(IP_STAT_NOL2TP); 277 1.1 knakahar return IPPROTO_DONE; 278 1.13 maxv } 279 1.13 maxv 280 1.13 maxv sc = var->lv_softc; 281 1.13 maxv l2tpp = &(sc->l2tp_ec.ec_if); 282 1.1 knakahar 283 1.13 maxv if (l2tpp == NULL || (l2tpp->if_flags & IFF_UP) == 0) { 284 1.1 knakahar #ifdef L2TP_DEBUG 285 1.13 maxv if (l2tpp == NULL) 286 1.13 maxv log(LOG_DEBUG, "%s: l2tpp is NULL\n", __func__); 287 1.13 maxv else 288 1.13 maxv log(LOG_DEBUG, "%s: l2tpp is down\n", __func__); 289 1.1 knakahar #endif 290 1.13 maxv m_freem(m); 291 1.13 maxv IP_STATINC(IP_STAT_NOL2TP); 292 1.13 maxv goto out; 293 1.13 maxv } 294 1.13 maxv 295 1.13 maxv /* other CPU did l2tp_delete_tunnel */ 296 1.13 maxv if (var->lv_psrc == NULL || var->lv_pdst == NULL) { 297 1.13 maxv m_freem(m); 298 1.13 maxv ip_statinc(IP_STAT_NOL2TP); 299 1.13 maxv goto out; 300 1.1 knakahar } 301 1.1 knakahar 302 1.1 knakahar if (var->lv_state != L2TP_STATE_UP) { 303 1.1 knakahar m_freem(m); 304 1.1 knakahar goto out; 305 1.1 knakahar } 306 1.1 knakahar m_adj(m, off + sizeof(uint32_t)); 307 1.1 knakahar 308 1.1 knakahar if (var->lv_use_cookie == L2TP_COOKIE_ON) { 309 1.14 maxv if (m->m_pkthdr.len < var->lv_my_cookie_len) { 310 1.14 maxv m_freem(m); 311 1.14 maxv goto out; 312 1.14 maxv } 313 1.1 knakahar if (var->lv_my_cookie_len == 4) { 314 1.1 knakahar m_copydata(m, 0, sizeof(uint32_t), (void *)&cookie_32); 315 1.1 knakahar NTOHL(cookie_32); 316 1.1 knakahar if (cookie_32 != var->lv_my_cookie) { 317 1.1 knakahar m_freem(m); 318 1.1 knakahar goto out; 319 1.1 knakahar } 320 1.1 knakahar m_adj(m, sizeof(uint32_t)); 321 1.1 knakahar } else { 322 1.1 knakahar m_copydata(m, 0, sizeof(uint64_t), (void *)&cookie_64); 323 1.1 knakahar BE64TOH(cookie_64); 324 1.1 knakahar if (cookie_64 != var->lv_my_cookie) { 325 1.1 knakahar m_freem(m); 326 1.1 knakahar goto out; 327 1.1 knakahar } 328 1.1 knakahar m_adj(m, sizeof(uint64_t)); 329 1.1 knakahar } 330 1.1 knakahar } 331 1.1 knakahar 332 1.1 knakahar /* TODO: IP_TCPMSS support */ 333 1.1 knakahar #ifdef IP_TCPMSS 334 1.1 knakahar m = l2tp_tcpmss_clamp(l2tpp, m); 335 1.1 knakahar if (m == NULL) 336 1.1 knakahar goto out; 337 1.1 knakahar #endif 338 1.1 knakahar l2tp_input(m, l2tpp); 339 1.1 knakahar 340 1.1 knakahar out: 341 1.1 knakahar l2tp_putref_variant(var, &psref); 342 1.1 knakahar return IPPROTO_DONE; 343 1.1 knakahar } 344 1.1 knakahar 345 1.1 knakahar /* 346 1.1 knakahar * This function is used by encap6_lookup() to decide priority of the encaptab. 347 1.1 knakahar * This priority is compared to the match length between mbuf's source/destination 348 1.1 knakahar * IPv6 address pair and encaptab's one. 349 1.1 knakahar * l2tp(4) does not use address pairs to search matched encaptab, so this 350 1.1 knakahar * function must return the length bigger than or equals to IPv6 address pair to 351 1.1 knakahar * avoid wrong encaptab. 352 1.1 knakahar */ 353 1.1 knakahar static int 354 1.1 knakahar in6_l2tp_match(struct mbuf *m, int off, int proto, void *arg) 355 1.1 knakahar { 356 1.17 knakahar struct l2tp_softc *sc = arg; 357 1.17 knakahar struct l2tp_variant *var; 358 1.17 knakahar struct psref psref; 359 1.1 knakahar uint32_t sess_id; 360 1.17 knakahar int rv = 0; 361 1.1 knakahar 362 1.1 knakahar KASSERT(proto == IPPROTO_L2TP); 363 1.1 knakahar 364 1.17 knakahar var = l2tp_getref_variant(sc, &psref); 365 1.17 knakahar if (__predict_false(var == NULL)) 366 1.17 knakahar return rv; 367 1.17 knakahar 368 1.12 knakahar /* 369 1.12 knakahar * If the packet contains no session ID it cannot match 370 1.12 knakahar */ 371 1.17 knakahar if (m_length(m) < off + sizeof(uint32_t)) { 372 1.17 knakahar rv = 0 ; 373 1.17 knakahar goto out; 374 1.17 knakahar } 375 1.1 knakahar 376 1.1 knakahar /* get L2TP session ID */ 377 1.1 knakahar m_copydata(m, off, sizeof(uint32_t), (void *)&sess_id); 378 1.1 knakahar NTOHL(sess_id); 379 1.1 knakahar if (sess_id == 0) { 380 1.1 knakahar /* 381 1.1 knakahar * L2TPv3 control packet received. 382 1.1 knakahar * userland daemon(l2tpd?) should process. 383 1.1 knakahar */ 384 1.17 knakahar rv = 128 * 2; 385 1.1 knakahar } else if (sess_id == var->lv_my_sess_id) 386 1.17 knakahar rv = 128 * 2; 387 1.1 knakahar else 388 1.17 knakahar rv = 0; 389 1.17 knakahar 390 1.17 knakahar out: 391 1.17 knakahar l2tp_putref_variant(var, &psref); 392 1.17 knakahar return rv; 393 1.1 knakahar } 394 1.1 knakahar 395 1.1 knakahar int 396 1.1 knakahar in6_l2tp_attach(struct l2tp_variant *var) 397 1.1 knakahar { 398 1.17 knakahar struct l2tp_softc *sc = var->lv_softc; 399 1.1 knakahar 400 1.17 knakahar if (sc == NULL) 401 1.17 knakahar return EINVAL; 402 1.22 knakahar 403 1.22 knakahar var->lv_encap_cookie = encap_attach_addr(AF_INET6, IPPROTO_L2TP, 404 1.22 knakahar var->lv_psrc, var->lv_pdst, in6_l2tp_match, &in6_l2tp_encapsw, sc); 405 1.1 knakahar if (var->lv_encap_cookie == NULL) 406 1.1 knakahar return EEXIST; 407 1.1 knakahar 408 1.1 knakahar return 0; 409 1.1 knakahar } 410 1.1 knakahar 411 1.1 knakahar int 412 1.1 knakahar in6_l2tp_detach(struct l2tp_variant *var) 413 1.1 knakahar { 414 1.1 knakahar int error; 415 1.1 knakahar 416 1.1 knakahar error = encap_detach(var->lv_encap_cookie); 417 1.1 knakahar if (error == 0) 418 1.1 knakahar var->lv_encap_cookie = NULL; 419 1.1 knakahar 420 1.1 knakahar return error; 421 1.1 knakahar } 422