Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[IPV6] MIP6: Loadable module support for MIPv6.

This patch makes MIPv6 loadable module named "mip6".

Here is a modprobe.conf(5) example to load it automatically
when user application uses XFRM state for MIPv6:

alias xfrm-type-10-43 mip6
alias xfrm-type-10-60 mip6

Some MIPv6 feature is not included by this modular, however,
it should not be affected to other features like either IPsec
or IPv6 with and without the patch.
We may discuss XFRM, MH (RAW socket) and ancillary data/sockopt
separately for future work.

Loadable features:
* MH receiving check (to send ICMP error back)
* RO header parsing and building (i.e. RH2 and HAO in DSTOPTS)
* XFRM policy/state database handling for RO

These are NOT covered as loadable:
* Home Address flags and its rule on source address selection
* XFRM sub policy (depends on its own kernel option)
* XFRM functions to receive RO as IPv6 extension header
* MH sending/receiving through raw socket if user application
opens it (since raw socket allows to do so)
* RH2 sending as ancillary data
* RH2 operation with setsockopt(2)

Signed-off-by: Masahide NAKAMURA <nakam@linux-ipv6.org>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Masahide NAKAMURA and committed by
David S. Miller
59fbb3a6 136ebf08

+88 -46
+1 -1
include/linux/ipv6.h
··· 247 247 __u16 lastopt; 248 248 __u32 nhoff; 249 249 __u16 flags; 250 - #ifdef CONFIG_IPV6_MIP6 250 + #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) 251 251 __u16 dsthao; 252 252 #endif 253 253
+1 -1
include/net/addrconf.h
··· 61 61 extern int ipv6_chk_addr(struct in6_addr *addr, 62 62 struct net_device *dev, 63 63 int strict); 64 - #ifdef CONFIG_IPV6_MIP6 64 + #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) 65 65 extern int ipv6_chk_home_addr(struct in6_addr *addr); 66 66 #endif 67 67 extern struct inet6_ifaddr * ipv6_get_ifaddr(struct in6_addr *addr,
-4
include/net/mip6.h
··· 54 54 #define IP6_MH_TYPE_BERROR 7 /* Binding Error */ 55 55 #define IP6_MH_TYPE_MAX IP6_MH_TYPE_BERROR 56 56 57 - extern int mip6_init(void); 58 - extern void mip6_fini(void); 59 - extern int mip6_mh_filter(struct sock *sk, struct sk_buff *skb); 60 - 61 57 #endif
+9
include/net/rawv6.h
··· 3 3 4 4 #ifdef __KERNEL__ 5 5 6 + #include <net/protocol.h> 7 + 6 8 #define RAWV6_HTABLE_SIZE MAX_INET_PROTOS 7 9 extern struct hlist_head raw_v6_htable[RAWV6_HTABLE_SIZE]; 8 10 extern rwlock_t raw_v6_lock; ··· 24 22 struct inet6_skb_parm *opt, 25 23 int type, int code, 26 24 int offset, __be32 info); 25 + 26 + #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) 27 + int rawv6_mh_filter_register(int (*filter)(struct sock *sock, 28 + struct sk_buff *skb)); 29 + int rawv6_mh_filter_unregister(int (*filter)(struct sock *sock, 30 + struct sk_buff *skb)); 31 + #endif 27 32 28 33 #endif 29 34
+1 -1
net/ipv6/Kconfig
··· 109 109 If unsure, say Y. 110 110 111 111 config IPV6_MIP6 112 - bool "IPv6: Mobility (EXPERIMENTAL)" 112 + tristate "IPv6: Mobility (EXPERIMENTAL)" 113 113 depends on IPV6 && EXPERIMENTAL 114 114 select XFRM 115 115 ---help---
+1 -1
net/ipv6/Makefile
··· 14 14 xfrm6_output.o 15 15 ipv6-$(CONFIG_NETFILTER) += netfilter.o 16 16 ipv6-$(CONFIG_IPV6_MULTIPLE_TABLES) += fib6_rules.o 17 - ipv6-$(CONFIG_IPV6_MIP6) += mip6.o 18 17 ipv6-$(CONFIG_PROC_FS) += proc.o 19 18 20 19 ipv6-objs += $(ipv6-y) ··· 27 28 obj-$(CONFIG_INET6_XFRM_MODE_TUNNEL) += xfrm6_mode_tunnel.o 28 29 obj-$(CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION) += xfrm6_mode_ro.o 29 30 obj-$(CONFIG_INET6_XFRM_MODE_BEET) += xfrm6_mode_beet.o 31 + obj-$(CONFIG_IPV6_MIP6) += mip6.o 30 32 obj-$(CONFIG_NETFILTER) += netfilter/ 31 33 32 34 obj-$(CONFIG_IPV6_SIT) += sit.o
+2 -2
net/ipv6/addrconf.c
··· 1034 1034 } 1035 1035 1036 1036 /* Rule 4: Prefer home address */ 1037 - #ifdef CONFIG_IPV6_MIP6 1037 + #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) 1038 1038 if (hiscore.rule < 4) { 1039 1039 if (ifa_result->flags & IFA_F_HOMEADDRESS) 1040 1040 hiscore.attrs |= IPV6_SADDR_SCORE_HOA; ··· 2835 2835 } 2836 2836 #endif /* CONFIG_PROC_FS */ 2837 2837 2838 - #ifdef CONFIG_IPV6_MIP6 2838 + #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) 2839 2839 /* Check if address is a home address configured on any interface. */ 2840 2840 int ipv6_chk_home_addr(struct in6_addr *addr) 2841 2841 {
+1 -9
net/ipv6/af_inet6.c
··· 58 58 #ifdef CONFIG_IPV6_TUNNEL 59 59 #include <net/ip6_tunnel.h> 60 60 #endif 61 - #ifdef CONFIG_IPV6_MIP6 62 - #include <net/mip6.h> 63 - #endif 64 61 65 62 #include <asm/uaccess.h> 66 63 #include <asm/system.h> ··· 850 853 ipv6_frag_init(); 851 854 ipv6_nodata_init(); 852 855 ipv6_destopt_init(); 853 - #ifdef CONFIG_IPV6_MIP6 854 - mip6_init(); 855 - #endif 856 856 857 857 /* Init v6 transport protocols. */ 858 858 udpv6_init(); ··· 915 921 916 922 /* Cleanup code parts. */ 917 923 ipv6_packet_cleanup(); 918 - #ifdef CONFIG_IPV6_MIP6 919 - mip6_fini(); 920 - #endif 924 + 921 925 addrconf_cleanup(); 922 926 ip6_flowlabel_cleanup(); 923 927 ip6_route_cleanup();
+4 -4
net/ipv6/ah6.c
··· 74 74 return 0; 75 75 } 76 76 77 - #ifdef CONFIG_IPV6_MIP6 77 + #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) 78 78 /** 79 79 * ipv6_rearrange_destopt - rearrange IPv6 destination options header 80 80 * @iph: IPv6 header ··· 228 228 u8 nexthdr; 229 229 char tmp_base[8]; 230 230 struct { 231 - #ifdef CONFIG_IPV6_MIP6 231 + #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) 232 232 struct in6_addr saddr; 233 233 #endif 234 234 struct in6_addr daddr; ··· 255 255 err = -ENOMEM; 256 256 goto error; 257 257 } 258 - #ifdef CONFIG_IPV6_MIP6 258 + #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) 259 259 memcpy(tmp_ext, &top_iph->saddr, extlen); 260 260 #else 261 261 memcpy(tmp_ext, &top_iph->daddr, extlen); ··· 294 294 295 295 memcpy(top_iph, tmp_base, sizeof(tmp_base)); 296 296 if (tmp_ext) { 297 - #ifdef CONFIG_IPV6_MIP6 297 + #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) 298 298 memcpy(&top_iph->saddr, tmp_ext, extlen); 299 299 #else 300 300 memcpy(&top_iph->daddr, tmp_ext, extlen);
+1 -1
net/ipv6/datagram.c
··· 658 658 659 659 switch (rthdr->type) { 660 660 case IPV6_SRCRT_TYPE_0: 661 - #ifdef CONFIG_IPV6_MIP6 661 + #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) 662 662 case IPV6_SRCRT_TYPE_2: 663 663 #endif 664 664 break;
+10 -9
net/ipv6/exthdrs.c
··· 42 42 #include <net/ndisc.h> 43 43 #include <net/ip6_route.h> 44 44 #include <net/addrconf.h> 45 - #ifdef CONFIG_IPV6_MIP6 45 + #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) 46 46 #include <net/xfrm.h> 47 47 #endif 48 48 ··· 90 90 bad: 91 91 return -1; 92 92 } 93 + EXPORT_SYMBOL_GPL(ipv6_find_tlv); 93 94 94 95 /* 95 96 * Parsing tlv encoded headers. ··· 197 196 Destination options header. 198 197 *****************************/ 199 198 200 - #ifdef CONFIG_IPV6_MIP6 199 + #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) 201 200 static int ipv6_dest_hao(struct sk_buff **skbp, int optoff) 202 201 { 203 202 struct sk_buff *skb = *skbp; ··· 271 270 #endif 272 271 273 272 static struct tlvtype_proc tlvprocdestopt_lst[] = { 274 - #ifdef CONFIG_IPV6_MIP6 273 + #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) 275 274 { 276 275 .type = IPV6_TLV_HAO, 277 276 .func = ipv6_dest_hao, ··· 284 283 { 285 284 struct sk_buff *skb = *skbp; 286 285 struct inet6_skb_parm *opt = IP6CB(skb); 287 - #ifdef CONFIG_IPV6_MIP6 286 + #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) 288 287 __u16 dstbuf; 289 288 #endif 290 289 struct dst_entry *dst; ··· 299 298 } 300 299 301 300 opt->lastopt = opt->dst1 = skb_network_header_len(skb); 302 - #ifdef CONFIG_IPV6_MIP6 301 + #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) 303 302 dstbuf = opt->dst1; 304 303 #endif 305 304 ··· 309 308 skb = *skbp; 310 309 skb->transport_header += (skb_transport_header(skb)[1] + 1) << 3; 311 310 opt = IP6CB(skb); 312 - #ifdef CONFIG_IPV6_MIP6 311 + #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) 313 312 opt->nhoff = dstbuf; 314 313 #else 315 314 opt->nhoff = opt->dst1; ··· 428 427 looped_back: 429 428 if (hdr->segments_left == 0) { 430 429 switch (hdr->type) { 431 - #ifdef CONFIG_IPV6_MIP6 430 + #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) 432 431 case IPV6_SRCRT_TYPE_2: 433 432 /* Silently discard type 2 header unless it was 434 433 * processed by own ··· 464 463 return -1; 465 464 } 466 465 break; 467 - #ifdef CONFIG_IPV6_MIP6 466 + #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) 468 467 case IPV6_SRCRT_TYPE_2: 469 468 /* Silently discard invalid RTH type 2 */ 470 469 if (hdr->hdrlen != 2 || hdr->segments_left != 1) { ··· 521 520 addr += i - 1; 522 521 523 522 switch (hdr->type) { 524 - #ifdef CONFIG_IPV6_MIP6 523 + #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) 525 524 case IPV6_SRCRT_TYPE_2: 526 525 if (xfrm6_input_addr(skb, (xfrm_address_t *)addr, 527 526 (xfrm_address_t *)&ipv6_hdr(skb)->saddr,
+1 -1
net/ipv6/icmp.c
··· 272 272 return 0; 273 273 } 274 274 275 - #ifdef CONFIG_IPV6_MIP6 275 + #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) 276 276 static void mip6_addr_swap(struct sk_buff *skb) 277 277 { 278 278 struct ipv6hdr *iph = ipv6_hdr(skb);
+1 -1
net/ipv6/ip6_output.c
··· 543 543 found_rhdr = 1; 544 544 break; 545 545 case NEXTHDR_DEST: 546 - #ifdef CONFIG_IPV6_MIP6 546 + #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) 547 547 if (ipv6_find_tlv(skb, offset, IPV6_TLV_HAO) >= 0) 548 548 break; 549 549 #endif
+1 -1
net/ipv6/ipv6_sockglue.c
··· 417 417 struct ipv6_rt_hdr *rthdr = opt->srcrt; 418 418 switch (rthdr->type) { 419 419 case IPV6_SRCRT_TYPE_0: 420 - #ifdef CONFIG_IPV6_MIP6 420 + #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) 421 421 case IPV6_SRCRT_TYPE_2: 422 422 #endif 423 423 break;
+19 -3
net/ipv6/mip6.c
··· 30 30 #include <net/sock.h> 31 31 #include <net/ipv6.h> 32 32 #include <net/ip6_checksum.h> 33 + #include <net/rawv6.h> 33 34 #include <net/xfrm.h> 34 35 #include <net/mip6.h> 35 36 ··· 87 86 return len; 88 87 } 89 88 90 - int mip6_mh_filter(struct sock *sk, struct sk_buff *skb) 89 + static int mip6_mh_filter(struct sock *sk, struct sk_buff *skb) 91 90 { 92 91 struct ip6_mh *mh; 93 92 ··· 472 471 .remote_addr = mip6_xfrm_addr, 473 472 }; 474 473 475 - int __init mip6_init(void) 474 + static int __init mip6_init(void) 476 475 { 477 476 printk(KERN_INFO "Mobile IPv6\n"); 478 477 ··· 484 483 printk(KERN_INFO "%s: can't add xfrm type(rthdr)\n", __FUNCTION__); 485 484 goto mip6_rthdr_xfrm_fail; 486 485 } 486 + if (rawv6_mh_filter_register(mip6_mh_filter) < 0) { 487 + printk(KERN_INFO "%s: can't add rawv6 mh filter\n", __FUNCTION__); 488 + goto mip6_rawv6_mh_fail; 489 + } 490 + 491 + 487 492 return 0; 488 493 494 + mip6_rawv6_mh_fail: 495 + xfrm_unregister_type(&mip6_rthdr_type, AF_INET6); 489 496 mip6_rthdr_xfrm_fail: 490 497 xfrm_unregister_type(&mip6_destopt_type, AF_INET6); 491 498 mip6_destopt_xfrm_fail: 492 499 return -EAGAIN; 493 500 } 494 501 495 - void __exit mip6_fini(void) 502 + static void __exit mip6_fini(void) 496 503 { 504 + if (rawv6_mh_filter_unregister(mip6_mh_filter) < 0) 505 + printk(KERN_INFO "%s: can't remove rawv6 mh filter\n", __FUNCTION__); 497 506 if (xfrm_unregister_type(&mip6_rthdr_type, AF_INET6) < 0) 498 507 printk(KERN_INFO "%s: can't remove xfrm type(rthdr)\n", __FUNCTION__); 499 508 if (xfrm_unregister_type(&mip6_destopt_type, AF_INET6) < 0) 500 509 printk(KERN_INFO "%s: can't remove xfrm type(destopt)\n", __FUNCTION__); 501 510 } 511 + 512 + module_init(mip6_init); 513 + module_exit(mip6_fini); 514 + 515 + MODULE_LICENSE("GPL");
+31 -3
net/ipv6/raw.c
··· 49 49 #include <net/udp.h> 50 50 #include <net/inet_common.h> 51 51 #include <net/tcp_states.h> 52 - #ifdef CONFIG_IPV6_MIP6 52 + #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) 53 53 #include <net/mip6.h> 54 54 #endif 55 55 ··· 137 137 return 0; 138 138 } 139 139 140 + #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) 141 + static int (*mh_filter)(struct sock *sock, struct sk_buff *skb); 142 + 143 + int rawv6_mh_filter_register(int (*filter)(struct sock *sock, 144 + struct sk_buff *skb)) 145 + { 146 + rcu_assign_pointer(mh_filter, filter); 147 + return 0; 148 + } 149 + EXPORT_SYMBOL(rawv6_mh_filter_register); 150 + 151 + int rawv6_mh_filter_unregister(int (*filter)(struct sock *sock, 152 + struct sk_buff *skb)) 153 + { 154 + rcu_assign_pointer(mh_filter, NULL); 155 + synchronize_rcu(); 156 + return 0; 157 + } 158 + EXPORT_SYMBOL(rawv6_mh_filter_unregister); 159 + 160 + #endif 161 + 140 162 /* 141 163 * demultiplex raw sockets. 142 164 * (should consider queueing the skb in the sock receive_queue ··· 200 178 case IPPROTO_ICMPV6: 201 179 filtered = icmpv6_filter(sk, skb); 202 180 break; 203 - #ifdef CONFIG_IPV6_MIP6 181 + 182 + #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) 204 183 case IPPROTO_MH: 184 + { 205 185 /* XXX: To validate MH only once for each packet, 206 186 * this is placed here. It should be after checking 207 187 * xfrm policy, however it doesn't. The checking xfrm 208 188 * policy is placed in rawv6_rcv() because it is 209 189 * required for each socket. 210 190 */ 211 - filtered = mip6_mh_filter(sk, skb); 191 + int (*filter)(struct sock *sock, struct sk_buff *skb); 192 + 193 + filter = rcu_dereference(mh_filter); 194 + filtered = filter ? filter(sk, skb) : 0; 212 195 break; 196 + } 213 197 #endif 214 198 default: 215 199 filtered = 0;
+2 -2
net/ipv6/xfrm6_policy.c
··· 18 18 #include <net/ip.h> 19 19 #include <net/ipv6.h> 20 20 #include <net/ip6_route.h> 21 - #ifdef CONFIG_IPV6_MIP6 21 + #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) 22 22 #include <net/mip6.h> 23 23 #endif 24 24 ··· 318 318 fl->proto = nexthdr; 319 319 return; 320 320 321 - #ifdef CONFIG_IPV6_MIP6 321 + #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) 322 322 case IPPROTO_MH: 323 323 if (pskb_may_pull(skb, nh + offset + 3 - skb->data)) { 324 324 struct ip6_mh *mh;
+2 -2
net/ipv6/xfrm6_state.c
··· 65 65 goto end; 66 66 67 67 /* Rule 2: select MIPv6 RO or inbound trigger */ 68 - #ifdef CONFIG_IPV6_MIP6 68 + #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) 69 69 for (i = 0; i < n; i++) { 70 70 if (src[i] && 71 71 (src[i]->props.mode == XFRM_MODE_ROUTEOPTIMIZATION || ··· 130 130 goto end; 131 131 132 132 /* Rule 2: select MIPv6 RO or inbound trigger */ 133 - #ifdef CONFIG_IPV6_MIP6 133 + #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) 134 134 for (i = 0; i < n; i++) { 135 135 if (src[i] && 136 136 (src[i]->mode == XFRM_MODE_ROUTEOPTIMIZATION ||