head 1.22; access; symbols netbsd-10-0-RELEASE:1.21 netbsd-10-0-RC6:1.21 netbsd-10-0-RC5:1.21 netbsd-10-0-RC4:1.21 netbsd-10-0-RC3:1.21 netbsd-10-0-RC2:1.21 thorpej-ifq:1.22.0.4 thorpej-ifq-base:1.22 thorpej-altq-separation:1.22.0.2 thorpej-altq-separation-base:1.22 netbsd-10-0-RC1:1.21 netbsd-10:1.21.0.2 netbsd-10-base:1.21 bouyer-sunxi-drm:1.20.0.16 bouyer-sunxi-drm-base:1.20 netbsd-9-3-RELEASE:1.16.4.1 thorpej-i2c-spi-conf2:1.20.0.14 thorpej-i2c-spi-conf2-base:1.20 thorpej-futex2:1.20.0.12 thorpej-futex2-base:1.20 thorpej-cfargs2:1.20.0.10 thorpej-cfargs2-base:1.20 cjep_sun2x-base1:1.20 cjep_sun2x:1.20.0.8 cjep_sun2x-base:1.20 cjep_staticlib_x-base1:1.20 netbsd-9-2-RELEASE:1.16.4.1 cjep_staticlib_x:1.20.0.6 cjep_staticlib_x-base:1.20 thorpej-i2c-spi-conf:1.20.0.4 thorpej-i2c-spi-conf-base:1.20 thorpej-cfargs:1.20.0.2 thorpej-cfargs-base:1.20 thorpej-futex:1.18.0.6 thorpej-futex-base:1.20 netbsd-9-1-RELEASE:1.16.4.1 bouyer-xenpvh-base2:1.18 phil-wifi-20200421:1.18 bouyer-xenpvh-base1:1.18 phil-wifi-20200411:1.18 bouyer-xenpvh:1.18.0.4 bouyer-xenpvh-base:1.18 is-mlppp:1.18.0.2 is-mlppp-base:1.18 phil-wifi-20200406:1.18 netbsd-8-2-RELEASE:1.2.8.8 ad-namecache-base3:1.18 netbsd-9-0-RELEASE:1.16.4.1 netbsd-9-0-RC2:1.16.4.1 ad-namecache-base2:1.17 ad-namecache-base1:1.17 ad-namecache:1.17.0.2 ad-namecache-base:1.17 netbsd-9-0-RC1:1.16.4.1 phil-wifi-20191119:1.17 netbsd-9:1.16.0.4 netbsd-9-base:1.16 phil-wifi-20190609:1.16 netbsd-8-1-RELEASE:1.2.8.7 netbsd-8-1-RC1:1.2.8.7 isaki-audio2:1.16.0.2 isaki-audio2-base:1.16 pgoyette-compat-merge-20190127:1.12.2.3 pgoyette-compat-20190127:1.16 pgoyette-compat-20190118:1.16 pgoyette-compat-1226:1.16 pgoyette-compat-1126:1.16 pgoyette-compat-1020:1.16 pgoyette-compat-0930:1.16 pgoyette-compat-0906:1.16 pgoyette-compat-0728:1.15 netbsd-8-0-RELEASE:1.2.8.6 phil-wifi:1.15.0.2 phil-wifi-base:1.15 pgoyette-compat-0625:1.15 netbsd-8-0-RC2:1.2.8.5 pgoyette-compat-0521:1.14 pgoyette-compat-0502:1.14 pgoyette-compat-0422:1.12 netbsd-8-0-RC1:1.2.8.4 pgoyette-compat-0415:1.12 pgoyette-compat-0407:1.12 pgoyette-compat-0330:1.12 pgoyette-compat-0322:1.12 pgoyette-compat-0315:1.12 pgoyette-compat:1.12.0.2 pgoyette-compat-base:1.12 tls-maxphys:1.4.0.2 tls-maxphys-base-20171202:1.4 matt-nb8-mediatek:1.2.8.1.0.2 matt-nb8-mediatek-base:1.2.8.1 nick-nhusb:1.3.0.4 nick-nhusb-base-20170825:1.3 perseant-stdc-iso10646:1.3.0.2 perseant-stdc-iso10646-base:1.3 netbsd-8:1.2.0.8 netbsd-8-base:1.2 prg-localcount2-base3:1.2 prg-localcount2-base2:1.2 prg-localcount2-base1:1.2 prg-localcount2:1.2.0.6 prg-localcount2-base:1.2 pgoyette-localcount-20170426:1.2 bouyer-socketcan:1.2.0.4 bouyer-socketcan-base1:1.2 jdolecek-ncq:1.2.0.2 jdolecek-ncq-base:1.2 pgoyette-localcount:1.1.0.2 pgoyette-localcount-20170320:1.1; locks; strict; comment @ * @; 1.22 date 2023.09.01.11.23.39; author andvar; state Exp; branches; next 1.21; commitid JOTdGAAV2UqvJ3DE; 1.21 date 2022.12.07.08.30.15; author knakahara; state Exp; branches; next 1.20; commitid epNrGxLU4btgoB4E; 1.20 date 2021.02.19.14.51.59; author christos; state Exp; branches; next 1.19; commitid wdRVbcAyAXsnAkIC; 1.19 date 2021.02.14.20.58.35; author christos; state Exp; branches; next 1.18; commitid jf1vtf1Dpp5BLIHC; 1.18 date 2020.01.29.04.37.24; author thorpej; state Exp; branches 1.18.6.1; next 1.17; commitid CpzRopLdjgVZCxUB; 1.17 date 2019.09.19.06.07.25; author knakahara; state Exp; branches 1.17.2.1; next 1.16; commitid qJJI3j4jdHENmADB; 1.16 date 2018.09.03.02.33.30; author knakahara; state Exp; branches 1.16.4.1; next 1.15; commitid av087AU2icXKqBQA; 1.15 date 2018.06.21.10.37.50; author knakahara; state Exp; branches 1.15.2.1; next 1.14; commitid vSPYPhlx6g9tu8HA; 1.14 date 2018.05.01.07.21.39; author maxv; state Exp; branches; next 1.13; commitid WJfFRrHJ8oMH2zAA; 1.13 date 2018.04.27.09.55.28; author knakahara; state Exp; branches; next 1.12; commitid EmUjcpvFihcn14AA; 1.12 date 2018.01.26.07.49.15; author maxv; state Exp; branches 1.12.2.1; next 1.11; commitid i7YmUtWyTqLufmoA; 1.11 date 2018.01.25.10.45.58; author maxv; state Exp; branches; next 1.10; commitid MJIutwb1NBq8gfoA; 1.10 date 2018.01.22.09.51.06; author maxv; state Exp; branches; next 1.9; commitid kQy2cDq6Dkao3RnA; 1.9 date 2017.12.18.03.21.44; author knakahara; state Exp; branches; next 1.8; commitid uyqdKwuaCtsz1kjA; 1.8 date 2017.12.18.03.20.12; author knakahara; state Exp; branches; next 1.7; commitid u4VDAhKZqTNZ0kjA; 1.7 date 2017.12.15.05.01.16; author knakahara; state Exp; branches; next 1.6; commitid jsia3NoHzwt9FWiA; 1.6 date 2017.12.15.04.58.31; author knakahara; state Exp; branches; next 1.5; commitid 6qvCoMm1VvVzEWiA; 1.5 date 2017.12.11.02.17.35; author knakahara; state Exp; branches; next 1.4; commitid VTYA3vkBkQqaTpiA; 1.4 date 2017.11.15.10.42.41; author knakahara; state Exp; branches 1.4.2.1; next 1.3; commitid 11iqliCSvCpBw7fA; 1.3 date 2017.07.11.05.03.45; author knakahara; state Exp; branches 1.3.4.1; next 1.2; commitid PmnhzOy5nG9oJLYz; 1.2 date 2017.03.30.23.13.54; author knakahara; state Exp; branches 1.2.4.1 1.2.8.1; next 1.1; commitid MYMBj6kuZOeB4DLz; 1.1 date 2017.02.16.08.23.35; author knakahara; state Exp; branches 1.1.2.1; next ; commitid kmlgpTG5a8SYu9Gz; 1.18.6.1 date 2021.04.03.22.29.01; author thorpej; state Exp; branches; next ; commitid 1gqS07EfPjskJTNC; 1.17.2.1 date 2020.02.29.20.21.07; author ad; state Exp; branches; next ; commitid OjSb8ro7YQETQBYB; 1.16.4.1 date 2019.09.24.03.10.35; author martin; state Exp; branches; next ; commitid nYjvjjBTcYMjedEB; 1.15.2.1 date 2019.06.10.22.09.47; author christos; state Exp; branches; next 1.15.2.2; commitid jtc8rnCzWiEEHGqB; 1.15.2.2 date 2020.04.08.14.08.58; author martin; state Exp; branches; next 1.15.2.3; commitid Qli2aW9E74UFuA3C; 1.15.2.3 date 2020.04.13.08.05.16; author martin; state Exp; branches; next ; commitid X01YhRUPVUDaec4C; 1.12.2.1 date 2018.05.02.07.20.23; author pgoyette; state Exp; branches; next 1.12.2.2; commitid o3kRuNRzl9360HAA; 1.12.2.2 date 2018.06.25.07.26.06; author pgoyette; state Exp; branches; next 1.12.2.3; commitid 8PtAu9af7VvhiDHA; 1.12.2.3 date 2018.09.06.06.56.44; author pgoyette; state Exp; branches; next ; commitid HCi1bXD317XIK0RA; 1.4.2.1 date 2017.11.15.10.42.41; author jdolecek; state dead; branches; next 1.4.2.2; commitid XcIYRZTAh1LmerhA; 1.4.2.2 date 2017.12.03.11.39.04; author jdolecek; state Exp; branches; next ; commitid XcIYRZTAh1LmerhA; 1.3.4.1 date 2017.07.11.05.03.45; author skrll; state dead; branches; next 1.3.4.2; commitid UQQpnjvcNkUZn05A; 1.3.4.2 date 2017.08.28.17.53.12; author skrll; state Exp; branches; next ; commitid UQQpnjvcNkUZn05A; 1.2.4.1 date 2017.03.30.23.13.54; author bouyer; state dead; branches; next 1.2.4.2; commitid dUG7nkTKALCadqOz; 1.2.4.2 date 2017.04.21.16.54.05; author bouyer; state Exp; branches; next ; commitid dUG7nkTKALCadqOz; 1.2.8.1 date 2017.07.12.13.42.11; author martin; state Exp; branches; next 1.2.8.2; commitid i4IQeORLXgxjzWYz; 1.2.8.2 date 2017.12.10.09.41.31; author snj; state Exp; branches; next 1.2.8.3; commitid dg6xdcf4JT9pnkiA; 1.2.8.3 date 2018.01.02.10.39.57; author snj; state Exp; branches; next 1.2.8.4; commitid rkUzfXkJnblUXhlA; 1.2.8.4 date 2018.03.08.13.41.41; author martin; state Exp; branches; next 1.2.8.5; commitid nY8ypfJ7czQPSEtA; 1.2.8.5 date 2018.05.17.14.07.03; author martin; state Exp; branches; next 1.2.8.6; commitid UR4jmmzU1ho1MECA; 1.2.8.6 date 2018.07.13.14.26.47; author martin; state Exp; branches; next 1.2.8.7; commitid wEpABar11HNc3ZJA; 1.2.8.7 date 2018.09.10.15.58.47; author martin; state Exp; branches; next 1.2.8.8; commitid c0bGw1gqCh0cFzRA; 1.2.8.8 date 2019.09.24.18.27.10; author martin; state Exp; branches; next ; commitid RvehYH9WLwoKiiEB; 1.1.2.1 date 2017.02.16.08.23.35; author pgoyette; state dead; branches; next 1.1.2.2; commitid jjw7cAwgyKq7RfKz; 1.1.2.2 date 2017.03.20.06.57.50; author pgoyette; state Exp; branches; next 1.1.2.3; commitid jjw7cAwgyKq7RfKz; 1.1.2.3 date 2017.04.26.02.53.29; author pgoyette; state Exp; branches; next ; commitid ojV02aOSdzvBqZOz; desc @@ 1.22 log @fix typos in comments, mainly s/innner/inner/. @ text @/* $NetBSD: in_l2tp.c,v 1.21 2022/12/07 08:30:15 knakahara Exp $ */ /* * Copyright (c) 2017 Internet Initiative Japan Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include __KERNEL_RCSID(0, "$NetBSD: in_l2tp.c,v 1.21 2022/12/07 08:30:15 knakahara Exp $"); #ifdef _KERNEL_OPT #include "opt_l2tp.h" #endif #include #include #include #include #include #include #include #include #include #include /* For softnet_lock */ #include #include #include #include #include #include #include #include #include #include #include #ifdef ALTQ #include #endif /* TODO: IP_TCPMSS support */ #undef IP_TCPMSS #ifdef IP_TCPMSS #include #endif #include int ip_l2tp_ttl = L2TP_TTL; static void in_l2tp_input(struct mbuf *, int, int, void *); static const struct encapsw in_l2tp_encapsw = { .encapsw4 = { .pr_input = in_l2tp_input, .pr_ctlinput = NULL, } }; static int in_l2tp_match(struct mbuf *, int, int, void *); int in_l2tp_output(struct l2tp_variant *var, struct mbuf *m) { struct l2tp_softc *sc; struct ifnet *ifp; struct sockaddr_in *sin_src = satosin(var->lv_psrc); struct sockaddr_in *sin_dst = satosin(var->lv_pdst); struct ip iphdr; /* capsule IP header, host byte ordered */ struct rtentry *rt; struct route *ro_pc; kmutex_t *lock_pc; int error; uint32_t sess_id; KASSERT(var != NULL); KASSERT(l2tp_heldref_variant(var)); KASSERT(sin_src != NULL && sin_dst != NULL); KASSERT(sin_src->sin_family == AF_INET && sin_dst->sin_family == AF_INET); sc = var->lv_softc; ifp = &sc->l2tp_ec.ec_if; error = l2tp_check_nesting(ifp, m); if (error) { m_freem(m); goto looped; } /* bidirectional configured tunnel mode */ if (sin_dst->sin_addr.s_addr == INADDR_ANY) { m_freem(m); if ((ifp->if_flags & IFF_DEBUG) != 0) log(LOG_DEBUG, "%s: ENETUNREACH\n", __func__); error = ENETUNREACH; goto out; } #ifdef NOTYET /* TODO: support ALTQ for inner frame */ #ifdef ALTQ ALTQ_SAVE_PAYLOAD(m, AF_ETHER); #endif #endif memset(&iphdr, 0, sizeof(iphdr)); iphdr.ip_src = sin_src->sin_addr; iphdr.ip_dst = sin_dst->sin_addr; iphdr.ip_p = IPPROTO_L2TP; /* version will be set in ip_output() */ iphdr.ip_ttl = ip_l2tp_ttl; /* outer IP header length */ iphdr.ip_len = sizeof(struct ip); /* session-id length */ iphdr.ip_len += sizeof(uint32_t); if (var->lv_use_cookie == L2TP_COOKIE_ON) { /* cookie length */ iphdr.ip_len += var->lv_peer_cookie_len; } /* TODO: IP_TCPMSS support */ #ifdef IP_TCPMSS m = l2tp_tcpmss_clamp(ifp, m); if (m == NULL) { error = EINVAL; goto out; } #endif /* * Payload length. * * NOTE: payload length may be changed in ip_tcpmss(). Typical case * is missing of TCP mss option in original TCP header. */ iphdr.ip_len += m->m_pkthdr.len; HTONS(iphdr.ip_len); if (var->lv_use_cookie == L2TP_COOKIE_ON) { /* prepend session cookie */ uint32_t cookie_32; uint64_t cookie_64; M_PREPEND(m, var->lv_peer_cookie_len, M_DONTWAIT); if (m && m->m_len < var->lv_peer_cookie_len) m = m_pullup(m, var->lv_peer_cookie_len); if (m == NULL) { error = ENOBUFS; goto out; } if (var->lv_peer_cookie_len == 4) { cookie_32 = htonl((uint32_t)var->lv_peer_cookie); memcpy(mtod(m, void *), &cookie_32, sizeof(uint32_t)); } else { cookie_64 = htobe64(var->lv_peer_cookie); memcpy(mtod(m, void *), &cookie_64, sizeof(uint64_t)); } } /* prepend session-ID */ sess_id = htonl(var->lv_peer_sess_id); M_PREPEND(m, sizeof(uint32_t), M_DONTWAIT); if (m && m->m_len < sizeof(uint32_t)) m = m_pullup(m, sizeof(uint32_t)); if (m == NULL) { error = ENOBUFS; goto out; } memcpy(mtod(m, uint32_t *), &sess_id, sizeof(uint32_t)); /* prepend new IP header */ M_PREPEND(m, sizeof(struct ip), M_DONTWAIT); if (m == NULL) { error = ENOBUFS; goto out; } if (M_GET_ALIGNED_HDR(&m, struct ip, false) != 0) { error = ENOBUFS; goto out; } memcpy(mtod(m, struct ip *), &iphdr, sizeof(struct ip)); if_tunnel_get_ro(sc->l2tp_ro_percpu, &ro_pc, &lock_pc); if ((rt = rtcache_lookup(ro_pc, var->lv_pdst)) == NULL) { if_tunnel_put_ro(sc->l2tp_ro_percpu, lock_pc); m_freem(m); error = ENETUNREACH; goto out; } if (rt->rt_ifp == ifp) { rtcache_unref(rt, ro_pc); rtcache_free(ro_pc); if_tunnel_put_ro(sc->l2tp_ro_percpu, lock_pc); m_freem(m); error = ENETUNREACH; /*XXX*/ goto out; } rtcache_unref(rt, ro_pc); /* * To avoid inappropriate rewrite of checksum, * clear csum flags. */ m->m_pkthdr.csum_flags = 0; error = ip_output(m, NULL, ro_pc, 0, NULL, NULL); if_tunnel_put_ro(sc->l2tp_ro_percpu, lock_pc); return error; looped: if (error) if_statinc(ifp, if_oerrors); out: return error; } static void in_l2tp_input(struct mbuf *m, int off, int proto, void *eparg __unused) { struct ifnet *l2tpp = NULL; struct l2tp_softc *sc; uint32_t sess_id; uint32_t cookie_32; uint64_t cookie_64; struct psref psref; struct l2tp_variant *var; KASSERT((m->m_flags & M_PKTHDR) != 0); if (m->m_pkthdr.len < off + sizeof(uint32_t)) { m_freem(m); return; } /* get L2TP session ID */ m_copydata(m, off, sizeof(uint32_t), (void *)&sess_id); NTOHL(sess_id); #ifdef L2TP_DEBUG log(LOG_DEBUG, "%s: sess_id = %" PRIu32 "\n", __func__, sess_id); #endif if (sess_id == 0) { /* * L2TPv3 control packet received. * userland daemon(l2tpd?) should process. */ SOFTNET_LOCK_IF_NET_MPSAFE(); rip_input(m, off, proto); SOFTNET_UNLOCK_IF_NET_MPSAFE(); return; } var = l2tp_lookup_session_ref(sess_id, &psref); if (var == NULL) { m_freem(m); ip_statinc(IP_STAT_NOL2TP); return; } sc = var->lv_softc; l2tpp = &(sc->l2tp_ec.ec_if); if (l2tpp == NULL || (l2tpp->if_flags & IFF_UP) == 0) { #ifdef L2TP_DEBUG if (l2tpp == NULL) log(LOG_DEBUG, "%s: l2tpp is NULL\n", __func__); else log(LOG_DEBUG, "%s: l2tpp is down\n", __func__); #endif m_freem(m); ip_statinc(IP_STAT_NOL2TP); goto out; } /* other CPU did l2tp_delete_tunnel */ if (var->lv_psrc == NULL || var->lv_pdst == NULL) { m_freem(m); ip_statinc(IP_STAT_NOL2TP); goto out; } if (var->lv_state != L2TP_STATE_UP) { m_freem(m); goto out; } m_adj(m, off + sizeof(uint32_t)); if (var->lv_use_cookie == L2TP_COOKIE_ON) { if (m->m_pkthdr.len < var->lv_my_cookie_len) { m_freem(m); goto out; } if (var->lv_my_cookie_len == 4) { m_copydata(m, 0, sizeof(uint32_t), (void *)&cookie_32); NTOHL(cookie_32); if (cookie_32 != var->lv_my_cookie) { m_freem(m); goto out; } m_adj(m, sizeof(uint32_t)); } else { m_copydata(m, 0, sizeof(uint64_t), (void *)&cookie_64); BE64TOH(cookie_64); if (cookie_64 != var->lv_my_cookie) { m_freem(m); goto out; } m_adj(m, sizeof(uint64_t)); } } /* TODO: IP_TCPMSS support */ #ifdef IP_TCPMSS m = l2tp_tcpmss_clamp(l2tpp, m); if (m == NULL) goto out; #endif l2tp_input(m, l2tpp); out: l2tp_putref_variant(var, &psref); return; } /* * This function is used by encap4_lookup() to decide priority of the encaptab. * This priority is compared to the match length between mbuf's source/destination * IPv4 address pair and encaptab's one. * l2tp(4) does not use address pairs to search matched encaptab, so this * function must return the length bigger than or equals to IPv4 address pair to * avoid wrong encaptab. */ static int in_l2tp_match(struct mbuf *m, int off, int proto, void *arg) { struct l2tp_softc *sc = arg; struct l2tp_variant *var; struct psref psref; uint32_t sess_id; int rv = 0; KASSERT(proto == IPPROTO_L2TP); var = l2tp_getref_variant(sc, &psref); if (__predict_false(var == NULL)) return rv; /* * If the packet contains no session ID it cannot match */ if (m_length(m) < off + sizeof(uint32_t)) { rv = 0; goto out; } /* get L2TP session ID */ m_copydata(m, off, sizeof(uint32_t), (void *)&sess_id); NTOHL(sess_id); if (sess_id == 0) { /* * L2TPv3 control packet received. * userland daemon(l2tpd?) should process. */ rv = 32 * 2; } else if (sess_id == var->lv_my_sess_id) rv = 32 * 2; else rv = 0; out: l2tp_putref_variant(var, &psref); return rv; } int in_l2tp_attach(struct l2tp_variant *var) { struct l2tp_softc *sc = var->lv_softc; if (sc == NULL) return EINVAL; var->lv_encap_cookie = encap_attach_addr(AF_INET, IPPROTO_L2TP, var->lv_psrc, var->lv_pdst, in_l2tp_match, &in_l2tp_encapsw, sc); if (var->lv_encap_cookie == NULL) return EEXIST; return 0; } int in_l2tp_detach(struct l2tp_variant *var) { int error; error = encap_detach(var->lv_encap_cookie); if (error == 0) var->lv_encap_cookie = NULL; return error; } @ 1.21 log @gif(4), ipsec(4) and l2tp(4) use encap_attach_addr(). @ text @d1 1 a1 1 /* $NetBSD: in_l2tp.c,v 1.20 2021/02/19 14:51:59 christos Exp $ */ d30 1 a30 1 __KERNEL_RCSID(0, "$NetBSD: in_l2tp.c,v 1.20 2021/02/19 14:51:59 christos Exp $"); d124 1 a124 1 /* TODO: support ALTQ for innner frame */ @ 1.20 log @- Make ALIGNED_POINTER use __alignof(t) instead of sizeof(t). This is more correct because it works with non-primitive types and provides the ABI alignment for the type the compiler will use. - Remove all the *_HDR_ALIGNMENT macros and asserts - Replace POINTER_ALIGNED_P with ACCESSIBLE_POINTER which is identical to ALIGNED_POINTER, but returns that the pointer is always aligned if the CPU supports unaligned accesses. [ as proposed in tech-kern ] @ text @d1 1 a1 1 /* $NetBSD: in_l2tp.c,v 1.19 2021/02/14 20:58:35 christos Exp $ */ d30 1 a30 1 __KERNEL_RCSID(0, "$NetBSD: in_l2tp.c,v 1.19 2021/02/14 20:58:35 christos Exp $"); d407 3 a409 2 var->lv_encap_cookie = encap_attach_func(AF_INET, IPPROTO_L2TP, in_l2tp_match, &in_l2tp_encapsw, sc); @ 1.19 log @- centralize header align and pullup into a single inline function - use a single macro to align pointers and expose the alignment, instead of hard-coding 3 in 1/2 the macros. - fix an issue in the ipv6 lt2p where it was aligning for ipv4 and pulling for ipv6. @ text @d1 1 a1 1 /* $NetBSD: in_l2tp.c,v 1.18 2020/01/29 04:37:24 thorpej Exp $ */ d30 1 a30 1 __KERNEL_RCSID(0, "$NetBSD: in_l2tp.c,v 1.18 2020/01/29 04:37:24 thorpej Exp $"); d200 1 a200 2 if (m_get_aligned_hdr(&m, IP_HDR_ALIGNMENT, sizeof(iphdr), false) != 0) { @ 1.18 log @Adopt . @ text @d1 1 a1 1 /* $NetBSD: in_l2tp.c,v 1.17 2019/09/19 06:07:25 knakahara Exp $ */ d30 1 a30 1 __KERNEL_RCSID(0, "$NetBSD: in_l2tp.c,v 1.17 2019/09/19 06:07:25 knakahara Exp $"); d200 2 a201 7 if (IP_HDR_ALIGNED_P(mtod(m, void *)) == 0) { m = m_copyup(m, sizeof(struct ip), 0); } else { if (m->m_len < sizeof(struct ip)) m = m_pullup(m, sizeof(struct ip)); } if (m == NULL) { @ 1.18.6.1 log @Sync with HEAD. @ text @d1 1 a1 1 /* $NetBSD: in_l2tp.c,v 1.20 2021/02/19 14:51:59 christos Exp $ */ d30 1 a30 1 __KERNEL_RCSID(0, "$NetBSD: in_l2tp.c,v 1.20 2021/02/19 14:51:59 christos Exp $"); d200 7 a206 1 if (M_GET_ALIGNED_HDR(&m, struct ip, false) != 0) { @ 1.17 log @Avoid having a rtcache directly in a percpu storage for tunnel protocols. percpu(9) has a certain memory storage for each CPU and provides it by the piece to users. If the storages went short, percpu(9) enlarges them by allocating new larger memory areas, replacing old ones with them and destroying the old ones. A percpu storage referenced by a pointer gotten via percpu_getref can be destroyed by the mechanism after a running thread sleeps even if percpu_putref has not been called. Using rtcache, i.e., packet processing, typically involves sleepable operations such as rwlock so we must avoid dereferencing a rtcache that is directly stored in a percpu storage during packet processing. Address this situation by having just a pointer to a rtcache in a percpu storage instead. Reviewed by ozaki-r@@ and yamaguchi@@ @ text @d1 1 a1 1 /* $NetBSD: in_l2tp.c,v 1.16 2018/09/03 02:33:30 knakahara Exp $ */ d30 1 a30 1 __KERNEL_RCSID(0, "$NetBSD: in_l2tp.c,v 1.16 2018/09/03 02:33:30 knakahara Exp $"); d242 1 a242 1 ifp->if_oerrors++; @ 1.17.2.1 log @Sync with head. @ text @d1 1 a1 1 /* $NetBSD: in_l2tp.c,v 1.18 2020/01/29 04:37:24 thorpej Exp $ */ d30 1 a30 1 __KERNEL_RCSID(0, "$NetBSD: in_l2tp.c,v 1.18 2020/01/29 04:37:24 thorpej Exp $"); d242 1 a242 1 if_statinc(ifp, if_oerrors); @ 1.16 log @fix: l2tp(4) cannot receive packets after reset session without reset tunnel. Pointed out by k-goda@@IIJ When the following operations are done after established session, the l2tp0 cannot receive packets until done deletetunnel && tunnel "src" "dst". ==================== ifconfig l2tp0 deletesession ifconfig l2tp0 deletecookie ifconfig l2tp0 session 200 100 ==================== XXX pullup-8 @ text @d1 1 a1 1 /* $NetBSD: in_l2tp.c,v 1.15 2018/06/21 10:37:50 knakahara Exp $ */ d30 1 a30 1 __KERNEL_RCSID(0, "$NetBSD: in_l2tp.c,v 1.15 2018/06/21 10:37:50 knakahara Exp $"); d94 3 a96 1 struct l2tp_ro *lro; d212 3 a214 5 lro = percpu_getref(sc->l2tp_ro_percpu); mutex_enter(lro->lr_lock); if ((rt = rtcache_lookup(&lro->lr_ro, var->lv_pdst)) == NULL) { mutex_exit(lro->lr_lock); percpu_putref(sc->l2tp_ro_percpu); d221 3 a223 4 rtcache_unref(rt, &lro->lr_ro); rtcache_free(&lro->lr_ro); mutex_exit(lro->lr_lock); percpu_putref(sc->l2tp_ro_percpu); d228 1 a228 1 rtcache_unref(rt, &lro->lr_ro); d236 2 a237 3 error = ip_output(m, NULL, &lro->lr_ro, 0, NULL, NULL); mutex_exit(lro->lr_lock); percpu_putref(sc->l2tp_ro_percpu); @ 1.16.4.1 log @Pull up following revision(s) (requested by ozaki-r in ticket #238): sys/netipsec/ipsec_output.c: revision 1.83 sys/net/route.h: revision 1.125 sys/netinet6/ip6_input.c: revision 1.210 sys/netinet6/ip6_input.c: revision 1.211 sys/net/if.c: revision 1.461 sys/net/if_gif.h: revision 1.33 sys/net/route.c: revision 1.220 sys/net/route.c: revision 1.221 sys/net/if.h: revision 1.277 sys/netinet6/ip6_forward.c: revision 1.97 sys/netinet/wqinput.c: revision 1.6 sys/net/if_ipsec.h: revision 1.5 sys/netinet6/in6_l2tp.c: revision 1.18 sys/netinet6/in6_gif.c: revision 1.94 sys/net/if_l2tp.h: revision 1.7 sys/net/if_gif.c: revision 1.149 sys/net/if_l2tp.h: revision 1.8 sys/netinet/in_gif.c: revision 1.95 sys/netinet/in_l2tp.c: revision 1.17 sys/netipsec/ipsecif.c: revision 1.17 sys/net/if_ipsec.c: revision 1.24 sys/net/if_l2tp.c: revision 1.37 sys/netinet/ip_input.c: revision 1.391 sys/net/if_l2tp.c: revision 1.38 sys/netinet/ip_input.c: revision 1.392 sys/net/if_l2tp.c: revision 1.39 Avoid having a rtcache directly in a percpu storage percpu(9) has a certain memory storage for each CPU and provides it by the piece to users. If the storages went short, percpu(9) enlarges them by allocating new larger memory areas, replacing old ones with them and destroying the old ones. A percpu storage referenced by a pointer gotten via percpu_getref can be destroyed by the mechanism after a running thread sleeps even if percpu_putref has not been called. Using rtcache, i.e., packet processing, typically involves sleepable operations such as rwlock so we must avoid dereferencing a rtcache that is directly stored in a percpu storage during packet processing. Address this situation by having just a pointer to a rtcache in a percpu storage instead. Reviewed by knakahara@@ and yamaguchi@@ - wqinput: avoid having struct wqinput_worklist directly in a percpu storage percpu(9) has a certain memory storage for each CPU and provides it by the piece to users. If the storages went short, percpu(9) enlarges them by allocating new larger memory areas, replacing old ones with them and destroying the old ones. A percpu storage referenced by a pointer gotten via percpu_getref can be destroyed by the mechanism after a running thread sleeps even if percpu_putref has not been called. Input handlers of wqinput normally involves sleepable operations so we must avoid dereferencing a percpu data (struct wqinput_worklist) after executing an input handler. Address this situation by having just a pointer to the data in a percpu storage instead. Reviewed by knakahara@@ and yamaguchi@@ - Add missing #include - Divide Tx context of l2tp(4) to improve performance. It seems l2tp(4) call path is too long for instruction cache. So, dividing l2tp(4) Tx context improves CPU use efficiency. After this commit, l2tp(4) throughput gains 10% on my machine(Atom C3000). - Apply some missing changes lost on the previous commit - Avoid having a rtcache directly in a percpu storage for tunnel protocols. percpu(9) has a certain memory storage for each CPU and provides it by the piece to users. If the storages went short, percpu(9) enlarges them by allocating new larger memory areas, replacing old ones with them and destroying the old ones. A percpu storage referenced by a pointer gotten via percpu_getref can be destroyed by the mechanism after a running thread sleeps even if percpu_putref has not been called. Using rtcache, i.e., packet processing, typically involves sleepable operations such as rwlock so we must avoid dereferencing a rtcache that is directly stored in a percpu storage during packet processing. Address this situation by having just a pointer to a rtcache in a percpu storage instead. Reviewed by ozaki-r@@ and yamaguchi@@ - l2tp(4): avoid having struct ifqueue directly in a percpu storage. percpu(9) has a certain memory storage for each CPU and provides it by the piece to users. If the storages went short, percpu(9) enlarges them by allocating new larger memory areas, replacing old ones with them and destroying the old ones. A percpu storage referenced by a pointer gotten via percpu_getref can be destroyed by the mechanism after a running thread sleeps even if percpu_putref has not been called. Tx processing of l2tp(4) uses normally involves sleepable operations so we must avoid dereferencing a percpu data (struct ifqueue) after executing Tx processing. Address this situation by having just a pointer to the data in a percpu storage instead. Reviewed by ozaki-r@@ and yamaguchi@@ @ text @d1 1 a1 1 /* $NetBSD: in_l2tp.c,v 1.16 2018/09/03 02:33:30 knakahara Exp $ */ d30 1 a30 1 __KERNEL_RCSID(0, "$NetBSD: in_l2tp.c,v 1.16 2018/09/03 02:33:30 knakahara Exp $"); d94 1 a94 3 struct route *ro_pc; kmutex_t *lock_pc; d210 5 a214 3 if_tunnel_get_ro(sc->l2tp_ro_percpu, &ro_pc, &lock_pc); if ((rt = rtcache_lookup(ro_pc, var->lv_pdst)) == NULL) { if_tunnel_put_ro(sc->l2tp_ro_percpu, lock_pc); d221 4 a224 3 rtcache_unref(rt, ro_pc); rtcache_free(ro_pc); if_tunnel_put_ro(sc->l2tp_ro_percpu, lock_pc); d229 1 a229 1 rtcache_unref(rt, ro_pc); d237 3 a239 2 error = ip_output(m, NULL, ro_pc, 0, NULL, NULL); if_tunnel_put_ro(sc->l2tp_ro_percpu, lock_pc); @ 1.15 log @sbappendaddr() is required any lock. Currently, softnet_lock is appropriate. When rip_input() is called as inetsw[].pr_input, rip_iput() is always called with holding softnet_lock, that is, in case of !defined(NET_MPSAFE) it is acquired in ipintr(), otherwise(defined(NET_MPSAFE)) it is acquire in PR_WRAP_INPUT macro. However, some function calls rip_input() directly without holding softnet_lock. That causes assertion failure in sbappendaddr(). rip6_input() and icmp6_rip6_input() are also required softnet_lock for the same reason. @ text @d1 1 a1 1 /* $NetBSD: in_l2tp.c,v 1.14 2018/05/01 07:21:39 maxv Exp $ */ d30 1 a30 1 __KERNEL_RCSID(0, "$NetBSD: in_l2tp.c,v 1.14 2018/05/01 07:21:39 maxv Exp $"); d369 3 a371 1 struct l2tp_variant *var = arg; d373 1 d377 4 d384 4 a387 2 if (m_length(m) < off + sizeof(uint32_t)) return 0; d397 1 a397 1 return 32 * 2; d399 1 a399 1 return 32 * 2; d401 5 a405 1 return 0; d411 1 d413 2 d416 1 a416 1 in_l2tp_match, &in_l2tp_encapsw, var); @ 1.15.2.1 log @Sync with HEAD @ text @d1 1 a1 1 /* $NetBSD: in_l2tp.c,v 1.16 2018/09/03 02:33:30 knakahara Exp $ */ d30 1 a30 1 __KERNEL_RCSID(0, "$NetBSD: in_l2tp.c,v 1.16 2018/09/03 02:33:30 knakahara Exp $"); d369 1 a369 3 struct l2tp_softc *sc = arg; struct l2tp_variant *var; struct psref psref; a370 1 int rv = 0; a373 4 var = l2tp_getref_variant(sc, &psref); if (__predict_false(var == NULL)) return rv; d377 2 a378 4 if (m_length(m) < off + sizeof(uint32_t)) { rv = 0; goto out; } d388 1 a388 1 rv = 32 * 2; d390 1 a390 1 rv = 32 * 2; d392 1 a392 5 rv = 0; out: l2tp_putref_variant(var, &psref); return rv; a397 1 struct l2tp_softc *sc = var->lv_softc; a398 2 if (sc == NULL) return EINVAL; d400 1 a400 1 in_l2tp_match, &in_l2tp_encapsw, sc); @ 1.15.2.2 log @Merge changes from current as of 20200406 @ text @d1 1 a1 1 /* $NetBSD$ */ d30 1 a30 1 __KERNEL_RCSID(0, "$NetBSD$"); d244 1 a244 1 if_statinc(ifp, if_oerrors); @ 1.15.2.3 log @Mostly merge changes from HEAD upto 20200411 @ text @d94 1 a94 3 struct route *ro_pc; kmutex_t *lock_pc; d210 5 a214 3 if_tunnel_get_ro(sc->l2tp_ro_percpu, &ro_pc, &lock_pc); if ((rt = rtcache_lookup(ro_pc, var->lv_pdst)) == NULL) { if_tunnel_put_ro(sc->l2tp_ro_percpu, lock_pc); d221 4 a224 3 rtcache_unref(rt, ro_pc); rtcache_free(ro_pc); if_tunnel_put_ro(sc->l2tp_ro_percpu, lock_pc); d229 1 a229 1 rtcache_unref(rt, ro_pc); d237 3 a239 2 error = ip_output(m, NULL, ro_pc, 0, NULL, NULL); if_tunnel_put_ro(sc->l2tp_ro_percpu, lock_pc); @ 1.14 log @Remove now unused net_osdep.h includes, the other BSDs did the same. @ text @d1 1 a1 1 /* $NetBSD: in_l2tp.c,v 1.13 2018/04/27 09:55:28 knakahara Exp $ */ d30 1 a30 1 __KERNEL_RCSID(0, "$NetBSD: in_l2tp.c,v 1.13 2018/04/27 09:55:28 knakahara Exp $"); d45 1 d279 1 d281 1 @ 1.13 log @Fix LOCKDEBUG kernel panic when many(about 200) tunnel interfaces is created. The tunnel interfaces are gif(4), l2tp(4), and ipsecif(4). They use mutex itself in percpu area. When percpu_cpu_enlarge() run, the address of the mutex in percpu area becomes different from the address which lockdebug saved. That can cause "already initialized" false detection. @ text @d1 1 a1 1 /* $NetBSD: in_l2tp.c,v 1.12 2018/01/26 07:49:15 maxv Exp $ */ d30 1 a30 1 __KERNEL_RCSID(0, "$NetBSD: in_l2tp.c,v 1.12 2018/01/26 07:49:15 maxv Exp $"); a70 2 #include @ 1.12 log @Several fixes in L2TP: * l2tp_input(): use m_copydata, and ensure there is enough space in the chain. Otherwise overflow. * l2tp_tcpmss_clamp(): ensure there is enough space in the chain. * in_l2tp_output(): don't check 'sc' against NULL, it can't be NULL. * in_l2tp_input(): no need to call m_pullup since we use m_copydata. Just check the space in the chain. * in_l2tp_input(): if there is a cookie, make sure the chain has enough space. * in6_l2tp_input(): same changes as in_l2tp_input(). Ok knakahara@@ @ text @d1 1 a1 1 /* $NetBSD: in_l2tp.c,v 1.10 2018/01/22 09:51:06 maxv Exp $ */ d30 1 a30 1 __KERNEL_RCSID(0, "$NetBSD: in_l2tp.c,v 1.10 2018/01/22 09:51:06 maxv Exp $"); d212 1 a212 1 mutex_enter(&lro->lr_lock); d214 1 a214 1 mutex_exit(&lro->lr_lock); d224 1 a224 1 mutex_exit(&lro->lr_lock); d239 1 a239 1 mutex_exit(&lro->lr_lock); @ 1.12.2.1 log @Synch with HEAD @ text @d1 1 a1 1 /* $NetBSD: in_l2tp.c,v 1.14 2018/05/01 07:21:39 maxv Exp $ */ d30 1 a30 1 __KERNEL_RCSID(0, "$NetBSD: in_l2tp.c,v 1.14 2018/05/01 07:21:39 maxv Exp $"); d71 2 d212 1 a212 1 mutex_enter(lro->lr_lock); d214 1 a214 1 mutex_exit(lro->lr_lock); d224 1 a224 1 mutex_exit(lro->lr_lock); d239 1 a239 1 mutex_exit(lro->lr_lock); @ 1.12.2.2 log @Sync with HEAD @ text @d1 1 a1 1 /* $NetBSD: in_l2tp.c,v 1.15 2018/06/21 10:37:50 knakahara Exp $ */ d30 1 a30 1 __KERNEL_RCSID(0, "$NetBSD: in_l2tp.c,v 1.15 2018/06/21 10:37:50 knakahara Exp $"); a44 1 #include /* For softnet_lock */ a277 1 SOFTNET_LOCK_IF_NET_MPSAFE(); a278 1 SOFTNET_UNLOCK_IF_NET_MPSAFE(); @ 1.12.2.3 log @Sync with HEAD Resolve a couple of conflicts (result of the uimin/uimax changes) @ text @d1 1 a1 1 /* $NetBSD: in_l2tp.c,v 1.16 2018/09/03 02:33:30 knakahara Exp $ */ d30 1 a30 1 __KERNEL_RCSID(0, "$NetBSD: in_l2tp.c,v 1.16 2018/09/03 02:33:30 knakahara Exp $"); d369 1 a369 3 struct l2tp_softc *sc = arg; struct l2tp_variant *var; struct psref psref; a370 1 int rv = 0; a373 4 var = l2tp_getref_variant(sc, &psref); if (__predict_false(var == NULL)) return rv; d377 2 a378 4 if (m_length(m) < off + sizeof(uint32_t)) { rv = 0; goto out; } d388 1 a388 1 rv = 32 * 2; d390 1 a390 1 rv = 32 * 2; d392 1 a392 5 rv = 0; out: l2tp_putref_variant(var, &psref); return rv; a397 1 struct l2tp_softc *sc = var->lv_softc; a398 2 if (sc == NULL) return EINVAL; d400 1 a400 1 in_l2tp_match, &in_l2tp_encapsw, sc); @ 1.11 log @Style, reduce the indentation level when possible, and add a missing NULL check after M_PREPEND. @ text @a105 3 if (sc == NULL) return ENETUNREACH; d262 6 a267 7 if (m->m_len < off + sizeof(uint32_t)) { m = m_pullup(m, off + sizeof(uint32_t)); if (!m) { /* if payload length < 4 octets */ return; } } d321 4 @ 1.10 log @Fix null deref, m could be NULL if M_PREPEND fails. @ text @d1 1 a1 1 /* $NetBSD: in_l2tp.c,v 1.9 2017/12/18 03:21:44 knakahara Exp $ */ d30 1 a30 1 __KERNEL_RCSID(0, "$NetBSD: in_l2tp.c,v 1.9 2017/12/18 03:21:44 knakahara Exp $"); d116 10 a125 1 #ifdef NETYET d134 1 a134 10 /* bidirectional configured tunnel mode */ if (sin_dst->sin_addr.s_addr != INADDR_ANY) iphdr.ip_dst = sin_dst->sin_addr; else { m_freem(m); if ((ifp->if_flags & IFF_DEBUG) != 0) log(LOG_DEBUG, "%s: ENETUNREACH\n", __func__); error = ENETUNREACH; goto out; } d155 1 d157 4 a160 4 * payload length * NOTE: Payload length may be changed in ip_tcpmss(). * Typical case is missing of TCP mss option in original * TCP header. d178 1 a178 2 memcpy(mtod(m, void *), &cookie_32, sizeof(uint32_t)); d181 1 a181 2 memcpy(mtod(m, void *), &cookie_64, sizeof(uint64_t)); d293 4 a296 3 } else { sc = var->lv_softc; l2tpp = &(sc->l2tp_ec.ec_if); d298 1 a298 1 if (l2tpp == NULL || (l2tpp->if_flags & IFF_UP) == 0) { d300 4 a303 4 if (l2tpp == NULL) log(LOG_DEBUG, "%s: l2tpp is NULL\n", __func__); else log(LOG_DEBUG, "%s: l2tpp is down\n", __func__); d305 4 a308 4 m_freem(m); ip_statinc(IP_STAT_NOL2TP); goto out; } d310 5 a314 6 /* other CPU do l2tp_delete_tunnel */ if (var->lv_psrc == NULL || var->lv_pdst == NULL) { m_freem(m); ip_statinc(IP_STAT_NOL2TP); goto out; } @ 1.9 log @fix mbuf leaks. pointed out and suggested by kre@@n.o, thanks. @ text @d1 1 a1 1 /* $NetBSD: in_l2tp.c,v 1.8 2017/12/18 03:20:12 knakahara Exp $ */ d30 1 a30 1 __KERNEL_RCSID(0, "$NetBSD: in_l2tp.c,v 1.8 2017/12/18 03:20:12 knakahara Exp $"); d199 4 d204 1 a204 2 if (m) m = m_copyup(m, sizeof(struct ip), 0); d206 1 a206 1 if (m && m->m_len < sizeof(struct ip)) @ 1.8 log @backout wrong fix again, sorry. @ text @d1 1 a1 1 /* $NetBSD: in_l2tp.c,v 1.7 2017/12/15 05:01:16 knakahara Exp $ */ d30 1 a30 1 __KERNEL_RCSID(0, "$NetBSD: in_l2tp.c,v 1.7 2017/12/15 05:01:16 knakahara Exp $"); d371 5 a375 7 if (m->m_len < off + sizeof(uint32_t)) { m = m_pullup(m, off + sizeof(uint32_t)); if (!m) { /* if payload length < 4 octets */ return 0; } } @ 1.7 log @Fix pullup'ed mbuf leaks. The match function just requires enough mbuf length. XXX need pullup-8 @ text @d1 1 a1 1 /* $NetBSD: in_l2tp.c,v 1.6 2017/12/15 04:58:31 knakahara Exp $ */ d30 1 a30 1 __KERNEL_RCSID(0, "$NetBSD: in_l2tp.c,v 1.6 2017/12/15 04:58:31 knakahara Exp $"); d372 3 a374 2 /* if payload length < 4 octets */ if(!m_ensure_contig(&m, off + sizeof(uint32_t))) d376 2 a377 1 } @ 1.6 log @backout wrong fix as it causes atf net/ipsec/t_ipsec_l2tp failures. @ text @d1 1 a1 1 /* $NetBSD: in_l2tp.c,v 1.5 2017/12/11 02:17:35 knakahara Exp $ */ d30 1 a30 1 __KERNEL_RCSID(0, "$NetBSD: in_l2tp.c,v 1.5 2017/12/11 02:17:35 knakahara Exp $"); d372 2 a373 3 m = m_pullup(m, off + sizeof(uint32_t)); if (!m) { /* if payload length < 4 octets */ d375 1 a375 2 } } @ 1.5 log @fix pullup'ed mbuf leaks. pointed out by maxv@@n.o, thanks. XXX need pullup-8 @ text @d1 1 a1 1 /* $NetBSD: in_l2tp.c,v 1.4 2017/11/15 10:42:41 knakahara Exp $ */ d30 1 a30 1 __KERNEL_RCSID(0, "$NetBSD: in_l2tp.c,v 1.4 2017/11/15 10:42:41 knakahara Exp $"); d371 7 a377 3 /* if payload length < 4 octets */ if (m->m_len < off + sizeof(uint32_t)) return 0; @ 1.4 log @Add argument to encapsw->pr_input() instead of m_tag. @ text @d1 1 a1 1 /* $NetBSD: in_l2tp.c,v 1.3 2017/07/11 05:03:45 knakahara Exp $ */ d30 1 a30 1 __KERNEL_RCSID(0, "$NetBSD: in_l2tp.c,v 1.3 2017/07/11 05:03:45 knakahara Exp $"); d371 3 a373 7 if (m->m_len < off + sizeof(uint32_t)) { m = m_pullup(m, off + sizeof(uint32_t)); if (!m) { /* if payload length < 4 octets */ return 0; } } @ 1.4.2.1 log @file in_l2tp.c was added on branch tls-maxphys on 2017-12-03 11:39:04 +0000 @ text @d1 416 @ 1.4.2.2 log @update from HEAD @ text @a0 416 /* $NetBSD$ */ /* * Copyright (c) 2017 Internet Initiative Japan Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include __KERNEL_RCSID(0, "$NetBSD$"); #ifdef _KERNEL_OPT #include "opt_l2tp.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef ALTQ #include #endif /* TODO: IP_TCPMSS support */ #undef IP_TCPMSS #ifdef IP_TCPMSS #include #endif #include #include int ip_l2tp_ttl = L2TP_TTL; static void in_l2tp_input(struct mbuf *, int, int, void *); static const struct encapsw in_l2tp_encapsw = { .encapsw4 = { .pr_input = in_l2tp_input, .pr_ctlinput = NULL, } }; static int in_l2tp_match(struct mbuf *, int, int, void *); int in_l2tp_output(struct l2tp_variant *var, struct mbuf *m) { struct l2tp_softc *sc; struct ifnet *ifp; struct sockaddr_in *sin_src = satosin(var->lv_psrc); struct sockaddr_in *sin_dst = satosin(var->lv_pdst); struct ip iphdr; /* capsule IP header, host byte ordered */ struct rtentry *rt; struct l2tp_ro *lro; int error; uint32_t sess_id; KASSERT(var != NULL); KASSERT(l2tp_heldref_variant(var)); KASSERT(sin_src != NULL && sin_dst != NULL); KASSERT(sin_src->sin_family == AF_INET && sin_dst->sin_family == AF_INET); sc = var->lv_softc; if (sc == NULL) return ENETUNREACH; ifp = &sc->l2tp_ec.ec_if; error = l2tp_check_nesting(ifp, m); if (error) { m_freem(m); goto looped; } #ifdef NETYET /* TODO: support ALTQ for innner frame */ #ifdef ALTQ ALTQ_SAVE_PAYLOAD(m, AF_ETHER); #endif #endif memset(&iphdr, 0, sizeof(iphdr)); iphdr.ip_src = sin_src->sin_addr; /* bidirectional configured tunnel mode */ if (sin_dst->sin_addr.s_addr != INADDR_ANY) iphdr.ip_dst = sin_dst->sin_addr; else { m_freem(m); if ((ifp->if_flags & IFF_DEBUG) != 0) log(LOG_DEBUG, "%s: ENETUNREACH\n", __func__); error = ENETUNREACH; goto out; } iphdr.ip_p = IPPROTO_L2TP; /* version will be set in ip_output() */ iphdr.ip_ttl = ip_l2tp_ttl; /* outer IP header length */ iphdr.ip_len = sizeof(struct ip); /* session-id length */ iphdr.ip_len += sizeof(uint32_t); if (var->lv_use_cookie == L2TP_COOKIE_ON) { /* cookie length */ iphdr.ip_len += var->lv_peer_cookie_len; } /* TODO: IP_TCPMSS support */ #ifdef IP_TCPMSS m = l2tp_tcpmss_clamp(ifp, m); if (m == NULL) { error = EINVAL; goto out; } #endif /* * payload length * NOTE: Payload length may be changed in ip_tcpmss(). * Typical case is missing of TCP mss option in original * TCP header. */ iphdr.ip_len += m->m_pkthdr.len; HTONS(iphdr.ip_len); if (var->lv_use_cookie == L2TP_COOKIE_ON) { /* prepend session cookie */ uint32_t cookie_32; uint64_t cookie_64; M_PREPEND(m, var->lv_peer_cookie_len, M_DONTWAIT); if (m && m->m_len < var->lv_peer_cookie_len) m = m_pullup(m, var->lv_peer_cookie_len); if (m == NULL) { error = ENOBUFS; goto out; } if (var->lv_peer_cookie_len == 4) { cookie_32 = htonl((uint32_t)var->lv_peer_cookie); memcpy(mtod(m, void *), &cookie_32, sizeof(uint32_t)); } else { cookie_64 = htobe64(var->lv_peer_cookie); memcpy(mtod(m, void *), &cookie_64, sizeof(uint64_t)); } } /* prepend session-ID */ sess_id = htonl(var->lv_peer_sess_id); M_PREPEND(m, sizeof(uint32_t), M_DONTWAIT); if (m && m->m_len < sizeof(uint32_t)) m = m_pullup(m, sizeof(uint32_t)); if (m == NULL) { error = ENOBUFS; goto out; } memcpy(mtod(m, uint32_t *), &sess_id, sizeof(uint32_t)); /* prepend new IP header */ M_PREPEND(m, sizeof(struct ip), M_DONTWAIT); if (IP_HDR_ALIGNED_P(mtod(m, void *)) == 0) { if (m) m = m_copyup(m, sizeof(struct ip), 0); } else { if (m && m->m_len < sizeof(struct ip)) m = m_pullup(m, sizeof(struct ip)); } if (m == NULL) { error = ENOBUFS; goto out; } memcpy(mtod(m, struct ip *), &iphdr, sizeof(struct ip)); lro = percpu_getref(sc->l2tp_ro_percpu); mutex_enter(&lro->lr_lock); if ((rt = rtcache_lookup(&lro->lr_ro, var->lv_pdst)) == NULL) { mutex_exit(&lro->lr_lock); percpu_putref(sc->l2tp_ro_percpu); m_freem(m); error = ENETUNREACH; goto out; } if (rt->rt_ifp == ifp) { rtcache_unref(rt, &lro->lr_ro); rtcache_free(&lro->lr_ro); mutex_exit(&lro->lr_lock); percpu_putref(sc->l2tp_ro_percpu); m_freem(m); error = ENETUNREACH; /*XXX*/ goto out; } rtcache_unref(rt, &lro->lr_ro); /* * To avoid inappropriate rewrite of checksum, * clear csum flags. */ m->m_pkthdr.csum_flags = 0; error = ip_output(m, NULL, &lro->lr_ro, 0, NULL, NULL); mutex_exit(&lro->lr_lock); percpu_putref(sc->l2tp_ro_percpu); return error; looped: if (error) ifp->if_oerrors++; out: return error; } static void in_l2tp_input(struct mbuf *m, int off, int proto, void *eparg __unused) { struct ifnet *l2tpp = NULL; struct l2tp_softc *sc; uint32_t sess_id; uint32_t cookie_32; uint64_t cookie_64; struct psref psref; struct l2tp_variant *var; if (m->m_len < off + sizeof(uint32_t)) { m = m_pullup(m, off + sizeof(uint32_t)); if (!m) { /* if payload length < 4 octets */ return; } } /* get L2TP session ID */ m_copydata(m, off, sizeof(uint32_t), (void *)&sess_id); NTOHL(sess_id); #ifdef L2TP_DEBUG log(LOG_DEBUG, "%s: sess_id = %" PRIu32 "\n", __func__, sess_id); #endif if (sess_id == 0) { /* * L2TPv3 control packet received. * userland daemon(l2tpd?) should process. */ rip_input(m, off, proto); return; } var = l2tp_lookup_session_ref(sess_id, &psref); if (var == NULL) { m_freem(m); ip_statinc(IP_STAT_NOL2TP); return; } else { sc = var->lv_softc; l2tpp = &(sc->l2tp_ec.ec_if); if (l2tpp == NULL || (l2tpp->if_flags & IFF_UP) == 0) { #ifdef L2TP_DEBUG if (l2tpp == NULL) log(LOG_DEBUG, "%s: l2tpp is NULL\n", __func__); else log(LOG_DEBUG, "%s: l2tpp is down\n", __func__); #endif m_freem(m); ip_statinc(IP_STAT_NOL2TP); goto out; } /* other CPU do l2tp_delete_tunnel */ if (var->lv_psrc == NULL || var->lv_pdst == NULL) { m_freem(m); ip_statinc(IP_STAT_NOL2TP); goto out; } } if (var->lv_state != L2TP_STATE_UP) { m_freem(m); goto out; } m_adj(m, off + sizeof(uint32_t)); if (var->lv_use_cookie == L2TP_COOKIE_ON) { if (var->lv_my_cookie_len == 4) { m_copydata(m, 0, sizeof(uint32_t), (void *)&cookie_32); NTOHL(cookie_32); if (cookie_32 != var->lv_my_cookie) { m_freem(m); goto out; } m_adj(m, sizeof(uint32_t)); } else { m_copydata(m, 0, sizeof(uint64_t), (void *)&cookie_64); BE64TOH(cookie_64); if (cookie_64 != var->lv_my_cookie) { m_freem(m); goto out; } m_adj(m, sizeof(uint64_t)); } } /* TODO: IP_TCPMSS support */ #ifdef IP_TCPMSS m = l2tp_tcpmss_clamp(l2tpp, m); if (m == NULL) goto out; #endif l2tp_input(m, l2tpp); out: l2tp_putref_variant(var, &psref); return; } /* * This function is used by encap4_lookup() to decide priority of the encaptab. * This priority is compared to the match length between mbuf's source/destination * IPv4 address pair and encaptab's one. * l2tp(4) does not use address pairs to search matched encaptab, so this * function must return the length bigger than or equals to IPv4 address pair to * avoid wrong encaptab. */ static int in_l2tp_match(struct mbuf *m, int off, int proto, void *arg) { struct l2tp_variant *var = arg; uint32_t sess_id; KASSERT(proto == IPPROTO_L2TP); if (m->m_len < off + sizeof(uint32_t)) { m = m_pullup(m, off + sizeof(uint32_t)); if (!m) { /* if payload length < 4 octets */ return 0; } } /* get L2TP session ID */ m_copydata(m, off, sizeof(uint32_t), (void *)&sess_id); NTOHL(sess_id); if (sess_id == 0) { /* * L2TPv3 control packet received. * userland daemon(l2tpd?) should process. */ return 32 * 2; } else if (sess_id == var->lv_my_sess_id) return 32 * 2; else return 0; } int in_l2tp_attach(struct l2tp_variant *var) { var->lv_encap_cookie = encap_attach_func(AF_INET, IPPROTO_L2TP, in_l2tp_match, &in_l2tp_encapsw, var); if (var->lv_encap_cookie == NULL) return EEXIST; return 0; } int in_l2tp_detach(struct l2tp_variant *var) { int error; error = encap_detach(var->lv_encap_cookie); if (error == 0) var->lv_encap_cookie = NULL; return error; } @ 1.3 log @l2tp(4): fix mbuf leak when tunnel nested over the limit XXX need pullup -8 branch @ text @d1 1 a1 1 /* $NetBSD: in_l2tp.c,v 1.2 2017/03/30 23:13:54 knakahara Exp $ */ d30 1 a30 1 __KERNEL_RCSID(0, "$NetBSD: in_l2tp.c,v 1.2 2017/03/30 23:13:54 knakahara Exp $"); d75 1 a75 1 static void in_l2tp_input(struct mbuf *, int, int); d253 1 a253 1 in_l2tp_input(struct mbuf *m, int off, int proto) @ 1.3.4.1 log @file in_l2tp.c was added on branch nick-nhusb on 2017-08-28 17:53:12 +0000 @ text @d1 416 @ 1.3.4.2 log @Sync with HEAD @ text @a0 416 /* $NetBSD: in_l2tp.c,v 1.3 2017/07/11 05:03:45 knakahara Exp $ */ /* * Copyright (c) 2017 Internet Initiative Japan Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include __KERNEL_RCSID(0, "$NetBSD: in_l2tp.c,v 1.3 2017/07/11 05:03:45 knakahara Exp $"); #ifdef _KERNEL_OPT #include "opt_l2tp.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef ALTQ #include #endif /* TODO: IP_TCPMSS support */ #undef IP_TCPMSS #ifdef IP_TCPMSS #include #endif #include #include int ip_l2tp_ttl = L2TP_TTL; static void in_l2tp_input(struct mbuf *, int, int); static const struct encapsw in_l2tp_encapsw = { .encapsw4 = { .pr_input = in_l2tp_input, .pr_ctlinput = NULL, } }; static int in_l2tp_match(struct mbuf *, int, int, void *); int in_l2tp_output(struct l2tp_variant *var, struct mbuf *m) { struct l2tp_softc *sc; struct ifnet *ifp; struct sockaddr_in *sin_src = satosin(var->lv_psrc); struct sockaddr_in *sin_dst = satosin(var->lv_pdst); struct ip iphdr; /* capsule IP header, host byte ordered */ struct rtentry *rt; struct l2tp_ro *lro; int error; uint32_t sess_id; KASSERT(var != NULL); KASSERT(l2tp_heldref_variant(var)); KASSERT(sin_src != NULL && sin_dst != NULL); KASSERT(sin_src->sin_family == AF_INET && sin_dst->sin_family == AF_INET); sc = var->lv_softc; if (sc == NULL) return ENETUNREACH; ifp = &sc->l2tp_ec.ec_if; error = l2tp_check_nesting(ifp, m); if (error) { m_freem(m); goto looped; } #ifdef NETYET /* TODO: support ALTQ for innner frame */ #ifdef ALTQ ALTQ_SAVE_PAYLOAD(m, AF_ETHER); #endif #endif memset(&iphdr, 0, sizeof(iphdr)); iphdr.ip_src = sin_src->sin_addr; /* bidirectional configured tunnel mode */ if (sin_dst->sin_addr.s_addr != INADDR_ANY) iphdr.ip_dst = sin_dst->sin_addr; else { m_freem(m); if ((ifp->if_flags & IFF_DEBUG) != 0) log(LOG_DEBUG, "%s: ENETUNREACH\n", __func__); error = ENETUNREACH; goto out; } iphdr.ip_p = IPPROTO_L2TP; /* version will be set in ip_output() */ iphdr.ip_ttl = ip_l2tp_ttl; /* outer IP header length */ iphdr.ip_len = sizeof(struct ip); /* session-id length */ iphdr.ip_len += sizeof(uint32_t); if (var->lv_use_cookie == L2TP_COOKIE_ON) { /* cookie length */ iphdr.ip_len += var->lv_peer_cookie_len; } /* TODO: IP_TCPMSS support */ #ifdef IP_TCPMSS m = l2tp_tcpmss_clamp(ifp, m); if (m == NULL) { error = EINVAL; goto out; } #endif /* * payload length * NOTE: Payload length may be changed in ip_tcpmss(). * Typical case is missing of TCP mss option in original * TCP header. */ iphdr.ip_len += m->m_pkthdr.len; HTONS(iphdr.ip_len); if (var->lv_use_cookie == L2TP_COOKIE_ON) { /* prepend session cookie */ uint32_t cookie_32; uint64_t cookie_64; M_PREPEND(m, var->lv_peer_cookie_len, M_DONTWAIT); if (m && m->m_len < var->lv_peer_cookie_len) m = m_pullup(m, var->lv_peer_cookie_len); if (m == NULL) { error = ENOBUFS; goto out; } if (var->lv_peer_cookie_len == 4) { cookie_32 = htonl((uint32_t)var->lv_peer_cookie); memcpy(mtod(m, void *), &cookie_32, sizeof(uint32_t)); } else { cookie_64 = htobe64(var->lv_peer_cookie); memcpy(mtod(m, void *), &cookie_64, sizeof(uint64_t)); } } /* prepend session-ID */ sess_id = htonl(var->lv_peer_sess_id); M_PREPEND(m, sizeof(uint32_t), M_DONTWAIT); if (m && m->m_len < sizeof(uint32_t)) m = m_pullup(m, sizeof(uint32_t)); if (m == NULL) { error = ENOBUFS; goto out; } memcpy(mtod(m, uint32_t *), &sess_id, sizeof(uint32_t)); /* prepend new IP header */ M_PREPEND(m, sizeof(struct ip), M_DONTWAIT); if (IP_HDR_ALIGNED_P(mtod(m, void *)) == 0) { if (m) m = m_copyup(m, sizeof(struct ip), 0); } else { if (m && m->m_len < sizeof(struct ip)) m = m_pullup(m, sizeof(struct ip)); } if (m == NULL) { error = ENOBUFS; goto out; } memcpy(mtod(m, struct ip *), &iphdr, sizeof(struct ip)); lro = percpu_getref(sc->l2tp_ro_percpu); mutex_enter(&lro->lr_lock); if ((rt = rtcache_lookup(&lro->lr_ro, var->lv_pdst)) == NULL) { mutex_exit(&lro->lr_lock); percpu_putref(sc->l2tp_ro_percpu); m_freem(m); error = ENETUNREACH; goto out; } if (rt->rt_ifp == ifp) { rtcache_unref(rt, &lro->lr_ro); rtcache_free(&lro->lr_ro); mutex_exit(&lro->lr_lock); percpu_putref(sc->l2tp_ro_percpu); m_freem(m); error = ENETUNREACH; /*XXX*/ goto out; } rtcache_unref(rt, &lro->lr_ro); /* * To avoid inappropriate rewrite of checksum, * clear csum flags. */ m->m_pkthdr.csum_flags = 0; error = ip_output(m, NULL, &lro->lr_ro, 0, NULL, NULL); mutex_exit(&lro->lr_lock); percpu_putref(sc->l2tp_ro_percpu); return error; looped: if (error) ifp->if_oerrors++; out: return error; } static void in_l2tp_input(struct mbuf *m, int off, int proto) { struct ifnet *l2tpp = NULL; struct l2tp_softc *sc; uint32_t sess_id; uint32_t cookie_32; uint64_t cookie_64; struct psref psref; struct l2tp_variant *var; if (m->m_len < off + sizeof(uint32_t)) { m = m_pullup(m, off + sizeof(uint32_t)); if (!m) { /* if payload length < 4 octets */ return; } } /* get L2TP session ID */ m_copydata(m, off, sizeof(uint32_t), (void *)&sess_id); NTOHL(sess_id); #ifdef L2TP_DEBUG log(LOG_DEBUG, "%s: sess_id = %" PRIu32 "\n", __func__, sess_id); #endif if (sess_id == 0) { /* * L2TPv3 control packet received. * userland daemon(l2tpd?) should process. */ rip_input(m, off, proto); return; } var = l2tp_lookup_session_ref(sess_id, &psref); if (var == NULL) { m_freem(m); ip_statinc(IP_STAT_NOL2TP); return; } else { sc = var->lv_softc; l2tpp = &(sc->l2tp_ec.ec_if); if (l2tpp == NULL || (l2tpp->if_flags & IFF_UP) == 0) { #ifdef L2TP_DEBUG if (l2tpp == NULL) log(LOG_DEBUG, "%s: l2tpp is NULL\n", __func__); else log(LOG_DEBUG, "%s: l2tpp is down\n", __func__); #endif m_freem(m); ip_statinc(IP_STAT_NOL2TP); goto out; } /* other CPU do l2tp_delete_tunnel */ if (var->lv_psrc == NULL || var->lv_pdst == NULL) { m_freem(m); ip_statinc(IP_STAT_NOL2TP); goto out; } } if (var->lv_state != L2TP_STATE_UP) { m_freem(m); goto out; } m_adj(m, off + sizeof(uint32_t)); if (var->lv_use_cookie == L2TP_COOKIE_ON) { if (var->lv_my_cookie_len == 4) { m_copydata(m, 0, sizeof(uint32_t), (void *)&cookie_32); NTOHL(cookie_32); if (cookie_32 != var->lv_my_cookie) { m_freem(m); goto out; } m_adj(m, sizeof(uint32_t)); } else { m_copydata(m, 0, sizeof(uint64_t), (void *)&cookie_64); BE64TOH(cookie_64); if (cookie_64 != var->lv_my_cookie) { m_freem(m); goto out; } m_adj(m, sizeof(uint64_t)); } } /* TODO: IP_TCPMSS support */ #ifdef IP_TCPMSS m = l2tp_tcpmss_clamp(l2tpp, m); if (m == NULL) goto out; #endif l2tp_input(m, l2tpp); out: l2tp_putref_variant(var, &psref); return; } /* * This function is used by encap4_lookup() to decide priority of the encaptab. * This priority is compared to the match length between mbuf's source/destination * IPv4 address pair and encaptab's one. * l2tp(4) does not use address pairs to search matched encaptab, so this * function must return the length bigger than or equals to IPv4 address pair to * avoid wrong encaptab. */ static int in_l2tp_match(struct mbuf *m, int off, int proto, void *arg) { struct l2tp_variant *var = arg; uint32_t sess_id; KASSERT(proto == IPPROTO_L2TP); if (m->m_len < off + sizeof(uint32_t)) { m = m_pullup(m, off + sizeof(uint32_t)); if (!m) { /* if payload length < 4 octets */ return 0; } } /* get L2TP session ID */ m_copydata(m, off, sizeof(uint32_t), (void *)&sess_id); NTOHL(sess_id); if (sess_id == 0) { /* * L2TPv3 control packet received. * userland daemon(l2tpd?) should process. */ return 32 * 2; } else if (sess_id == var->lv_my_sess_id) return 32 * 2; else return 0; } int in_l2tp_attach(struct l2tp_variant *var) { var->lv_encap_cookie = encap_attach_func(AF_INET, IPPROTO_L2TP, in_l2tp_match, &in_l2tp_encapsw, var); if (var->lv_encap_cookie == NULL) return EEXIST; return 0; } int in_l2tp_detach(struct l2tp_variant *var) { int error; error = encap_detach(var->lv_encap_cookie); if (error == 0) var->lv_encap_cookie = NULL; return error; } @ 1.2 log @remove duplicated validation. That is already done in l2tp_lookup_session_ref(). pointed out by s-yamaguchi@@IIJ, thanks. @ text @d1 1 a1 1 /* $NetBSD: in_l2tp.c,v 1.1 2017/02/16 08:23:35 knakahara Exp $ */ d30 1 a30 1 __KERNEL_RCSID(0, "$NetBSD: in_l2tp.c,v 1.1 2017/02/16 08:23:35 knakahara Exp $"); d111 2 a112 1 if (error) d114 1 @ 1.2.8.1 log @Pull up following revision(s) (requested by knakahara in ticket #121): sys/netinet6/in6_l2tp.c: revision 1.6 sys/netinet/in_l2tp.c: revision 1.3 l2tp(4): fix mbuf leak when tunnel nested over the limit XXX need pullup -8 branch @ text @d1 1 a1 1 /* $NetBSD: in_l2tp.c,v 1.2 2017/03/30 23:13:54 knakahara Exp $ */ d30 1 a30 1 __KERNEL_RCSID(0, "$NetBSD: in_l2tp.c,v 1.2 2017/03/30 23:13:54 knakahara Exp $"); d111 1 a111 2 if (error) { m_freem(m); a112 1 } @ 1.2.8.2 log @Pull up following revision(s) (requested by knakahara in ticket #419): sys/net/if_stf.c: revision 1.103 sys/net/if_stf.h: revision 1.8 sys/netinet/in_gif.c: revision 1.89 sys/netinet/in_gif.h: revision 1.17 sys/netinet/in_l2tp.c: revision 1.4 sys/netinet/ip_encap.c: revision 1.66 sys/netinet/ip_encap.h: revision 1.23 sys/netinet/ip_mroute.c: revision 1.148 sys/netinet6/in6_gif.c: revision 1.87 sys/netinet6/in6_gif.h: revision 1.16 sys/netinet6/in6_l2tp.c: revision 1.7 sys/netipsec/xform.h: revision 1.13 sys/netipsec/xform_ipip.c: revision 1.55 Add argument to encapsw->pr_input() instead of m_tag. @ text @d1 1 a1 1 /* $NetBSD: in_l2tp.c,v 1.2.8.1 2017/07/12 13:42:11 martin Exp $ */ d30 1 a30 1 __KERNEL_RCSID(0, "$NetBSD: in_l2tp.c,v 1.2.8.1 2017/07/12 13:42:11 martin Exp $"); d75 1 a75 1 static void in_l2tp_input(struct mbuf *, int, int, void *); d253 1 a253 1 in_l2tp_input(struct mbuf *m, int off, int proto, void *eparg __unused) @ 1.2.8.3 log @Pull up following revision(s) (requested by knakahara in ticket #461): sys/netinet/in_l2tp.c: revision 1.9 sys/netinet6/in6_l2tp.c: revision 1.12 fix mbuf leaks. pointed out and suggested by kre@@n.o, thanks. @ text @d1 1 a1 1 /* $NetBSD: in_l2tp.c,v 1.2.8.2 2017/12/10 09:41:31 snj Exp $ */ d30 1 a30 1 __KERNEL_RCSID(0, "$NetBSD: in_l2tp.c,v 1.2.8.2 2017/12/10 09:41:31 snj Exp $"); d371 7 a377 5 /* * If the packet contains no session ID it cannot match */ if (m_length(m) < off + sizeof(uint32_t)) return 0; @ 1.2.8.4 log @Pull up following revision(s) (requested by knakahara in ticket #614): sys/net/if_l2tp.c: revision 1.20 sys/netinet6/in6_l2tp.c: revision 1.13 sys/netinet6/in6_l2tp.c: revision 1.14 sys/net/if_l2tp.h: revision 1.3 sys/net/if_l2tp.c: revision 1.13 sys/netinet/in_l2tp.c: revision 1.10 sys/net/if_l2tp.c: revision 1.18 sys/netinet/in_l2tp.c: revision 1.11 sys/net/if_l2tp.c: revision 1.19 sys/netinet/in_l2tp.c: revision 1.12 If if_attach() failed in the attach function, return. Add comments about if_initialize(). suggested by ozaki-r@@n.o. Fix null deref, m could be NULL if M_PREPEND fails. style Style, reduce the indentation level when possible, and add a missing NULL check after M_PREPEND. Several fixes in L2TP: * l2tp_input(): use m_copydata, and ensure there is enough space in the chain. Otherwise overflow. * l2tp_tcpmss_clamp(): ensure there is enough space in the chain. * in_l2tp_output(): don't check 'sc' against NULL, it can't be NULL. * in_l2tp_input(): no need to call m_pullup since we use m_copydata. Just check the space in the chain. * in_l2tp_input(): if there is a cookie, make sure the chain has enough space. * in6_l2tp_input(): same changes as in_l2tp_input(). Ok knakahara@@ Use MH_ALIGN instead, ok knakahara@@. @ text @d1 1 a1 1 /* $NetBSD: in_l2tp.c,v 1.2.8.3 2018/01/02 10:39:57 snj Exp $ */ d30 1 a30 1 __KERNEL_RCSID(0, "$NetBSD: in_l2tp.c,v 1.2.8.3 2018/01/02 10:39:57 snj Exp $"); d106 3 d116 1 a116 10 /* bidirectional configured tunnel mode */ if (sin_dst->sin_addr.s_addr == INADDR_ANY) { m_freem(m); if ((ifp->if_flags & IFF_DEBUG) != 0) log(LOG_DEBUG, "%s: ENETUNREACH\n", __func__); error = ENETUNREACH; goto out; } #ifdef NOTYET d125 10 a134 1 iphdr.ip_dst = sin_dst->sin_addr; a154 1 d156 4 a159 4 * Payload length. * * NOTE: payload length may be changed in ip_tcpmss(). Typical case * is missing of TCP mss option in original TCP header. d177 2 a178 1 memcpy(mtod(m, void *), &cookie_32, sizeof(uint32_t)); d181 2 a182 1 memcpy(mtod(m, void *), &cookie_64, sizeof(uint64_t)); a198 4 if (m == NULL) { error = ENOBUFS; goto out; } d200 2 a201 1 m = m_copyup(m, sizeof(struct ip), 0); d203 1 a203 1 if (m->m_len < sizeof(struct ip)) d263 7 a269 6 KASSERT((m->m_flags & M_PKTHDR) != 0); if (m->m_pkthdr.len < off + sizeof(uint32_t)) { m_freem(m); return; } d291 3 a293 4 } sc = var->lv_softc; l2tpp = &(sc->l2tp_ec.ec_if); d295 1 a295 1 if (l2tpp == NULL || (l2tpp->if_flags & IFF_UP) == 0) { d297 4 a300 4 if (l2tpp == NULL) log(LOG_DEBUG, "%s: l2tpp is NULL\n", __func__); else log(LOG_DEBUG, "%s: l2tpp is down\n", __func__); d302 4 a305 4 m_freem(m); ip_statinc(IP_STAT_NOL2TP); goto out; } d307 6 a312 5 /* other CPU did l2tp_delete_tunnel */ if (var->lv_psrc == NULL || var->lv_pdst == NULL) { m_freem(m); ip_statinc(IP_STAT_NOL2TP); goto out; a322 4 if (m->m_pkthdr.len < var->lv_my_cookie_len) { m_freem(m); goto out; } @ 1.2.8.5 log @Pull up following revision(s) (requested by knakahara in ticket #829): sys/net/if_l2tp.c: revision 1.24 sys/net/if_ipsec.c: revision 1.13 sys/net/if_gif.h: revision 1.31 sys/netipsec/ipsecif.c: revision 1.8 sys/net/if_gif.c: revision 1.140 sys/netinet6/in6_l2tp.c: revision 1.15 sys/net/if_ipsec.h: revision 1.3 sys/netinet6/in6_gif.c: revision 1.92 sys/net/if_l2tp.h: revision 1.5 sys/netinet/in_l2tp.c: revision 1.13 sys/netinet/in_gif.c: revision 1.93 Fix LOCKDEBUG kernel panic when many(about 200) tunnel interfaces is created. The tunnel interfaces are gif(4), l2tp(4), and ipsecif(4). They use mutex itself in percpu area. When percpu_cpu_enlarge() run, the address of the mutex in percpu area becomes different from the address which lockdebug saved. That can cause "already initialized" false detection. @ text @d1 1 a1 1 /* $NetBSD: in_l2tp.c,v 1.2.8.4 2018/03/08 13:41:41 martin Exp $ */ d30 1 a30 1 __KERNEL_RCSID(0, "$NetBSD: in_l2tp.c,v 1.2.8.4 2018/03/08 13:41:41 martin Exp $"); d212 1 a212 1 mutex_enter(lro->lr_lock); d214 1 a214 1 mutex_exit(lro->lr_lock); d224 1 a224 1 mutex_exit(lro->lr_lock); d239 1 a239 1 mutex_exit(lro->lr_lock); @ 1.2.8.6 log @Pull up following revision(s) via patch (requested by knakahara in ticket #905): sys/netinet/ip_mroute.c: revision 1.160 sys/netinet6/in6_l2tp.c: revision 1.16 sys/net/if.h: revision 1.263 sys/netinet/in_l2tp.c: revision 1.15 sys/netinet/ip_icmp.c: revision 1.172 sys/netinet/igmp.c: revision 1.68 sys/netinet/ip_encap.c: revision 1.69 sys/netinet6/ip6_mroute.c: revision 1.129 sbappendaddr() is required any lock. Currently, softnet_lock is appropriate. When rip_input() is called as inetsw[].pr_input, rip_iput() is always called with holding softnet_lock, that is, in case of !defined(NET_MPSAFE) it is acquired in ipintr(), otherwise(defined(NET_MPSAFE)) it is acquire in PR_WRAP_INPUT macro. However, some function calls rip_input() directly without holding softnet_lock. That causes assertion failure in sbappendaddr(). rip6_input() and icmp6_rip6_input() are also required softnet_lock for the same reason. @ text @d1 1 a1 1 /* $NetBSD: in_l2tp.c,v 1.2.8.5 2018/05/17 14:07:03 martin Exp $ */ d30 1 a30 1 __KERNEL_RCSID(0, "$NetBSD: in_l2tp.c,v 1.2.8.5 2018/05/17 14:07:03 martin Exp $"); a44 1 #include /* For softnet_lock */ a279 1 SOFTNET_LOCK_IF_NET_MPSAFE(); a280 1 SOFTNET_UNLOCK_IF_NET_MPSAFE(); @ 1.2.8.7 log @Pull up following revision(s) (requested by knakahara in ticket #1018): sys/netinet6/in6_l2tp.c: revision 1.17 sys/netinet/in_l2tp.c: revision 1.16 fix: l2tp(4) cannot receive packets after reset session without reset tunnel. Pointed out by k-goda@@IIJ When the following operations are done after established session, the l2tp0 cannot receive packets until done deletetunnel && tunnel "src" "dst". ==================== ifconfig l2tp0 deletesession ifconfig l2tp0 deletecookie ifconfig l2tp0 session 200 100 ==================== XXX pullup-8 @ text @d1 1 a1 1 /* $NetBSD: in_l2tp.c,v 1.2.8.6 2018/07/13 14:26:47 martin Exp $ */ d30 1 a30 1 __KERNEL_RCSID(0, "$NetBSD: in_l2tp.c,v 1.2.8.6 2018/07/13 14:26:47 martin Exp $"); d371 1 a371 3 struct l2tp_softc *sc = arg; struct l2tp_variant *var; struct psref psref; a372 1 int rv = 0; a375 4 var = l2tp_getref_variant(sc, &psref); if (__predict_false(var == NULL)) return rv; d379 2 a380 4 if (m_length(m) < off + sizeof(uint32_t)) { rv = 0; goto out; } d390 1 a390 1 rv = 32 * 2; d392 1 a392 1 rv = 32 * 2; d394 1 a394 5 rv = 0; out: l2tp_putref_variant(var, &psref); return rv; a399 1 struct l2tp_softc *sc = var->lv_softc; a400 2 if (sc == NULL) return EINVAL; d402 1 a402 1 in_l2tp_match, &in_l2tp_encapsw, sc); @ 1.2.8.8 log @Pull up following revision(s) (requested by knakahara in ticket #1385): sys/net/if.c 1.461 sys/net/if.h 1.277 sys/net/if_gif.c 1.149 sys/net/if_gif.h 1.33 sys/net/if_ipsec.c 1.19,1.20,1.24 sys/net/if_ipsec.h 1.5 sys/net/if_l2tp.c 1.33,1.36-1.39 sys/net/if_l2tp.h 1.7,1.8 sys/net/route.c 1.220,1.221 sys/net/route.h 1.125 sys/netinet/in_gif.c 1.95 sys/netinet/in_l2tp.c 1.17 sys/netinet/ip_input.c 1.391,1.392 sys/netinet/wqinput.c 1.6 sys/netinet6/in6_gif.c 1.94 sys/netinet6/in6_l2tp.c 1.18 sys/netinet6/ip6_forward.c 1.97 sys/netinet6/ip6_input.c 1.210,1.211 sys/netipsec/ipsec_output.c 1.82,1.83 (patched) sys/netipsec/ipsecif.c 1.12,1.13,1.15,1.17 (patched) sys/netipsec/key.c 1.259,1.260 ipsecif(4) support input drop packet counter. ipsecif(4) should not increment drop counter by errors not related to if_snd. Pointed out by ozaki-r@@n.o, thanks. Remove unnecessary addresses in PF_KEY message. MOBIKE Extensions for PF_KEY draft-schilcher-mobike-pfkey-extension-01.txt says ==================== 5. SPD Update // snip SADB_X_SPDADD: // snip sadb_x_ipsecrequest_reqid: An ID for that SA can be passed to the kernel in the sadb_x_ipsecrequest_reqid field. If tunnel mode is specified, the sadb_x_ipsecrequest structure is followed by two sockaddr structures that define the tunnel endpoint addresses. In the case that transport mode is used, no additional addresses are specified. ==================== see: https://tools.ietf.org/html/draft-schilcher-mobike-pfkey-extension-01 ipsecif(4) uses transport mode, so it should not add addresses. ipsecif(4) supports multiple peers in the same NAPT. E.g. ipsec0 connects between NetBSD_A and NetBSD_B, ipsec1 connects NetBSD_A and NetBSD_C at the following figure. +----------+ +----| NetBSD_B | +----------+ +------+ | +----------+ | NetBSD_A |--- ... ---| NAPT |---+ +----------+ +------+ | +----------+ +----| NetBSD_C | +----------+ Add ATF later. l2tp(4): fix output bytes counter. Pointed by k-goda@@IIJ, thanks. remove a variable which is no longer used. l2tp: initialize mowner variables for MBUFTRACE Avoid having a rtcache directly in a percpu storage percpu(9) has a certain memory storage for each CPU and provides it by the piece to users. If the storages went short, percpu(9) enlarges them by allocating new larger memory areas, replacing old ones with them and destroying the old ones. A percpu storage referenced by a pointer gotten via percpu_getref can be destroyed by the mechanism after a running thread sleeps even if percpu_putref has not been called. Using rtcache, i.e., packet processing, typically involves sleepable operations such as rwlock so we must avoid dereferencing a rtcache that is directly stored in a percpu storage during packet processing. Address this situation by having just a pointer to a rtcache in a percpu storage instead. Reviewed by knakahara@@ and yamaguchi@@ wqinput: avoid having struct wqinput_worklist directly in a percpu storage percpu(9) has a certain memory storage for each CPU and provides it by the piece to users. If the storages went short, percpu(9) enlarges them by allocating new larger memory areas, replacing old ones with them and destroying the old ones. A percpu storage referenced by a pointer gotten via percpu_getref can be destroyed by the mechanism after a running thread sleeps even if percpu_putref has not been called. Input handlers of wqinput normally involves sleepable operations so we must avoid dereferencing a percpu data (struct wqinput_worklist) after executing an input handler. Address this situation by having just a pointer to the data in a percpu storage instead. Reviewed by knakahara@@ and yamaguchi@@ Add missing #include Divide Tx context of l2tp(4) to improve performance. It seems l2tp(4) call path is too long for instruction cache. So, dividing l2tp(4) Tx context improves CPU use efficiency. After this commit, l2tp(4) throughput gains 10% on my machine(Atom C3000). Apply some missing changes lost on the previous commit Avoid having a rtcache directly in a percpu storage for tunnel protocols. percpu(9) has a certain memory storage for each CPU and provides it by the piece to users. If the storages went short, percpu(9) enlarges them by allocating new larger memory areas, replacing old ones with them and destroying the old ones. A percpu storage referenced by a pointer gotten via percpu_getref can be destroyed by the mechanism after a running thread sleeps even if percpu_putref has not been called. Using rtcache, i.e., packet processing, typically involves sleepable operations such as rwlock so we must avoid dereferencing a rtcache that is directly stored in a percpu storage during packet processing. Address this situation by having just a pointer to a rtcache in a percpu storage instead. Reviewed by ozaki-r@@ and yamaguchi@@ l2tp(4): avoid having struct ifqueue directly in a percpu storage. percpu(9) has a certain memory storage for each CPU and provides it by the piece to users. If the storages went short, percpu(9) enlarges them by allocating new larger memory areas, replacing old ones with them and destroying the old ones. A percpu storage referenced by a pointer gotten via percpu_getref can be destroyed by the mechanism after a running thread sleeps even if percpu_putref has not been called. Tx processing of l2tp(4) uses normally involves sleepable operations so we must avoid dereferencing a percpu data (struct ifqueue) after executing Tx processing. Address this situation by having just a pointer to the data in a percpu storage instead. Reviewed by ozaki-r@@ and yamaguchi@@ @ text @d1 1 a1 1 /* $NetBSD: in_l2tp.c,v 1.2.8.7 2018/09/10 15:58:47 martin Exp $ */ d30 1 a30 1 __KERNEL_RCSID(0, "$NetBSD: in_l2tp.c,v 1.2.8.7 2018/09/10 15:58:47 martin Exp $"); d96 1 a96 3 struct route *ro_pc; kmutex_t *lock_pc; d212 5 a216 3 if_tunnel_get_ro(sc->l2tp_ro_percpu, &ro_pc, &lock_pc); if ((rt = rtcache_lookup(ro_pc, var->lv_pdst)) == NULL) { if_tunnel_put_ro(sc->l2tp_ro_percpu, lock_pc); d223 4 a226 3 rtcache_unref(rt, ro_pc); rtcache_free(ro_pc); if_tunnel_put_ro(sc->l2tp_ro_percpu, lock_pc); d231 1 a231 1 rtcache_unref(rt, ro_pc); d239 3 a241 2 error = ip_output(m, NULL, ro_pc, 0, NULL, NULL); if_tunnel_put_ro(sc->l2tp_ro_percpu, lock_pc); @ 1.2.4.1 log @file in_l2tp.c was added on branch bouyer-socketcan on 2017-04-21 16:54:05 +0000 @ text @d1 414 @ 1.2.4.2 log @Sync with HEAD @ text @a0 414 /* $NetBSD: in_l2tp.c,v 1.2 2017/03/30 23:13:54 knakahara Exp $ */ /* * Copyright (c) 2017 Internet Initiative Japan Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include __KERNEL_RCSID(0, "$NetBSD: in_l2tp.c,v 1.2 2017/03/30 23:13:54 knakahara Exp $"); #ifdef _KERNEL_OPT #include "opt_l2tp.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef ALTQ #include #endif /* TODO: IP_TCPMSS support */ #undef IP_TCPMSS #ifdef IP_TCPMSS #include #endif #include #include int ip_l2tp_ttl = L2TP_TTL; static void in_l2tp_input(struct mbuf *, int, int); static const struct encapsw in_l2tp_encapsw = { .encapsw4 = { .pr_input = in_l2tp_input, .pr_ctlinput = NULL, } }; static int in_l2tp_match(struct mbuf *, int, int, void *); int in_l2tp_output(struct l2tp_variant *var, struct mbuf *m) { struct l2tp_softc *sc; struct ifnet *ifp; struct sockaddr_in *sin_src = satosin(var->lv_psrc); struct sockaddr_in *sin_dst = satosin(var->lv_pdst); struct ip iphdr; /* capsule IP header, host byte ordered */ struct rtentry *rt; struct l2tp_ro *lro; int error; uint32_t sess_id; KASSERT(var != NULL); KASSERT(l2tp_heldref_variant(var)); KASSERT(sin_src != NULL && sin_dst != NULL); KASSERT(sin_src->sin_family == AF_INET && sin_dst->sin_family == AF_INET); sc = var->lv_softc; if (sc == NULL) return ENETUNREACH; ifp = &sc->l2tp_ec.ec_if; error = l2tp_check_nesting(ifp, m); if (error) goto looped; #ifdef NETYET /* TODO: support ALTQ for innner frame */ #ifdef ALTQ ALTQ_SAVE_PAYLOAD(m, AF_ETHER); #endif #endif memset(&iphdr, 0, sizeof(iphdr)); iphdr.ip_src = sin_src->sin_addr; /* bidirectional configured tunnel mode */ if (sin_dst->sin_addr.s_addr != INADDR_ANY) iphdr.ip_dst = sin_dst->sin_addr; else { m_freem(m); if ((ifp->if_flags & IFF_DEBUG) != 0) log(LOG_DEBUG, "%s: ENETUNREACH\n", __func__); error = ENETUNREACH; goto out; } iphdr.ip_p = IPPROTO_L2TP; /* version will be set in ip_output() */ iphdr.ip_ttl = ip_l2tp_ttl; /* outer IP header length */ iphdr.ip_len = sizeof(struct ip); /* session-id length */ iphdr.ip_len += sizeof(uint32_t); if (var->lv_use_cookie == L2TP_COOKIE_ON) { /* cookie length */ iphdr.ip_len += var->lv_peer_cookie_len; } /* TODO: IP_TCPMSS support */ #ifdef IP_TCPMSS m = l2tp_tcpmss_clamp(ifp, m); if (m == NULL) { error = EINVAL; goto out; } #endif /* * payload length * NOTE: Payload length may be changed in ip_tcpmss(). * Typical case is missing of TCP mss option in original * TCP header. */ iphdr.ip_len += m->m_pkthdr.len; HTONS(iphdr.ip_len); if (var->lv_use_cookie == L2TP_COOKIE_ON) { /* prepend session cookie */ uint32_t cookie_32; uint64_t cookie_64; M_PREPEND(m, var->lv_peer_cookie_len, M_DONTWAIT); if (m && m->m_len < var->lv_peer_cookie_len) m = m_pullup(m, var->lv_peer_cookie_len); if (m == NULL) { error = ENOBUFS; goto out; } if (var->lv_peer_cookie_len == 4) { cookie_32 = htonl((uint32_t)var->lv_peer_cookie); memcpy(mtod(m, void *), &cookie_32, sizeof(uint32_t)); } else { cookie_64 = htobe64(var->lv_peer_cookie); memcpy(mtod(m, void *), &cookie_64, sizeof(uint64_t)); } } /* prepend session-ID */ sess_id = htonl(var->lv_peer_sess_id); M_PREPEND(m, sizeof(uint32_t), M_DONTWAIT); if (m && m->m_len < sizeof(uint32_t)) m = m_pullup(m, sizeof(uint32_t)); if (m == NULL) { error = ENOBUFS; goto out; } memcpy(mtod(m, uint32_t *), &sess_id, sizeof(uint32_t)); /* prepend new IP header */ M_PREPEND(m, sizeof(struct ip), M_DONTWAIT); if (IP_HDR_ALIGNED_P(mtod(m, void *)) == 0) { if (m) m = m_copyup(m, sizeof(struct ip), 0); } else { if (m && m->m_len < sizeof(struct ip)) m = m_pullup(m, sizeof(struct ip)); } if (m == NULL) { error = ENOBUFS; goto out; } memcpy(mtod(m, struct ip *), &iphdr, sizeof(struct ip)); lro = percpu_getref(sc->l2tp_ro_percpu); mutex_enter(&lro->lr_lock); if ((rt = rtcache_lookup(&lro->lr_ro, var->lv_pdst)) == NULL) { mutex_exit(&lro->lr_lock); percpu_putref(sc->l2tp_ro_percpu); m_freem(m); error = ENETUNREACH; goto out; } if (rt->rt_ifp == ifp) { rtcache_unref(rt, &lro->lr_ro); rtcache_free(&lro->lr_ro); mutex_exit(&lro->lr_lock); percpu_putref(sc->l2tp_ro_percpu); m_freem(m); error = ENETUNREACH; /*XXX*/ goto out; } rtcache_unref(rt, &lro->lr_ro); /* * To avoid inappropriate rewrite of checksum, * clear csum flags. */ m->m_pkthdr.csum_flags = 0; error = ip_output(m, NULL, &lro->lr_ro, 0, NULL, NULL); mutex_exit(&lro->lr_lock); percpu_putref(sc->l2tp_ro_percpu); return error; looped: if (error) ifp->if_oerrors++; out: return error; } static void in_l2tp_input(struct mbuf *m, int off, int proto) { struct ifnet *l2tpp = NULL; struct l2tp_softc *sc; uint32_t sess_id; uint32_t cookie_32; uint64_t cookie_64; struct psref psref; struct l2tp_variant *var; if (m->m_len < off + sizeof(uint32_t)) { m = m_pullup(m, off + sizeof(uint32_t)); if (!m) { /* if payload length < 4 octets */ return; } } /* get L2TP session ID */ m_copydata(m, off, sizeof(uint32_t), (void *)&sess_id); NTOHL(sess_id); #ifdef L2TP_DEBUG log(LOG_DEBUG, "%s: sess_id = %" PRIu32 "\n", __func__, sess_id); #endif if (sess_id == 0) { /* * L2TPv3 control packet received. * userland daemon(l2tpd?) should process. */ rip_input(m, off, proto); return; } var = l2tp_lookup_session_ref(sess_id, &psref); if (var == NULL) { m_freem(m); ip_statinc(IP_STAT_NOL2TP); return; } else { sc = var->lv_softc; l2tpp = &(sc->l2tp_ec.ec_if); if (l2tpp == NULL || (l2tpp->if_flags & IFF_UP) == 0) { #ifdef L2TP_DEBUG if (l2tpp == NULL) log(LOG_DEBUG, "%s: l2tpp is NULL\n", __func__); else log(LOG_DEBUG, "%s: l2tpp is down\n", __func__); #endif m_freem(m); ip_statinc(IP_STAT_NOL2TP); goto out; } /* other CPU do l2tp_delete_tunnel */ if (var->lv_psrc == NULL || var->lv_pdst == NULL) { m_freem(m); ip_statinc(IP_STAT_NOL2TP); goto out; } } if (var->lv_state != L2TP_STATE_UP) { m_freem(m); goto out; } m_adj(m, off + sizeof(uint32_t)); if (var->lv_use_cookie == L2TP_COOKIE_ON) { if (var->lv_my_cookie_len == 4) { m_copydata(m, 0, sizeof(uint32_t), (void *)&cookie_32); NTOHL(cookie_32); if (cookie_32 != var->lv_my_cookie) { m_freem(m); goto out; } m_adj(m, sizeof(uint32_t)); } else { m_copydata(m, 0, sizeof(uint64_t), (void *)&cookie_64); BE64TOH(cookie_64); if (cookie_64 != var->lv_my_cookie) { m_freem(m); goto out; } m_adj(m, sizeof(uint64_t)); } } /* TODO: IP_TCPMSS support */ #ifdef IP_TCPMSS m = l2tp_tcpmss_clamp(l2tpp, m); if (m == NULL) goto out; #endif l2tp_input(m, l2tpp); out: l2tp_putref_variant(var, &psref); return; } /* * This function is used by encap4_lookup() to decide priority of the encaptab. * This priority is compared to the match length between mbuf's source/destination * IPv4 address pair and encaptab's one. * l2tp(4) does not use address pairs to search matched encaptab, so this * function must return the length bigger than or equals to IPv4 address pair to * avoid wrong encaptab. */ static int in_l2tp_match(struct mbuf *m, int off, int proto, void *arg) { struct l2tp_variant *var = arg; uint32_t sess_id; KASSERT(proto == IPPROTO_L2TP); if (m->m_len < off + sizeof(uint32_t)) { m = m_pullup(m, off + sizeof(uint32_t)); if (!m) { /* if payload length < 4 octets */ return 0; } } /* get L2TP session ID */ m_copydata(m, off, sizeof(uint32_t), (void *)&sess_id); NTOHL(sess_id); if (sess_id == 0) { /* * L2TPv3 control packet received. * userland daemon(l2tpd?) should process. */ return 32 * 2; } else if (sess_id == var->lv_my_sess_id) return 32 * 2; else return 0; } int in_l2tp_attach(struct l2tp_variant *var) { var->lv_encap_cookie = encap_attach_func(AF_INET, IPPROTO_L2TP, in_l2tp_match, &in_l2tp_encapsw, var); if (var->lv_encap_cookie == NULL) return EEXIST; return 0; } int in_l2tp_detach(struct l2tp_variant *var) { int error; error = encap_detach(var->lv_encap_cookie); if (error == 0) var->lv_encap_cookie = NULL; return error; } @ 1.1 log @add missing files. @ text @d1 1 a1 1 /* $NetBSD$ */ d30 1 a30 1 __KERNEL_RCSID(0, "$NetBSD$"); a317 5 if (sess_id != var->lv_my_sess_id) { m_freem(m); goto out; } @ 1.1.2.1 log @file in_l2tp.c was added on branch pgoyette-localcount on 2017-03-20 06:57:50 +0000 @ text @d1 419 @ 1.1.2.2 log @Sync with HEAD @ text @a0 419 /* $NetBSD: in_l2tp.c,v 1.1 2017/02/16 08:23:35 knakahara Exp $ */ /* * Copyright (c) 2017 Internet Initiative Japan Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include __KERNEL_RCSID(0, "$NetBSD: in_l2tp.c,v 1.1 2017/02/16 08:23:35 knakahara Exp $"); #ifdef _KERNEL_OPT #include "opt_l2tp.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef ALTQ #include #endif /* TODO: IP_TCPMSS support */ #undef IP_TCPMSS #ifdef IP_TCPMSS #include #endif #include #include int ip_l2tp_ttl = L2TP_TTL; static void in_l2tp_input(struct mbuf *, int, int); static const struct encapsw in_l2tp_encapsw = { .encapsw4 = { .pr_input = in_l2tp_input, .pr_ctlinput = NULL, } }; static int in_l2tp_match(struct mbuf *, int, int, void *); int in_l2tp_output(struct l2tp_variant *var, struct mbuf *m) { struct l2tp_softc *sc; struct ifnet *ifp; struct sockaddr_in *sin_src = satosin(var->lv_psrc); struct sockaddr_in *sin_dst = satosin(var->lv_pdst); struct ip iphdr; /* capsule IP header, host byte ordered */ struct rtentry *rt; struct l2tp_ro *lro; int error; uint32_t sess_id; KASSERT(var != NULL); KASSERT(l2tp_heldref_variant(var)); KASSERT(sin_src != NULL && sin_dst != NULL); KASSERT(sin_src->sin_family == AF_INET && sin_dst->sin_family == AF_INET); sc = var->lv_softc; if (sc == NULL) return ENETUNREACH; ifp = &sc->l2tp_ec.ec_if; error = l2tp_check_nesting(ifp, m); if (error) goto looped; #ifdef NETYET /* TODO: support ALTQ for innner frame */ #ifdef ALTQ ALTQ_SAVE_PAYLOAD(m, AF_ETHER); #endif #endif memset(&iphdr, 0, sizeof(iphdr)); iphdr.ip_src = sin_src->sin_addr; /* bidirectional configured tunnel mode */ if (sin_dst->sin_addr.s_addr != INADDR_ANY) iphdr.ip_dst = sin_dst->sin_addr; else { m_freem(m); if ((ifp->if_flags & IFF_DEBUG) != 0) log(LOG_DEBUG, "%s: ENETUNREACH\n", __func__); error = ENETUNREACH; goto out; } iphdr.ip_p = IPPROTO_L2TP; /* version will be set in ip_output() */ iphdr.ip_ttl = ip_l2tp_ttl; /* outer IP header length */ iphdr.ip_len = sizeof(struct ip); /* session-id length */ iphdr.ip_len += sizeof(uint32_t); if (var->lv_use_cookie == L2TP_COOKIE_ON) { /* cookie length */ iphdr.ip_len += var->lv_peer_cookie_len; } /* TODO: IP_TCPMSS support */ #ifdef IP_TCPMSS m = l2tp_tcpmss_clamp(ifp, m); if (m == NULL) { error = EINVAL; goto out; } #endif /* * payload length * NOTE: Payload length may be changed in ip_tcpmss(). * Typical case is missing of TCP mss option in original * TCP header. */ iphdr.ip_len += m->m_pkthdr.len; HTONS(iphdr.ip_len); if (var->lv_use_cookie == L2TP_COOKIE_ON) { /* prepend session cookie */ uint32_t cookie_32; uint64_t cookie_64; M_PREPEND(m, var->lv_peer_cookie_len, M_DONTWAIT); if (m && m->m_len < var->lv_peer_cookie_len) m = m_pullup(m, var->lv_peer_cookie_len); if (m == NULL) { error = ENOBUFS; goto out; } if (var->lv_peer_cookie_len == 4) { cookie_32 = htonl((uint32_t)var->lv_peer_cookie); memcpy(mtod(m, void *), &cookie_32, sizeof(uint32_t)); } else { cookie_64 = htobe64(var->lv_peer_cookie); memcpy(mtod(m, void *), &cookie_64, sizeof(uint64_t)); } } /* prepend session-ID */ sess_id = htonl(var->lv_peer_sess_id); M_PREPEND(m, sizeof(uint32_t), M_DONTWAIT); if (m && m->m_len < sizeof(uint32_t)) m = m_pullup(m, sizeof(uint32_t)); if (m == NULL) { error = ENOBUFS; goto out; } memcpy(mtod(m, uint32_t *), &sess_id, sizeof(uint32_t)); /* prepend new IP header */ M_PREPEND(m, sizeof(struct ip), M_DONTWAIT); if (IP_HDR_ALIGNED_P(mtod(m, void *)) == 0) { if (m) m = m_copyup(m, sizeof(struct ip), 0); } else { if (m && m->m_len < sizeof(struct ip)) m = m_pullup(m, sizeof(struct ip)); } if (m == NULL) { error = ENOBUFS; goto out; } memcpy(mtod(m, struct ip *), &iphdr, sizeof(struct ip)); lro = percpu_getref(sc->l2tp_ro_percpu); mutex_enter(&lro->lr_lock); if ((rt = rtcache_lookup(&lro->lr_ro, var->lv_pdst)) == NULL) { mutex_exit(&lro->lr_lock); percpu_putref(sc->l2tp_ro_percpu); m_freem(m); error = ENETUNREACH; goto out; } if (rt->rt_ifp == ifp) { rtcache_unref(rt, &lro->lr_ro); rtcache_free(&lro->lr_ro); mutex_exit(&lro->lr_lock); percpu_putref(sc->l2tp_ro_percpu); m_freem(m); error = ENETUNREACH; /*XXX*/ goto out; } rtcache_unref(rt, &lro->lr_ro); /* * To avoid inappropriate rewrite of checksum, * clear csum flags. */ m->m_pkthdr.csum_flags = 0; error = ip_output(m, NULL, &lro->lr_ro, 0, NULL, NULL); mutex_exit(&lro->lr_lock); percpu_putref(sc->l2tp_ro_percpu); return error; looped: if (error) ifp->if_oerrors++; out: return error; } static void in_l2tp_input(struct mbuf *m, int off, int proto) { struct ifnet *l2tpp = NULL; struct l2tp_softc *sc; uint32_t sess_id; uint32_t cookie_32; uint64_t cookie_64; struct psref psref; struct l2tp_variant *var; if (m->m_len < off + sizeof(uint32_t)) { m = m_pullup(m, off + sizeof(uint32_t)); if (!m) { /* if payload length < 4 octets */ return; } } /* get L2TP session ID */ m_copydata(m, off, sizeof(uint32_t), (void *)&sess_id); NTOHL(sess_id); #ifdef L2TP_DEBUG log(LOG_DEBUG, "%s: sess_id = %" PRIu32 "\n", __func__, sess_id); #endif if (sess_id == 0) { /* * L2TPv3 control packet received. * userland daemon(l2tpd?) should process. */ rip_input(m, off, proto); return; } var = l2tp_lookup_session_ref(sess_id, &psref); if (var == NULL) { m_freem(m); ip_statinc(IP_STAT_NOL2TP); return; } else { sc = var->lv_softc; l2tpp = &(sc->l2tp_ec.ec_if); if (l2tpp == NULL || (l2tpp->if_flags & IFF_UP) == 0) { #ifdef L2TP_DEBUG if (l2tpp == NULL) log(LOG_DEBUG, "%s: l2tpp is NULL\n", __func__); else log(LOG_DEBUG, "%s: l2tpp is down\n", __func__); #endif m_freem(m); ip_statinc(IP_STAT_NOL2TP); goto out; } /* other CPU do l2tp_delete_tunnel */ if (var->lv_psrc == NULL || var->lv_pdst == NULL) { m_freem(m); ip_statinc(IP_STAT_NOL2TP); goto out; } } if (var->lv_state != L2TP_STATE_UP) { m_freem(m); goto out; } if (sess_id != var->lv_my_sess_id) { m_freem(m); goto out; } m_adj(m, off + sizeof(uint32_t)); if (var->lv_use_cookie == L2TP_COOKIE_ON) { if (var->lv_my_cookie_len == 4) { m_copydata(m, 0, sizeof(uint32_t), (void *)&cookie_32); NTOHL(cookie_32); if (cookie_32 != var->lv_my_cookie) { m_freem(m); goto out; } m_adj(m, sizeof(uint32_t)); } else { m_copydata(m, 0, sizeof(uint64_t), (void *)&cookie_64); BE64TOH(cookie_64); if (cookie_64 != var->lv_my_cookie) { m_freem(m); goto out; } m_adj(m, sizeof(uint64_t)); } } /* TODO: IP_TCPMSS support */ #ifdef IP_TCPMSS m = l2tp_tcpmss_clamp(l2tpp, m); if (m == NULL) goto out; #endif l2tp_input(m, l2tpp); out: l2tp_putref_variant(var, &psref); return; } /* * This function is used by encap4_lookup() to decide priority of the encaptab. * This priority is compared to the match length between mbuf's source/destination * IPv4 address pair and encaptab's one. * l2tp(4) does not use address pairs to search matched encaptab, so this * function must return the length bigger than or equals to IPv4 address pair to * avoid wrong encaptab. */ static int in_l2tp_match(struct mbuf *m, int off, int proto, void *arg) { struct l2tp_variant *var = arg; uint32_t sess_id; KASSERT(proto == IPPROTO_L2TP); if (m->m_len < off + sizeof(uint32_t)) { m = m_pullup(m, off + sizeof(uint32_t)); if (!m) { /* if payload length < 4 octets */ return 0; } } /* get L2TP session ID */ m_copydata(m, off, sizeof(uint32_t), (void *)&sess_id); NTOHL(sess_id); if (sess_id == 0) { /* * L2TPv3 control packet received. * userland daemon(l2tpd?) should process. */ return 32 * 2; } else if (sess_id == var->lv_my_sess_id) return 32 * 2; else return 0; } int in_l2tp_attach(struct l2tp_variant *var) { var->lv_encap_cookie = encap_attach_func(AF_INET, IPPROTO_L2TP, in_l2tp_match, &in_l2tp_encapsw, var); if (var->lv_encap_cookie == NULL) return EEXIST; return 0; } int in_l2tp_detach(struct l2tp_variant *var) { int error; error = encap_detach(var->lv_encap_cookie); if (error == 0) var->lv_encap_cookie = NULL; return error; } @ 1.1.2.3 log @Sync with HEAD @ text @d1 1 a1 1 /* $NetBSD: in_l2tp.c,v 1.2 2017/03/30 23:13:54 knakahara Exp $ */ d30 1 a30 1 __KERNEL_RCSID(0, "$NetBSD: in_l2tp.c,v 1.2 2017/03/30 23:13:54 knakahara Exp $"); d318 5 @