root/net/ipv6/mip6.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. calc_padlen
  2. mip6_padn
  3. mip6_param_prob
  4. mip6_mh_len
  5. mip6_mh_filter
  6. mip6_destopt_input
  7. mip6_destopt_output
  8. mip6_report_rl_allow
  9. mip6_destopt_reject
  10. mip6_destopt_offset
  11. mip6_destopt_init_state
  12. mip6_destopt_destroy
  13. mip6_rthdr_input
  14. mip6_rthdr_output
  15. mip6_rthdr_offset
  16. mip6_rthdr_init_state
  17. mip6_rthdr_destroy
  18. mip6_init
  19. mip6_fini

   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 
  26 static inline unsigned int calc_padlen(unsigned int len, unsigned int n)
  27 {
  28         return (n - len + 16) & 0x7;
  29 }
  30 
  31 static 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 
  46 static inline void mip6_param_prob(struct sk_buff *skb, u8 code, int pos)
  47 {
  48         icmpv6_send(skb, ICMPV6_PARAMPROB, code, pos);
  49 }
  50 
  51 static 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 
  74 static 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 
 107 struct 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 
 115 static struct mip6_report_rate_limiter mip6_report_rl = {
 116         .lock = __SPIN_LOCK_UNLOCKED(mip6_report_rl.lock)
 117 };
 118 
 119 static 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  */
 138 static 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 
 175 static 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 
 196 static 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 
 250 static 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 
 298 static 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  */
 322 static void mip6_destopt_destroy(struct xfrm_state *x)
 323 {
 324 }
 325 
 326 static 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 
 339 static 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  */
 357 static 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 
 386 static 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 
 433 static 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  */
 454 static void mip6_rthdr_destroy(struct xfrm_state *x)
 455 {
 456 }
 457 
 458 static 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 
 470 static 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 
 498 static 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 
 506 module_init(mip6_init);
 507 module_exit(mip6_fini);
 508 
 509 MODULE_LICENSE("GPL");
 510 MODULE_ALIAS_XFRM_TYPE(AF_INET6, XFRM_PROTO_DSTOPTS);
 511 MODULE_ALIAS_XFRM_TYPE(AF_INET6, XFRM_PROTO_ROUTING);

/* [<][>][^][v][top][bottom][index][help] */