[BACK]Return to in6_l2tp.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / netinet6

Annotation of src/sys/netinet6/in6_l2tp.c, Revision 1.10

1.10    ! knakahar    1: /*     $NetBSD: in6_l2tp.c,v 1.9 2017/12/15 04:58:31 knakahara Exp $   */
1.1       knakahar    2:
                      3: /*
                      4:  * Copyright (c) 2017 Internet Initiative Japan Inc.
                      5:  * All rights reserved.
                      6:  *
                      7:  * Redistribution and use in source and binary forms, with or without
                      8:  * modification, are permitted provided that the following conditions
                      9:  * are met:
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer.
                     12:  * 2. Redistributions in binary form must reproduce the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer in the
                     14:  *    documentation and/or other materials provided with the distribution.
                     15:  *
                     16:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     17:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     18:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     19:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     20:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     21:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     22:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     23:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     24:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     25:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     26:  * POSSIBILITY OF SUCH DAMAGE.
                     27:  */
                     28:
                     29: #include <sys/cdefs.h>
1.10    ! knakahar   30: __KERNEL_RCSID(0, "$NetBSD: in6_l2tp.c,v 1.9 2017/12/15 04:58:31 knakahara Exp $");
1.1       knakahar   31:
                     32: #ifdef _KERNEL_OPT
                     33: #include "opt_l2tp.h"
                     34: #endif
                     35:
                     36: #include <sys/param.h>
                     37: #include <sys/systm.h>
                     38: #include <sys/socket.h>
                     39: #include <sys/sockio.h>
                     40: #include <sys/mbuf.h>
                     41: #include <sys/errno.h>
                     42: #include <sys/ioctl.h>
                     43: #include <sys/syslog.h>
                     44: #include <sys/kernel.h>
                     45:
                     46: #include <net/if.h>
                     47: #include <net/route.h>
                     48: #include <net/if_ether.h>
                     49:
                     50: #include <netinet/in.h>
                     51: #include <netinet/in_systm.h>
                     52: #include <netinet/ip.h>
                     53: #include <netinet/ip_var.h>
                     54: #include <netinet/ip_private.h>
                     55: #include <netinet/in_l2tp.h>
                     56: #include <netinet/in_var.h>
                     57: #include <netinet/ip_encap.h>
                     58:
                     59: #include <netinet/ip6.h>
                     60: #include <netinet6/ip6_var.h>
                     61: #include <netinet6/in6_l2tp.h>
                     62:
                     63: #ifdef ALTQ
                     64: #include <altq/altq.h>
                     65: #endif
                     66:
                     67: /* TODO: IP_TCPMSS support */
                     68: #undef IP_TCPMSS
                     69: #ifdef IP_TCPMSS
                     70: #include <netinet/ip_tcpmss.h>
                     71: #endif
                     72:
                     73: #include <net/if_l2tp.h>
                     74:
                     75: #define L2TP_HLIM6             64
                     76: int ip6_l2tp_hlim = L2TP_HLIM6;
                     77:
