linux/net/ipv6/mip6.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Copyright (C)2003-2006 Helsinki University of Technology
   4 * Copyright (C)2003-2006 USAGI/WIDE Project
   5 */
   6/*
   7 * Authors:
   8 *      Noriaki TAKAMIYA @USAGI
   9 *      Masahide NAKAMURA @USAGI
  10 */
  11
  12#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  13
  14#include <linux/module.h>
  15#include <linux/skbuff.h>
  16#include <linux/time.h>
  17#include <linux/ipv6.h>
  18#include <linux/icmpv6.h>
  19#include <net/sock.h>
  20#include <net/ipv6.h>
  21#include <net/ip6_checksum.h>
  22#include <net/rawv6.h>
  23#include <net/xfrm.h>
  24#include <net/mip6.h>
  25
  26static inline unsigned int calc_padlen(unsigned int len, unsigned int n)
  27{
  28        return (n - len + 16) & 0x7;
  29}
  30
  31static inline void *mip6_padn(__u8 *data, __u8 padlen)
  32{
  33        if (!data)
  34                return NULL;
  35        if (padlen == 1) {
  36                data[0] = IPV6_TLV_PAD1;
  37        } else if (padlen > 1) {
  38                data[0] = IPV6_TLV_PADN;
  39                data[1] = padlen - 2;
  40                if (padlen > 2)
  41                        memset(data+2, 0, data[1]);
  42        }
  43        return data + padlen;
  44}
  45
  46static inline void mip6_param_prob(struct sk_buff *skb, u8 code, int pos)
  47{
  48        icmpv6_send(skb, ICMPV6_PARAMPROB, code, pos);
  49}
  50
  51static int mip6_mh_len(int type)
  52{
  53        int len = 0;
  54
  55        switch (type) {
  56        case IP6_MH_TYPE_BRR:
  57                len = 0;
  58                break;
  59        case IP6_MH_TYPE_HOTI:
  60        case IP6_MH_TYPE_COTI:
  61        case IP6_MH_TYPE_BU:
  62        case IP6_MH_TYPE_BACK:
  63                len = 1;
  64                break;
  65        case IP6_MH_TYPE_HOT:
  66        case IP6_MH_TYPE_COT:
  67        case IP6_MH_TYPE_BERROR:
  68                len = 2;
  69                break;
  70        }
  71        return len;
  72}
  73
  74static int mip6_mh_filter(struct sock *sk, struct sk_buff *skb)
  75{
  76        struct ip6_mh _hdr;
  77        const struct ip6_mh *mh;
  78
  79        mh = skb_header_pointer(skb, skb_transport_offset(skb),
  80                                sizeof(_hdr), &_hdr);
  81        if (!mh)
  82                return -1;
  83
  84        if (((mh->ip6mh_hdrlen + 1) << 3) > skb->len)
  85                return -1;
  86
  87        if (mh->ip6mh_hdrlen < mip6_mh_len(mh->ip6mh_type)) {
  88                net_dbg_ratelimited("mip6: MH message too short: %d vs >=%d\n",
  89                                    mh->ip6mh_hdrlen,
  90                                    mip6_mh_len(mh->ip6mh_type));
  91                mip6_param_prob(skb, 0, offsetof(struct ip6_mh, ip6mh_hdrlen) +
  92                                skb_network_header_len(skb));
  93                return -1;
  94        }
  95
  96        if (mh->ip6mh_proto != IPPROTO_NONE) {
  97                net_dbg_ratelimited("mip6: MH invalid payload proto = %d\n",
  98                                    mh->ip6mh_proto);
  99                mip6_param_prob(skb, 0, offsetof(struct ip6_mh, ip6mh_proto) +
 100                                skb_network_header_len(skb));
 101                return -1;
 102        }
 103
 104        return 0;
 105}
 106
 107struct mip6_report_rate_limiter {
 108        spinlock_t lock;
 109        ktime_t stamp;
 110        int iif;
 111        struct in6_addr src;
 112        struct in6_addr dst;
 113};
 114
 115static struct mip6_report_rate_limiter mip6_report_rl = {
 116        .lock = __SPIN_LOCK_UNLOCKED(mip6_report_rl.lock)
 117};
 118
 119static int mip6_destopt_input(struct xfrm_state *x, struct sk_buff *skb)
 120{
 121        const struct ipv6hdr *iph = ipv6_hdr(skb);
 122        struct ipv6_destopt_hdr *destopt = (struct ipv6_destopt_hdr *)skb->data;
 123        int err = destopt->nexthdr;
 124
 125        spin_lock(&x->lock);
 126        if (!ipv6_addr_equal(&iph->saddr, (struct in6_addr *)x->coaddr) &&
 127            !ipv6_addr_any((struct in6_addr *)x->coaddr))
 128                err = -ENOENT;
 129        spin_unlock(&x->lock);
 130
 131        return err;
 132}
 133
 134/* Destination Option Header is inserted.
 135 * IP Header's src address is replaced with Home Address Option in
 136 * Destination Option Header.
 137 */
 138static int mip6_destopt_output(struct xfrm_state *x, struct sk_buff *skb)
 139{
 140        struct ipv6hdr *iph;
 141        struct ipv6_destopt_hdr *dstopt;
 142        struct ipv6_destopt_hao *hao;
 143        u8 nexthdr;
 144        int len;
 145
 146        skb_push(skb, -skb_network_offset(skb));
 147        iph = ipv6_hdr(skb);
 148
 149        nexthdr = *skb_mac_header(skb);
 150        *skb_mac_header(skb) = IPPROTO_DSTOPTS;
 151
 152        dstopt = (struct ipv6_destopt_hdr *)skb_transport_header(skb);
 153        dstopt->nexthdr = nexthdr;
 154
 155        hao = mip6_padn((char *)(dstopt + 1),
 156                        calc_padlen(sizeof(*dstopt), 6));
 157
 158        hao->type = IPV6_TLV_HAO;
 159        BUILD_BUG_ON(sizeof(*hao) != 18);
 160        hao->length = sizeof(*hao) - 2;
 161
 162        len = ((char *)hao - (char *)dstopt) + sizeof(*hao);
 163
 164        memcpy(&hao->addr, &iph->saddr, sizeof(hao->addr));
 165        spin_lock_bh(&x->lock);
 166        memcpy(&iph->saddr, x->coaddr, sizeof(iph->saddr));
 167        spin_unlock_bh(&x->lock);
 168
 169        WARN_ON(len != x->props.header_len);
 170        dstopt->hdrlen = (x->props.header_len >> 3) - 1;
 171
 172        return 0;
 173}
 174
 175static inline int mip6_report_rl_allow(ktime_t stamp,
 176                                       const struct in6_addr *dst,
 177                                       const struct in6_addr *src, int iif)
 178{
 179        int allow = 0;
 180
 181        spin_lock_bh(&mip6_report_rl.lock);
 182        if (mip6_report_rl.stamp != stamp ||
 183            mip6_report_rl.iif != iif ||
 184            !ipv6_addr_equal(&mip6_report_rl.src, src) ||
 185            !ipv6_addr_equal(&mip6_report_rl.dst, dst)) {
 186                mip6_report_rl.stamp = stamp;
 187                mip6_report_rl.iif = iif;
 188                mip6_report_rl.src = *src;
 189                mip6_report_rl.dst = *dst;
 190                allow = 1;
 191        }
 192        spin_unlock_bh(&mip6_report_rl.lock);
 193        return allow;
 194}
 195
 196static int mip6_destopt_reject(struct xfrm_state *x, struct sk_buff *skb,
 197                               const struct flowi *fl)
 198{
 199        struct net *net = xs_net(x);
 200        struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb;
 201        const struct flowi6 *fl6 = &fl->u.ip6;
 202        struct ipv6_destopt_hao *hao = NULL;
 203        struct xfrm_selector sel;
 204        int offset;
 205        ktime_t stamp;
 206        int err = 0;
 207
 208        if (unlikely(fl6->flowi6_proto == IPPROTO_MH &&
 209                     fl6->fl6_mh_type <= IP6_MH_TYPE_MAX))
 210                goto out;
 211
 212        if (likely(opt->dsthao)) {
 213                offset = ipv6_find_tlv(skb, opt->dsthao, IPV6_TLV_HAO);
 214                if (likely(offset >= 0))
 215                        hao = (struct ipv6_destopt_hao *)
 216                                        (skb_network_header(skb) + offset);
 217        }
 218
 219        stamp = skb_get_ktime(skb);
 220
 221        if (!mip6_report_rl_allow(stamp, &ipv6_hdr(skb)->daddr,
 222                                  hao ? &hao->addr : &ipv6_hdr(skb)->saddr,
 223                                  opt->iif))
 224                goto out;
 225
 226        memset(&sel, 0, sizeof(sel));
 227        memcpy(&sel.daddr, (xfrm_address_t *)&ipv6_hdr(skb)->daddr,
 228               sizeof(sel.daddr));
 229        sel.prefixlen_d = 128;
 230        memcpy(&sel.saddr, (xfrm_address_t *)&ipv6_hdr(skb)->saddr,
 231               sizeof(sel.saddr));
 232        sel.prefixlen_s = 128;
 233        sel.family = AF_INET6;
 234        sel.proto = fl6->flowi6_proto;
 235        sel.dport = xfrm_flowi_dport(fl, &fl6->uli);
 236        if (sel.dport)
 237                sel.dport_mask = htons(~0);
 238        sel.sport = xfrm_flowi_sport(fl, &fl6->uli);
 239        if (sel.sport)
 240                sel.sport_mask = htons(~0);
 241        sel.ifindex = fl6->flowi6_oif;
 242
 243        err = km_report(net, IPPROTO_DSTOPTS, &sel,
 244                        (hao ? (xfrm_address_t *)&hao->addr : NULL));
 245
 246 out:
 247        return err;
 248}
 249
 250static int mip6_destopt_offset(struct xfrm_state *x, struct sk_buff *skb,
 251                               u8 **nexthdr)
 252{
 253        u16 offset = sizeof(struct ipv6hdr);
 254        struct ipv6_opt_hdr *exthdr =
 255                                   (struct ipv6_opt_hdr *)(ipv6_hdr(skb) + 1);
 256        const unsigned char *nh = skb_network_header(skb);
 257        unsigned int packet_len = skb_tail_pointer(skb) -
 258                skb_network_header(skb);
 259        int found_rhdr = 0;
 260
 261        *nexthdr = &ipv6_hdr(skb)->nexthdr;
 262
 263        while (offset + 1 <= packet_len) {
 264
 265                switch (**nexthdr) {
 266                case NEXTHDR_HOP:
 267                        break;
 268                case NEXTHDR_ROUTING:
 269                        found_rhdr = 1;
 270                        break;
 271                case NEXTHDR_DEST:
 272                        /*
 273                         * HAO MUST NOT appear more than once.
 274                         * XXX: It is better to try to find by the end of
 275                         * XXX: packet if HAO exists.
 276                         */
 277                        if (ipv6_find_tlv(skb, offset, IPV6_TLV_HAO) >= 0) {
 278                                net_dbg_ratelimited("mip6: hao exists already, override\n");
 279                                return offset;
 280                        }
 281
 282                        if (found_rhdr)
 283                                return offset;
 284
 285                        break;
 286                default:
 287                        return offset;
 288                }
 289
 290                offset += ipv6_optlen(exthdr);
 291                *nexthdr = &exthdr->nexthdr;
 292                exthdr = (struct ipv6_opt_hdr *)(nh + offset);
 293        }
 294
 295        return offset;
 296}
 297
 298static int mip6_destopt_init_state(struct xfrm_state *x)
 299{
 300        if (x->id.spi) {
 301                pr_info("%s: spi is not 0: %u\n", __func__, x->id.spi);
 302                return -EINVAL;
 303        }
 304        if (x->props.mode != XFRM_MODE_ROUTEOPTIMIZATION) {
 305                pr_info("%s: state's mode is not %u: %u\n",
 306                        __func__, XFRM_MODE_ROUTEOPTIMIZATION, x->props.mode);
 307                return -EINVAL;
 308        }
 309
 310        x->props.header_len = sizeof(struct ipv6_destopt_hdr) +
 311                calc_padlen(sizeof(struct ipv6_destopt_hdr), 6) +
 312                sizeof(struct ipv6_destopt_hao);
 313        WARN_ON(x->props.header_len != 24);
 314
 315        return 0;
 316}
 317
 318/*
 319 * Do nothing about destroying since it has no specific operation for
 320 * destination options header unlike IPsec protocols.
 321 */
 322static void mip6_destopt_destroy(struct xfrm_state *x)
 323{
 324}
 325
 326static const struct xfrm_type mip6_destopt_type = {
 327        .description    = "MIP6DESTOPT",
 328        .owner          = THIS_MODULE,
 329        .proto          = IPPROTO_DSTOPTS,
 330        .flags          = XFRM_TYPE_NON_FRAGMENT | XFRM_TYPE_LOCAL_COADDR,
 331        .init_state     = mip6_destopt_init_state,
 332        .destructor     = mip6_destopt_destroy,
 333        .input          = mip6_destopt_input,
 334        .output         = mip6_destopt_output,
 335        .reject         = mip6_destopt_reject,
 336        .hdr_offset     = mip6_destopt_offset,
 337};
 338
 339static int mip6_rthdr_input(struct xfrm_state *x, struct sk_buff *skb)
 340{
 341        const struct ipv6hdr *iph = ipv6_hdr(skb);
 342        struct rt2_hdr *rt2 = (struct rt2_hdr *)skb->data;
 343        int err = rt2->rt_hdr.nexthdr;
 344
 345        spin_lock(&x->lock);
 346        if (!ipv6_addr_equal(&iph->daddr, (struct in6_addr *)x->coaddr) &&
 347            !ipv6_addr_any((struct in6_addr *)x->coaddr))
 348                err = -ENOENT;
 349        spin_unlock(&x->lock);
 350
 351        return err;
 352}
 353
 354/* Routing Header type 2 is inserted.
 355 * IP Header's dst address is replaced with Routing Header's Home Address.
 356 */
 357static int mip6_rthdr_output(struct xfrm_state *x, struct sk_buff *skb)
 358{
 359        struct ipv6hdr *iph;
 360        struct rt2_hdr *rt2;
 361        u8 nexthdr;
 362
 363        skb_push(skb, -skb_network_offset(skb));
 364        iph = ipv6_hdr(skb);
 365
 366        nexthdr = *skb_mac_header(skb);
 367        *skb_mac_header(skb) = IPPROTO_ROUTING;
 368
 369        rt2 = (struct rt2_hdr *)skb_transport_header(skb);
 370        rt2->rt_hdr.nexthdr = nexthdr;
 371        rt2->rt_hdr.hdrlen = (x->props.header_len >> 3) - 1;
 372        rt2->rt_hdr.type = IPV6_SRCRT_TYPE_2;
 373        rt2->rt_hdr.segments_left = 1;
 374        memset(&rt2->reserved, 0, sizeof(rt2->reserved));
 375
 376        WARN_ON(rt2->rt_hdr.hdrlen != 2);
 377
 378        memcpy(&rt2->addr, &iph->daddr, sizeof(rt2->addr));
 379        spin_lock_bh(&x->lock);
 380        memcpy(&iph->daddr, x->coaddr, sizeof(iph->daddr));
 381        spin_unlock_bh(&x->lock);
 382
 383        return 0;
 384}
 385
 386static int mip6_rthdr_offset(struct xfrm_state *x, struct sk_buff *skb,
 387                             u8 **nexthdr)
 388{
 389        u16 offset = sizeof(struct ipv6hdr);
 390        struct ipv6_opt_hdr *exthdr =
 391                                   (struct ipv6_opt_hdr *)(ipv6_hdr(skb) + 1);
 392        const unsigned char *nh = skb_network_header(skb);
 393        unsigned int packet_len = skb_tail_pointer(skb) -
 394                skb_network_header(skb);
 395        int found_rhdr = 0;
 396
 397        *nexthdr = &ipv6_hdr(skb)->nexthdr;
 398
 399        while (offset + 1 <= packet_len) {
 400
 401                switch (**nexthdr) {
 402                case NEXTHDR_HOP:
 403                        break;
 404                case NEXTHDR_ROUTING:
 405                        if (offset + 3 <= packet_len) {
 406                                struct ipv6_rt_hdr *rt;
 407                                rt = (struct ipv6_rt_hdr *)(nh + offset);
 408                                if (rt->type != 0)
 409                                        return offset;
 410                        }
 411                        found_rhdr = 1;
 412                        break;
 413                case NEXTHDR_DEST:
 414                        if (ipv6_find_tlv(skb, offset, IPV6_TLV_HAO) >= 0)
 415                                return offset;
 416
 417                        if (found_rhdr)
 418                                return offset;
 419
 420                        break;
 421                default:
 422                        return offset;
 423                }
 424
 425                offset += ipv6_optlen(exthdr);
 426                *nexthdr = &exthdr->nexthdr;
 427                exthdr = (struct ipv6_opt_hdr *)(nh + offset);
 428        }
 429
 430        return offset;
 431}
 432
 433static int mip6_rthdr_init_state(struct xfrm_state *x)
 434{
 435        if (x->id.spi) {
 436                pr_info("%s: spi is not 0: %u\n", __func__, x->id.spi);
 437                return -EINVAL;
 438        }
 439        if (x->props.mode != XFRM_MODE_ROUTEOPTIMIZATION) {
 440                pr_info("%s: state's mode is not %u: %u\n",
 441                        __func__, XFRM_MODE_ROUTEOPTIMIZATION, x->props.mode);
 442                return -EINVAL;
 443        }
 444
 445        x->props.header_len = sizeof(struct rt2_hdr);
 446
 447        return 0;
 448}
 449
 450/*
 451 * Do nothing about destroying since it has no specific operation for routing
 452 * header type 2 unlike IPsec protocols.
 453 */
 454static void mip6_rthdr_destroy(struct xfrm_state *x)
 455{
 456}
 457
 458static const struct xfrm_type mip6_rthdr_type = {
 459        .description    = "MIP6RT",
 460        .owner          = THIS_MODULE,
 461        .proto          = IPPROTO_ROUTING,
 462        .flags          = XFRM_TYPE_NON_FRAGMENT | XFRM_TYPE_REMOTE_COADDR,
 463        .init_state     = mip6_rthdr_init_state,
 464        .destructor     = mip6_rthdr_destroy,
 465        .input          = mip6_rthdr_input,
 466        .output         = mip6_rthdr_output,
 467        .hdr_offset     = mip6_rthdr_offset,
 468};
 469
 470static int __init mip6_init(void)
 471{
 472        pr_info("Mobile IPv6\n");
 473
 474        if (xfrm_register_type(&mip6_destopt_type, AF_INET6) < 0) {
 475                pr_info("%s: can't add xfrm type(destopt)\n", __func__);
 476                goto mip6_destopt_xfrm_fail;
 477        }
 478        if (xfrm_register_type(&mip6_rthdr_type, AF_INET6) < 0) {
 479                pr_info("%s: can't add xfrm type(rthdr)\n", __func__);
 480                goto mip6_rthdr_xfrm_fail;
 481        }
 482        if (rawv6_mh_filter_register(mip6_mh_filter) < 0) {
 483                pr_info("%s: can't add rawv6 mh filter\n", __func__);
 484                goto mip6_rawv6_mh_fail;
 485        }
 486
 487
 488        return 0;
 489
 490 mip6_rawv6_mh_fail:
 491        xfrm_unregister_type(&mip6_rthdr_type, AF_INET6);
 492 mip6_rthdr_xfrm_fail:
 493        xfrm_unregister_type(&mip6_destopt_type, AF_INET6);
 494 mip6_destopt_xfrm_fail:
 495        return -EAGAIN;
 496}
 497
 498static void __exit mip6_fini(void)
 499{
 500        if (rawv6_mh_filter_unregister(mip6_mh_filter) < 0)
 501                pr_info("%s: can't remove rawv6 mh filter\n", __func__);
 502        xfrm_unregister_type(&mip6_rthdr_type, AF_INET6);
 503        xfrm_unregister_type(&mip6_destopt_type, AF_INET6);
 504}
 505
 506module_init(mip6_init);
 507module_exit(mip6_fini);
 508
 509MODULE_LICENSE("GPL");
 510MODULE_ALIAS_XFRM_TYPE(AF_INET6, XFRM_PROTO_DSTOPTS);
 511MODULE_ALIAS_XFRM_TYPE(AF_INET6, XFRM_PROTO_ROUTING);
 512