cregit-Linux how code gets into the kernel

Release 4.14 net/ipv6/mip6.c

Directory: net/ipv6
/*
 * Copyright (C)2003-2006 Helsinki University of Technology
 * Copyright (C)2003-2006 USAGI/WIDE Project
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
/*
 * Authors:
 *      Noriaki TAKAMIYA @USAGI
 *      Masahide NAKAMURA @USAGI
 */


#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/time.h>
#include <linux/ipv6.h>
#include <linux/icmpv6.h>
#include <net/sock.h>
#include <net/ipv6.h>
#include <net/ip6_checksum.h>
#include <net/rawv6.h>
#include <net/xfrm.h>
#include <net/mip6.h>


static inline unsigned int calc_padlen(unsigned int len, unsigned int n) { return (n - len + 16) & 0x7; }

Contributors

PersonTokensPropCommitsCommitProp
Noriaki Takamiya27100.00%1100.00%
Total27100.00%1100.00%


static inline void *mip6_padn(__u8 *data, __u8 padlen) { if (!data) return NULL; if (padlen == 1) { data[0] = IPV6_TLV_PAD1; } else if (padlen > 1) { data[0] = IPV6_TLV_PADN; data[1] = padlen - 2; if (padlen > 2) memset(data+2, 0, data[1]); } return data + padlen; }

Contributors

PersonTokensPropCommitsCommitProp
Noriaki Takamiya8697.73%133.33%
Hideaki Yoshifuji / 吉藤英明11.14%133.33%
Eldad Zack11.14%133.33%
Total88100.00%3100.00%


static inline void mip6_param_prob(struct sk_buff *skb, u8 code, int pos) { icmpv6_send(skb, ICMPV6_PARAMPROB, code, pos); }

Contributors

PersonTokensPropCommitsCommitProp
Masahide Nakamura2896.55%150.00%
Brian Haley13.45%150.00%
Total29100.00%2100.00%


static int mip6_mh_len(int type) { int len = 0; switch (type) { case IP6_MH_TYPE_BRR: len = 0; break; case IP6_MH_TYPE_HOTI: case IP6_MH_TYPE_COTI: case IP6_MH_TYPE_BU: case IP6_MH_TYPE_BACK: len = 1; break; case IP6_MH_TYPE_HOT: case IP6_MH_TYPE_COT: case IP6_MH_TYPE_BERROR: len = 2; break; } return len; }

Contributors

PersonTokensPropCommitsCommitProp
Masahide Nakamura62100.00%1100.00%
Total62100.00%1100.00%