1.7       knakahar   78: static int in6_l2tp_input(struct mbuf **, int *, int, void *);
1.1       knakahar   79:
                     80: static const struct encapsw in6_l2tp_encapsw = {
                     81:        .encapsw6 = {
                     82:                .pr_input       = in6_l2tp_input,
                     83:                .pr_ctlinput    = NULL,
                     84:        }
                     85: };
                     86:
                     87: static int in6_l2tp_match(struct mbuf *, int, int, void *);
                     88:
                     89: int
                     90: in6_l2tp_output(struct l2tp_variant *var, struct mbuf *m)
                     91: {
                     92:        struct rtentry *rt;
                     93:        struct l2tp_ro *lro;
                     94:        struct l2tp_softc *sc;
                     95:        struct ifnet *ifp;
                     96:        struct sockaddr_in6 *sin6_src = satosin6(var->lv_psrc);
                     97:        struct sockaddr_in6 *sin6_dst = satosin6(var->lv_pdst);
                     98:        struct ip6_hdr ip6hdr;  /* capsule IP header, host byte ordered */
                     99:        int error;
                    100:        uint32_t sess_id;
                    101:
                    102:        KASSERT(var != NULL);
                    103:        KASSERT(l2tp_heldref_variant(var));
                    104:        KASSERT(sin6_src != NULL && sin6_dst != NULL);
                    105:        KASSERT(sin6_src->sin6_family == AF_INET6
                    106:            && sin6_dst->sin6_family == AF_INET6);
                    107:
                    108:        sc = var->lv_softc;
                    109:        ifp = &sc->l2tp_ec.ec_if;
                    110:        error = l2tp_check_nesting(ifp, m);
1.6       knakahar  111:        if (error) {
                    112:                m_freem(m);
1.1       knakahar  113:                goto looped;
1.6       knakahar  114:        }
1.1       knakahar  115:
                    116: #ifdef NOTYET
                    117: /* TODO: support ALTQ for innner frame */
                    118: #ifdef ALTQ
                    119:        ALTQ_SAVE_PAYLOAD(m, AF_ETHER);
                    120: #endif
                    121: #endif
                    122:
                    123:        memset(&ip6hdr, 0, sizeof(ip6hdr));
                    124:        ip6hdr.ip6_src = sin6_src->sin6_addr;
                    125:        /* bidirectional configured tunnel mode */
                    126:        if (!IN6_IS_ADDR_UNSPECIFIED(&sin6_dst->sin6_addr))
                    127:                ip6hdr.ip6_dst = sin6_dst->sin6_addr;
                    128:        else {
                    129:                m_freem(m);
                    130:                if ((ifp->if_flags & IFF_DEBUG) != 0)
                    131:                        log(LOG_DEBUG, "%s: ENETUNREACH\n", __func__);
                    132:                return ENETUNREACH;
                    133:        }
                    134:        /* unlike IPv4, IP version must be filled by caller of ip6_output() */
                    135:        ip6hdr.ip6_vfc  = 0x60;
                    136:        ip6hdr.ip6_nxt  = IPPROTO_L2TP;
                    137:        ip6hdr.ip6_hlim = ip6_l2tp_hlim;
                    138:        /* outer IP payload length */
                    139:        ip6hdr.ip6_plen = 0;
                    140:        /* session-id length */
                    141:        ip6hdr.ip6_plen += sizeof(uint32_t);
                    142:        if (var->lv_use_cookie == L2TP_COOKIE_ON) {
                    143:                /* cookie length */
                    144:                ip6hdr.ip6_plen += var->lv_peer_cookie_len;
                    145:        }
                    146:
                    147: /* TODO: IP_TCPMSS support */
                    148: #ifdef IP_TCPMSS
                    149:        m = l2tp_tcpmss_clamp(ifp, m);
                    150:        if (m == NULL)
                    151:                return EINVAL;
                    152: #endif
                    153:
                    154:        /*
                    155:         * payload length
                    156:         *  NOTE: Payload length may be changed in ip_tcpmss().
                    157:         *        Typical case is missing of TCP mss option in original
                    158:         *        TCP header.
                    159:         */
                    160:        ip6hdr.ip6_plen += m->m_pkthdr.len;
                    161:        HTONS(ip6hdr.ip6_plen);
                    162:
                    163:        if (var->lv_use_cookie == L2TP_COOKIE_ON) {
                    164:                /* prepend session cookie */
                    165:                uint32_t cookie_32;
                    166:                uint64_t cookie_64;
                    167:                M_PREPEND(m, var->lv_peer_cookie_len, M_DONTWAIT);
                    168:                if (m && m->m_len < var->lv_peer_cookie_len)
                    169:                        m = m_pullup(m, var->lv_peer_cookie_len);
                    170:                if (m == NULL)
                    171:                        return ENOBUFS;
                    172:                if (var->lv_peer_cookie_len == 4) {
                    173:                        cookie_32 = htonl((uint32_t)var->lv_peer_cookie);
                    174:                        memcpy(mtod(m, void *), &cookie_32,
                    175:                            sizeof(uint32_t));
                    176:                } else {
                    177:                        cookie_64 = htobe64(var->lv_peer_cookie);
                    178:                        memcpy(mtod(m, void *), &cookie_64,
                    179:                            sizeof(uint64_t));
                    180:                }
                    181:        }
                    182:
                    183:        /* prepend session-ID */
                    184:        sess_id = htonl(var->lv_peer_sess_id);
                    185:        M_PREPEND(m, sizeof(uint32_t), M_DONTWAIT);
                    186:        if (m && m->m_len < sizeof(uint32_t))
                    187:                m = m_pullup(m, sizeof(uint32_t));
                    188:        if (m == NULL)
                    189:                return ENOBUFS;
                    190:        memcpy(mtod(m, uint32_t *), &sess_id, sizeof(uint32_t));
                    191:
                    192:        /* prepend new IP header */
                    193:        M_PREPEND(m, sizeof(struct ip6_hdr), M_DONTWAIT);
                    194:        if (IP_HDR_ALIGNED_P(mtod(m, void *)) == 0) {
                    195:                if (m)
                    196:                        m = m_copyup(m, sizeof(struct ip), 0);
                    197:        } else {
                    198:                if (m && m->m_len < sizeof(struct ip6_hdr))
                    199:                        m = m_pullup(m, sizeof(struct ip6_hdr));
                    200:        }
                    201:        if (m == NULL)
                    202:                return ENOBUFS;
                    203:        memcpy(mtod(m, struct ip6_hdr *), &ip6hdr, sizeof(struct ip6_hdr));
                    204:
                    205:        lro = percpu_getref(sc->l2tp_ro_percpu);
                    206:        mutex_enter(&lro->lr_lock);
                    207:        if ((rt = rtcache_lookup(&lro->lr_ro, var->lv_pdst)) == NULL) {
                    208:                mutex_exit(&lro->lr_lock);
                    209:                percpu_putref(sc->l2tp_ro_percpu);
                    210:                m_freem(m);
                    211:                return ENETUNREACH;
                    212:        }
                    213:
                    214:        /* If the route constitutes infinite encapsulation, punt. */
                    215:        if (rt->rt_ifp == ifp) {
                    216:                rtcache_unref(rt, &lro->lr_ro);
                    217:                rtcache_free(&lro->lr_ro);
                    218:                mutex_exit(&lro->lr_lock);
                    219:                percpu_putref(sc->l2tp_ro_percpu);
                    220:                m_freem(m);
                    221:                return ENETUNREACH;     /* XXX */
                    222:        }
                    223:        rtcache_unref(rt, &lro->lr_ro);
                    224:
                    225:        /*
                    226:         * To avoid inappropriate rewrite of checksum,
                    227:         * clear csum flags.
                    228:         */
                    229:        m->m_pkthdr.csum_flags  = 0;
                    230:
                    231:        error = ip6_output(m, 0, &lro->lr_ro, 0, NULL, NULL, NULL);
                    232:        mutex_exit(&lro->lr_lock);
                    233:        percpu_putref(sc->l2tp_ro_percpu);
                    234:        return(error);
                    235:
                    236: looped:
                    237:        if (error)
                    238:                ifp->if_oerrors++;
                    239:
                    240:        return error;
                    241: }
                    242:
                    243: static int
