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_init_state(struct xfrm_state *x)
 251{
 252        if (x->id.spi) {
 253                pr_info("%s: spi is not 0: %u\n", __func__, x->id.spi);
 254                return -EINVAL;
 255        }
 256        if (x->props.mode != XFRM_MODE_ROUTEOPTIMIZATION) {
 257                pr_info("%s: state's mode is not %u: %u\n",
 258                        __func__, XFRM_MODE_ROUTEOPTIMIZATION, x->props.mode);
 259                return -EINVAL;
 260        }
 261
 262        x->props.header_len = sizeof(struct ipv6_destopt_hdr) +
 263                calc_padlen(sizeof(struct ipv6_destopt_hdr), 6) +
 264                sizeof(struct ipv6_destopt_hao);
 265        WARN_ON(x->props.header_len != 24);
 266
 267        return 0;
 268}
 269
 270/*
 271 * Do nothing about destroying since it has no specific operation for
 272 * destination options header unlike IPsec protocols.
 273 */
 274static void mip6_destopt_destroy(struct xfrm_state *x)
 275{
 276}
 277
 278static const struct xfrm_type mip6_destopt_type = {
 279        .owner          = THIS_MODULE,
 280        .proto          = IPPROTO_DSTOPTS,
 281        .flags          = XFRM_TYPE_NON_FRAGMENT | XFRM_TYPE_LOCAL_COADDR,
 282        .init_state     = mip6_destopt_init_state,
 283        .destructor     = mip6_destopt_destroy,
 284        .input          = mip6_destopt_input,
 285        .output         = mip6_destopt_output,
 286        .reject         = mip6_destopt_reject,
 287};
 288
 289static int mip6_rthdr_input(struct xfrm_state *x, struct sk_buff *skb)
 290{
 291        const struct ipv6hdr *iph = ipv6_hdr(skb);
 292        struct rt2_hdr *rt2 = (struct rt2_hdr *)skb->data;
 293        int err = rt2->rt_hdr.nexthdr;
 294
 295        spin_lock(&x->lock);
 296        if (!ipv6_addr_equal(&iph->daddr, (struct in6_addr *)x->coaddr) &&
 297            !ipv6_addr_any((struct in6_addr *)x->coaddr))
 298                err = -ENOENT;
 299        spin_unlock(&x->lock);
 300
 301        return err;
 302}
 303
 304/* Routing Header type 2 is inserted.
 305 * IP Header's dst address is replaced with Routing Header's Home Address.
 306 */
 307static int mip6_rthdr_output(struct xfrm_state *x, struct sk_buff *skb)
 308{
 309        struct ipv6hdr *iph;
 310        struct rt2_hdr *rt2;
 311        u8 nexthdr;
 312
 313        skb_push(skb, -skb_network_offset(skb));
 314        iph = ipv6_hdr(skb);
 315
 316        nexthdr = *skb_mac_header(skb);
 317        *skb_mac_header(skb) = IPPROTO_ROUTING;
 318
 319        rt2 = (struct rt2_hdr *)skb_transport_header(skb);
 320        rt2->rt_hdr.nexthdr = nexthdr;
 321        rt2->rt_hdr.hdrlen = (x->props.header_len >> 3) - 1;
 322        rt2->rt_hdr.type = IPV6_SRCRT_TYPE_2;
 323        rt2->rt_hdr.segments_left = 1;
 324        memset(&rt2->reserved, 0, sizeof(rt2->reserved));
 325
 326        WARN_ON(rt2->rt_hdr.hdrlen != 2);
 327
 328        memcpy(&rt2->addr, &iph->daddr, sizeof(rt2->addr));
 329        spin_lock_bh(&x->lock);
 330        memcpy(&iph->daddr, x->coaddr, sizeof(iph->daddr));
 331        spin_unlock_bh(&x->lock);
 332
 333        return 0;
 334}
 335
 336static int mip6_rthdr_init_state(struct xfrm_state *x)
 337{
 338        if (x->id.spi) {
 339                pr_info("%s: spi is not 0: %u\n", __func__, x->id.spi);
 340                return -EINVAL;
 341        }
 342        if (x->props.mode != XFRM_MODE_ROUTEOPTIMIZATION) {
 343                pr_info("%s: state's mode is not %u: %u\n",
 344                        __func__, XFRM_MODE_ROUTEOPTIMIZATION, x->props.mode);
 345                return -EINVAL;
 346        }
 347
 348        x->props.header_len = sizeof(struct rt2_hdr);
 349
 350        return 0;
 351}
 352
 353/*
 354 * Do nothing about destroying since it has no specific operation for routing
 355 * header type 2 unlike IPsec protocols.
 356 */
 357static void mip6_rthdr_destroy(struct xfrm_state *x)
 358{
 359}
 360
 361static const struct xfrm_type mip6_rthdr_type = {
 362        .owner          = THIS_MODULE,
 363        .proto          = IPPROTO_ROUTING,
 364        .flags          = XFRM_TYPE_NON_FRAGMENT | XFRM_TYPE_REMOTE_COADDR,
 365        .init_state     = mip6_rthdr_init_state,
 366        .destructor     = mip6_rthdr_destroy,
 367        .input          = mip6_rthdr_input,
 368        .output         = mip6_rthdr_output,
 369};
 370
 371static int __init mip6_init(void)
 372{
 373        pr_info("Mobile IPv6\n");
 374
 375        if (xfrm_register_type(&mip6_destopt_type, AF_INET6) < 0) {
 376                pr_info("%s: can't add xfrm type(destopt)\n", __func__);
 377                goto mip6_destopt_xfrm_fail;
 378        }
 379        if (xfrm_register_type(&mip6_rthdr_type, AF_INET6) < 0) {
 380                pr_info("%s: can't add xfrm type(rthdr)\n", __func__);
 381                goto mip6_rthdr_xfrm_fail;
 382        }
 383        if (rawv6_mh_filter_register(mip6_mh_filter) < 0) {
 384                pr_info("%s: can't add rawv6 mh filter\n", __func__);
 385                goto mip6_rawv6_mh_fail;
 386        }
 387
 388
 389        return 0;
 390
 391 mip6_rawv6_mh_fail:
 392        xfrm_unregister_type(&mip6_rthdr_type, AF_INET6);
 393 mip6_rthdr_xfrm_fail:
 394        xfrm_unregister_type(&mip6_destopt_type, AF_INET6);
 395 mip6_destopt_xfrm_fail:
 396        return -EAGAIN;
 397}
 398
 399static void __exit mip6_fini(void)
 400{
 401        if (rawv6_mh_filter_unregister(mip6_mh_filter) < 0)
 402                pr_info("%s: can't remove rawv6 mh filter\n", __func__);
 403        xfrm_unregister_type(&mip6_rthdr_type, AF_INET6);
 404        xfrm_unregister_type(&mip6_destopt_type, AF_INET6);
 405}
 406
 407module_init(mip6_init);
 408module_exit(mip6_fini);
 409
 410MODULE_LICENSE("GPL");
 411MODULE_ALIAS_XFRM_TYPE(AF_INET6, XFRM_PROTO_DSTOPTS);
 412MODULE_ALIAS_XFRM_TYPE(AF_INET6, XFRM_PROTO_ROUTING);
 413