static int mip6_mh_filter(struct sock *sk, struct sk_buff *skb) { struct ip6_mh _hdr; const struct ip6_mh *mh; mh = skb_header_pointer(skb, skb_transport_offset(skb), sizeof(_hdr), &_hdr); if (!mh) return -1; if (((mh->ip6mh_hdrlen + 1) << 3) > skb->len) return -1; if (mh->ip6mh_hdrlen < mip6_mh_len(mh->ip6mh_type)) { net_dbg_ratelimited("mip6: MH message too short: %d vs >=%d\n", mh->ip6mh_hdrlen, mip6_mh_len(mh->ip6mh_type)); mip6_param_prob(skb, 0, offsetof(struct ip6_mh, ip6mh_hdrlen) + skb_network_header_len(skb)); return -1; } if (mh->ip6mh_proto != IPPROTO_NONE) { net_dbg_ratelimited("mip6: MH invalid payload proto = %d\n", mh->ip6mh_proto); mip6_param_prob(skb, 0, offsetof(struct ip6_mh, ip6mh_proto) + skb_network_header_len(skb)); return -1; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Masahide Nakamura11765.73%228.57%
Eric Dumazet4927.53%114.29%
Arnaldo Carvalho de Melo105.62%342.86%
Joe Perches21.12%114.29%
Total178100.00%7100.00%

struct mip6_report_rate_limiter { spinlock_t lock; ktime_t stamp; int iif; struct in6_addr src; struct in6_addr dst; }; static struct mip6_report_rate_limiter mip6_report_rl = { .lock = __SPIN_LOCK_UNLOCKED(mip6_report_rl.lock) };
static int mip6_destopt_input(struct xfrm_state *x, struct sk_buff *skb) { const struct ipv6hdr *iph = ipv6_hdr(skb); struct ipv6_destopt_hdr *destopt = (struct ipv6_destopt_hdr *)skb->data; int err = destopt->nexthdr; spin_lock(&x->lock); if (!ipv6_addr_equal(&iph->saddr, (struct in6_addr *)x->coaddr) && !ipv6_addr_any((struct in6_addr *)x->coaddr)) err = -ENOENT; spin_unlock(&x->lock); return err; }

Contributors

PersonTokensPropCommitsCommitProp
Noriaki Takamiya7470.48%125.00%
Herbert Xu2725.71%125.00%
Arnaldo Carvalho de Melo32.86%125.00%
Eric Dumazet10.95%125.00%
Total105100.00%4100.00%

/* Destination Option Header is inserted. * IP Header's src address is replaced with Home Address Option in * Destination Option Header. */
static int mip6_destopt_output(struct xfrm_state *x, struct sk_buff *skb) { struct ipv6hdr *iph; struct ipv6_destopt_hdr *dstopt; struct ipv6_destopt_hao *hao; u8 nexthdr; int len; skb_push(skb, -skb_network_offset(skb)); iph = ipv6_hdr(skb); nexthdr = *skb_mac_header(skb); *skb_mac_header(skb) = IPPROTO_DSTOPTS; dstopt = (struct ipv6_destopt_hdr *)skb_transport_header(skb); dstopt->nexthdr = nexthdr; hao = mip6_padn((char *)(dstopt + 1), calc_padlen(sizeof(*dstopt), 6)); hao->type = IPV6_TLV_HAO; BUILD_BUG_ON(sizeof(*hao) != 18); hao->length = sizeof(*hao) - 2; len = ((char *)hao - (char *)dstopt) + sizeof(*hao); memcpy(&hao->addr, &iph->saddr, sizeof(hao->addr)); spin_lock_bh(&x->lock); memcpy(&iph->saddr, x->coaddr, sizeof(iph->saddr)); spin_unlock_bh(&x->lock); WARN_ON(len != x->props.header_len); dstopt->hdrlen = (x->props.header_len >> 3) - 1; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Noriaki Takamiya19979.28%114.29%
Herbert Xu3212.75%342.86%
Ilpo Järvinen135.18%114.29%
Arnaldo Carvalho de Melo72.79%228.57%
Total251100.00%7100.00%


static inline int mip6_report_rl_allow(ktime_t stamp, const struct in6_addr *dst, const struct in6_addr *src, int iif) { int allow = 0; spin_lock_bh(&mip6_report_rl.lock); if (mip6_report_rl.stamp != stamp || mip6_report_rl.iif != iif || !ipv6_addr_equal(&mip6_report_rl.src, src) || !ipv6_addr_equal(&mip6_report_rl.dst, dst)) { mip6_report_rl.stamp = stamp; mip6_report_rl.iif = iif; mip6_report_rl.src = *src; mip6_report_rl.dst = *dst; allow = 1; } spin_unlock_bh(&mip6_report_rl.lock); return allow; }

Contributors

PersonTokensPropCommitsCommitProp
Masahide Nakamura10993.16%120.00%
Alexey Dobriyan43.42%120.00%
Eric Dumazet21.71%120.00%
Thomas Gleixner10.85%120.00%
Arnd Bergmann10.85%120.00%
Total117100.00%5100.00%


static int mip6_destopt_reject(struct xfrm_state *x, struct sk_buff *skb, const struct flowi *fl) { struct net *net = xs_net(x); struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb; const struct flowi6 *fl6 = &fl->u.ip6; struct ipv6_destopt_hao *hao = NULL; struct xfrm_selector sel; int offset; ktime_t stamp; int err = 0; if (unlikely(fl6->flowi6_proto == IPPROTO_MH && fl6->fl6_mh_type <= IP6_MH_TYPE_MAX)) goto out; if (likely(opt->dsthao)) { offset = ipv6_find_tlv(skb, opt->dsthao, IPV6_TLV_HAO); if (likely(offset >= 0)) hao = (struct ipv6_destopt_hao *) (skb_network_header(skb) + offset); } stamp = skb_get_ktime(skb); if (!mip6_report_rl_allow(stamp, &ipv6_hdr(skb)->daddr, hao ? &hao->addr : &ipv6_hdr(skb)->saddr, opt->iif)) goto out; memset(&sel, 0, sizeof(sel)); memcpy(&sel.daddr, (xfrm_address_t *)&ipv6_hdr(skb)->daddr, sizeof(sel.daddr)); sel.prefixlen_d = 128; memcpy(&sel.saddr, (xfrm_address_t *)&ipv6_hdr(skb)->saddr, sizeof(sel.saddr)); sel.prefixlen_s = 128; sel.family = AF_INET6; sel.proto = fl6->flowi6_proto; sel.dport = xfrm_flowi_dport(fl, &fl6->uli); if (sel.dport) sel.dport_mask = htons(~0); sel.sport = xfrm_flowi_sport(fl, &fl6->uli); if (sel.sport) sel.sport_mask = htons(~0); sel.ifindex = fl6->flowi6_oif; err = km_report(net, IPPROTO_DSTOPTS, &sel, (hao ? (xfrm_address_t *)&hao->addr : NULL)); out: return err; }

Contributors

PersonTokensPropCommitsCommitProp
Masahide Nakamura31982.22%216.67%
David S. Miller328.25%541.67%
Arnaldo Carvalho de Melo153.87%216.67%
Alexey Dobriyan123.09%18.33%
Al Viro61.55%18.33%
Arnd Bergmann41.03%18.33%
Total388100.00%12100.00%


static int mip6_destopt_offset(struct xfrm_state *x, struct sk_buff *skb, u8 **nexthdr) { u16 offset = sizeof(struct ipv6hdr); struct ipv6_opt_hdr *exthdr = (struct ipv6_opt_hdr *)(ipv6_hdr(skb) + 1); const unsigned char *nh = skb_network_header(skb); unsigned int packet_len = skb_tail_pointer(skb) - skb_network_header(skb); int found_rhdr = 0; *nexthdr = &ipv6_hdr(skb)->nexthdr; while (offset + 1 <= packet_len) { switch (**nexthdr) { case NEXTHDR_HOP: break; case NEXTHDR_ROUTING: found_rhdr = 1; break; case NEXTHDR_DEST: /* * HAO MUST NOT appear more than once. * XXX: It is better to try to find by the end of * XXX: packet if HAO exists. */ if (ipv6_find_tlv(skb, offset, IPV6_TLV_HAO) >= 0) { net_dbg_ratelimited("mip6: hao exists already, override\n"); return offset; } if (found_rhdr) return offset; break; default: return offset; } offset += ipv6_optlen(exthdr); *nexthdr = &exthdr->nexthdr; exthdr = (struct ipv6_opt_hdr *)(nh + offset); } return offset; }

Contributors

PersonTokensPropCommitsCommitProp
Noriaki Takamiya16586.84%116.67%
Arnaldo Carvalho de Melo189.47%350.00%
Simon Horman63.16%116.67%
Joe Perches10.53%116.67%
Total190100.00%6100.00%


static int mip6_destopt_init_state(struct xfrm_state *x) { if (x->id.spi) { pr_info("%s: spi is not 0: %u\n", __func__, x->id.spi); return -EINVAL; } if (x->props.mode != XFRM_MODE_ROUTEOPTIMIZATION) { pr_info("%s: state's mode is not %u: %u\n", __func__, XFRM_MODE_ROUTEOPTIMIZATION, x->props.mode); return -EINVAL; } x->props.header_len = sizeof(struct ipv6_destopt_hdr) + calc_padlen(sizeof(struct ipv6_destopt_hdr), 6) + sizeof(struct ipv6_destopt_hao); WARN_ON(x->props.header_len != 24); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Noriaki Takamiya10694.64%125.00%
Harvey Harrison21.79%125.00%
Joe Perches21.79%125.00%
Ilpo Järvinen21.79%125.00%
Total112100.00%4100.00%

/* * Do nothing about destroying since it has no specific operation for * destination options header unlike IPsec protocols. */
static void mip6_destopt_destroy(struct xfrm_state *x) { }

Contributors

PersonTokensPropCommitsCommitProp
Noriaki Takamiya10100.00%1100.00%
Total10100.00%1100.00%

static const struct xfrm_type mip6_destopt_type = { .description = "MIP6DESTOPT", .owner = THIS_MODULE, .proto = IPPROTO_DSTOPTS, .flags = XFRM_TYPE_NON_FRAGMENT | XFRM_TYPE_LOCAL_COADDR, .init_state = mip6_destopt_init_state, .destructor = mip6_destopt_destroy, .input = mip6_destopt_input, .output = mip6_destopt_output, .reject = mip6_destopt_reject, .hdr_offset = mip6_destopt_offset, };
static int mip6_rthdr_input(struct xfrm_state *x, struct sk_buff *skb) { const struct ipv6hdr *iph = ipv6_hdr(skb); struct rt2_hdr *rt2 = (struct rt2_hdr *)skb->data; int err = rt2->rt_hdr.nexthdr; spin_lock(&x->lock); if (!ipv6_addr_equal(&iph->daddr, (struct in6_addr *)x->coaddr) && !ipv6_addr_any((struct in6_addr *)x->coaddr)) err = -ENOENT; spin_unlock(&x->lock); return err; }

Contributors

PersonTokensPropCommitsCommitProp
Noriaki Takamiya6560.75%125.00%
Herbert Xu2927.10%125.00%
Arnaud Ebalard1211.21%125.00%
Eric Dumazet10.93%125.00%
Total107100.00%4100.00%

/* Routing Header type 2 is inserted. * IP Header's dst address is replaced with Routing Header's Home Address. */
static int mip6_rthdr_output(struct xfrm_state *x, struct sk_buff *skb) { struct ipv6hdr *iph; struct rt2_hdr *rt2; u8 nexthdr; skb_push(skb, -skb_network_offset(skb)); iph = ipv6_hdr(skb); nexthdr = *skb_mac_header(skb); *skb_mac_header(skb) = IPPROTO_ROUTING; rt2 = (struct rt2_hdr *)skb_transport_header(skb); rt2->rt_hdr.nexthdr = nexthdr; rt2->rt_hdr.hdrlen = (x->props.header_len >> 3) - 1; rt2->rt_hdr.type = IPV6_SRCRT_TYPE_2; rt2->rt_hdr.segments_left = 1; memset(&rt2->reserved, 0, sizeof(rt2->reserved)); WARN_ON(rt2->rt_hdr.hdrlen != 2); memcpy(&rt2->addr, &iph->daddr, sizeof(rt2->addr)); spin_lock_bh(&x->lock); memcpy(&iph->daddr, x->coaddr, sizeof(iph->daddr)); spin_unlock_bh(&x->lock); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Noriaki Takamiya16279.80%114.29%
Herbert Xu3215.76%342.86%
Arnaldo Carvalho de Melo73.45%228.57%
Ilpo Järvinen20.99%114.29%
Total203100.00%7100.00%


static int mip6_rthdr_offset(struct xfrm_state *x, struct sk_buff *skb, u8 **nexthdr) { u16 offset = sizeof(struct ipv6hdr); struct ipv6_opt_hdr *exthdr = (struct ipv6_opt_hdr *)(ipv6_hdr(skb) + 1); const unsigned char *nh = skb_network_header(skb); unsigned int packet_len = skb_tail_pointer(skb) - skb_network_header(skb); int found_rhdr = 0; *nexthdr = &ipv6_hdr(skb)->nexthdr; while (offset + 1 <= packet_len) { switch (**nexthdr) { case NEXTHDR_HOP: break; case NEXTHDR_ROUTING: if (offset + 3 <= packet_len) { struct ipv6_rt_hdr *rt; rt = (struct ipv6_rt_hdr *)(nh + offset); if (rt->type != 0) return offset; } found_rhdr = 1; break; case NEXTHDR_DEST: if (ipv6_find_tlv(skb, offset, IPV6_TLV_HAO) >= 0) return offset; if (found_rhdr) return offset; break; default: return offset; } offset += ipv6_optlen(exthdr); *nexthdr = &exthdr->nexthdr; exthdr = (struct ipv6_opt_hdr *)(nh + offset); } return offset; }

Contributors

PersonTokensPropCommitsCommitProp
Noriaki Takamiya19789.14%120.00%
Arnaldo Carvalho de Melo188.14%360.00%
Simon Horman62.71%120.00%
Total221100.00%5100.00%


static int mip6_rthdr_init_state(struct xfrm_state *x) { if (x->id.spi) { pr_info("%s: spi is not 0: %u\n", __func__, x->id.spi); return -EINVAL; } if (x->props.mode != XFRM_MODE_ROUTEOPTIMIZATION) { pr_info("%s: state's mode is not %u: %u\n", __func__, XFRM_MODE_ROUTEOPTIMIZATION, x->props.mode); return -EINVAL; } x->props.header_len = sizeof(struct rt2_hdr); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Noriaki Takamiya8095.24%133.33%
Joe Perches22.38%133.33%
Harvey Harrison22.38%133.33%
Total84100.00%3100.00%

/* * Do nothing about destroying since it has no specific operation for routing * header type 2 unlike IPsec protocols. */
static void mip6_rthdr_destroy(struct xfrm_state *x) { }

Contributors

PersonTokensPropCommitsCommitProp
Noriaki Takamiya10100.00%1100.00%
Total10100.00%1100.00%

static const struct xfrm_type mip6_rthdr_type = { .description = "MIP6RT", .owner = THIS_MODULE, .proto = IPPROTO_ROUTING, .flags = XFRM_TYPE_NON_FRAGMENT | XFRM_TYPE_REMOTE_COADDR, .init_state = mip6_rthdr_init_state, .destructor = mip6_rthdr_destroy, .input = mip6_rthdr_input, .output = mip6_rthdr_output, .hdr_offset = mip6_rthdr_offset, };
static int __init mip6_init(void) { pr_info("Mobile IPv6\n"); if (xfrm_register_type(&mip6_destopt_type, AF_INET6) < 0) { pr_info("%s: can't add xfrm type(destopt)\n", __func__); goto mip6_destopt_xfrm_fail; } if (xfrm_register_type(&mip6_rthdr_type, AF_INET6) < 0) { pr_info("%s: can't add xfrm type(rthdr)\n", __func__); goto mip6_rthdr_xfrm_fail; } if (rawv6_mh_filter_register(mip6_mh_filter) < 0) { pr_info("%s: can't add rawv6 mh filter\n", __func__); goto mip6_rawv6_mh_fail; } return 0; mip6_rawv6_mh_fail: xfrm_unregister_type(&mip6_rthdr_type, AF_INET6); mip6_rthdr_xfrm_fail: xfrm_unregister_type(&mip6_destopt_type, AF_INET6); mip6_destopt_xfrm_fail: return -EAGAIN; }

Contributors

PersonTokensPropCommitsCommitProp
Noriaki Takamiya7566.96%240.00%
Masahide Nakamura3026.79%120.00%
Joe Perches43.57%120.00%
Harvey Harrison32.68%120.00%
Total112100.00%5100.00%


static void __exit mip6_fini(void) { if (rawv6_mh_filter_unregister(mip6_mh_filter) < 0) pr_info("%s: can't remove rawv6 mh filter\n", __func__); if (xfrm_unregister_type(&mip6_rthdr_type, AF_INET6) < 0) pr_info("%s: can't remove xfrm type(rthdr)\n", __func__); if (xfrm_unregister_type(&mip6_destopt_type, AF_INET6) < 0) pr_info("%s: can't remove xfrm type(destopt)\n", __func__); }

Contributors

PersonTokensPropCommitsCommitProp
Noriaki Takamiya4266.67%240.00%
Masahide Nakamura1523.81%120.00%
Joe Perches34.76%120.00%
Harvey Harrison34.76%120.00%
Total63100.00%5100.00%

module_init(mip6_init); module_exit(mip6_fini); MODULE_LICENSE("GPL"); MODULE_ALIAS_XFRM_TYPE(AF_INET6, XFRM_PROTO_DSTOPTS); MODULE_ALIAS_XFRM_TYPE(AF_INET6, XFRM_PROTO_ROUTING);

Overall Contributors

PersonTokensPropCommitsCommitProp
Noriaki Takamiya142555.15%24.88%
Masahide Nakamura76129.45%512.20%
Herbert Xu1244.80%512.20%
Arnaldo Carvalho de Melo783.02%512.20%
Eric Dumazet552.13%37.32%
David S. Miller321.24%512.20%
Joe Perches210.81%24.88%
Ilpo Järvinen170.66%12.44%
Alexey Dobriyan160.62%24.88%
Simon Horman120.46%12.44%
Arnaud Ebalard120.46%12.44%
Harvey Harrison100.39%12.44%
Al Viro60.23%12.44%
Arnd Bergmann60.23%12.44%
Milind Arun Choudhary40.15%12.44%
Jeff Kirsher10.04%12.44%
Brian Haley10.04%12.44%
Hideaki Yoshifuji / 吉藤英明10.04%12.44%
Thomas Gleixner10.04%12.44%
Eldad Zack10.04%12.44%
Total2584100.00%41100.00%
Directory: net/ipv6
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.