1.7       knakahar  244: in6_l2tp_input(struct mbuf **mp, int *offp, int proto, void *eparg __unused)
1.1       knakahar  245: {
                    246:        struct mbuf *m = *mp;
                    247:        int off = *offp;
                    248:
                    249:        struct ifnet *l2tpp = NULL;
                    250:        struct l2tp_softc *sc;
                    251:        struct l2tp_variant *var;
                    252:        uint32_t sess_id;
                    253:        uint32_t cookie_32;
                    254:        uint64_t cookie_64;
                    255:        struct psref psref;
                    256:
                    257:        if (m->m_len < off + sizeof(uint32_t)) {
                    258:                m = m_pullup(m, off + sizeof(uint32_t));
                    259:                if (!m) {
                    260:                        /* if payload length < 4 octets */
                    261:                        return IPPROTO_DONE;
                    262:                }
                    263:                *mp = m;
                    264:         }
                    265:
                    266:        /* get L2TP session ID */
                    267:        m_copydata(m, off, sizeof(uint32_t), (void *)&sess_id);
                    268:        NTOHL(sess_id);
                    269: #ifdef L2TP_DEBUG
                    270:        log(LOG_DEBUG, "%s: sess_id = %" PRIu32 "\n", __func__, sess_id);
                    271: #endif
                    272:        if (sess_id == 0) {
                    273:                /*
                    274:                 * L2TPv3 control packet received.
                    275:                 * userland daemon(l2tpd?) should process.
                    276:                 */
                    277:                return rip6_input(mp, offp, proto);
                    278:        }
                    279:
                    280:        var = l2tp_lookup_session_ref(sess_id, &psref);
                    281:        if (var == NULL) {
                    282:                m_freem(m);
                    283:                IP_STATINC(IP_STAT_NOL2TP);
                    284:                return IPPROTO_DONE;
                    285:        } else {
                    286:                sc = var->lv_softc;
                    287:                l2tpp = &(sc->l2tp_ec.ec_if);
                    288:
                    289:                if (l2tpp == NULL || (l2tpp->if_flags & IFF_UP) == 0) {
                    290: #ifdef L2TP_DEBUG
                    291:                        if (l2tpp == NULL)
                    292:                                log(LOG_DEBUG, "%s: l2tpp is NULL\n", __func__);
                    293:                        else
                    294:                                log(LOG_DEBUG, "%s: l2tpp is down\n", __func__);
                    295: #endif
                    296:                        m_freem(m);
                    297:                        IP_STATINC(IP_STAT_NOL2TP);
                    298:                        goto out;
                    299:                }
                    300:                /* other CPU do l2tp_delete_tunnel */
                    301:                if (var->lv_psrc == NULL || var->lv_pdst == NULL) {
                    302:                        m_freem(m);
                    303:                        ip_statinc(IP_STAT_NOL2TP);
                    304:                        goto out;
                    305:                }
                    306:        }
                    307:
                    308:        if (var->lv_state != L2TP_STATE_UP) {
                    309:                m_freem(m);
                    310:                goto out;
                    311:        }
                    312:        m_adj(m, off + sizeof(uint32_t));
                    313:
                    314:        if (var->lv_use_cookie == L2TP_COOKIE_ON) {
                    315:                if (var->lv_my_cookie_len == 4) {
                    316:                        m_copydata(m, 0, sizeof(uint32_t), (void *)&cookie_32);
                    317:                        NTOHL(cookie_32);
                    318:                        if (cookie_32 != var->lv_my_cookie) {
                    319:                                m_freem(m);
                    320:                                goto out;
                    321:                        }
                    322:                        m_adj(m, sizeof(uint32_t));
                    323:                } else {
                    324:                        m_copydata(m, 0, sizeof(uint64_t), (void *)&cookie_64);
                    325:                        BE64TOH(cookie_64);
                    326:                        if (cookie_64 != var->lv_my_cookie) {
                    327:                                m_freem(m);
                    328:                                goto out;
                    329:                        }
                    330:                        m_adj(m, sizeof(uint64_t));
                    331:                }
                    332:        }
                    333:
                    334: /* TODO: IP_TCPMSS support */
                    335: #ifdef IP_TCPMSS
                    336:        m = l2tp_tcpmss_clamp(l2tpp, m);
                    337:        if (m == NULL)
                    338:                goto out;
                    339: #endif
                    340:        l2tp_input(m, l2tpp);
                    341:
                    342: out:
                    343:        l2tp_putref_variant(var, &psref);
                    344:        return IPPROTO_DONE;
                    345: }
                    346:
                    347: /*
                    348:  * This function is used by encap6_lookup() to decide priority of the encaptab.
                    349:  * This priority is compared to the match length between mbuf's source/destination
                    350:  * IPv6 address pair and encaptab's one.
                    351:  * l2tp(4) does not use address pairs to search matched encaptab, so this
                    352:  * function must return the length bigger than or equals to IPv6 address pair to
                    353:  * avoid wrong encaptab.
                    354:  */
                    355: static int
                    356: in6_l2tp_match(struct mbuf *m, int off, int proto, void *arg)
                    357: {
                    358:        struct l2tp_variant *var = arg;
                    359:        uint32_t sess_id;
                    360:
                    361:        KASSERT(proto == IPPROTO_L2TP);
                    362:
1.9       knakahar  363:        if (m->m_len < off + sizeof(uint32_t)) {
1.10    ! knakahar  364:                /* if payload length < 4 octets */
        !           365:                if(!m_ensure_contig(&m, off + sizeof(uint32_t)))
1.9       knakahar  366:                        return 0;
1.10    ! knakahar  367:        }
1.1       knakahar  368:
                    369:        /* get L2TP session ID */
                    370:        m_copydata(m, off, sizeof(uint32_t), (void *)&sess_id);
                    371:        NTOHL(sess_id);
                    372:        if (sess_id == 0) {
                    373:                /*
                    374:                 * L2TPv3 control packet received.
                    375:                 * userland daemon(l2tpd?) should process.
                    376:                 */
                    377:                return 128 * 2;
                    378:        } else if (sess_id == var->lv_my_sess_id)
                    379:                return 128 * 2;
                    380:        else
                    381:                return 0;
                    382: }
                    383:
                    384: int
                    385: in6_l2tp_attach(struct l2tp_variant *var)
                    386: {
                    387:
                    388:        var->lv_encap_cookie = encap_attach_func(AF_INET6, IPPROTO_L2TP,
                    389:            in6_l2tp_match, &in6_l2tp_encapsw, var);
                    390:        if (var->lv_encap_cookie == NULL)
                    391:                return EEXIST;
                    392:
                    393:        return 0;
                    394: }
                    395:
                    396: int
                    397: in6_l2tp_detach(struct l2tp_variant *var)
                    398: {
                    399:        int error;
                    400:
                    401:        error = encap_detach(var->lv_encap_cookie);
                    402:        if (error == 0)
                    403:                var->lv_encap_cookie = NULL;
                    404:
                    405:        return error;
                    406: }

CVSweb <webmaster@jp.NetBSD.org>