diff options
Diffstat (limited to 'net/ipv6')
| -rw-r--r-- | net/ipv6/Kconfig | 10 | ||||
| -rw-r--r-- | net/ipv6/Makefile | 1 | ||||
| -rw-r--r-- | net/ipv6/ipcomp6.c | 5 | ||||
| -rw-r--r-- | net/ipv6/udp.c | 64 | ||||
| -rw-r--r-- | net/ipv6/xfrm6_mode_beet.c | 107 |
5 files changed, 155 insertions, 32 deletions
diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig index a2d211da2aba..a460e8132b4d 100644 --- a/net/ipv6/Kconfig +++ b/net/ipv6/Kconfig | |||
| @@ -136,6 +136,16 @@ config INET6_XFRM_MODE_TUNNEL | |||
| 136 | 136 | ||
| 137 | If unsure, say Y. | 137 | If unsure, say Y. |
| 138 | 138 | ||
| 139 | config INET6_XFRM_MODE_BEET | ||
| 140 | tristate "IPv6: IPsec BEET mode" | ||
| 141 | depends on IPV6 | ||
| 142 | default IPV6 | ||
| 143 | select XFRM | ||
| 144 | ---help--- | ||
| 145 | Support for IPsec BEET mode. | ||
| 146 | |||
| 147 | If unsure, say Y. | ||
| 148 | |||
| 139 | config INET6_XFRM_MODE_ROUTEOPTIMIZATION | 149 | config INET6_XFRM_MODE_ROUTEOPTIMIZATION |
| 140 | tristate "IPv6: MIPv6 route optimization mode (EXPERIMENTAL)" | 150 | tristate "IPv6: MIPv6 route optimization mode (EXPERIMENTAL)" |
| 141 | depends on IPV6 && EXPERIMENTAL | 151 | depends on IPV6 && EXPERIMENTAL |
diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile index 0213c6612b58..87274e47fe32 100644 --- a/net/ipv6/Makefile +++ b/net/ipv6/Makefile | |||
| @@ -26,6 +26,7 @@ obj-$(CONFIG_INET6_TUNNEL) += tunnel6.o | |||
| 26 | obj-$(CONFIG_INET6_XFRM_MODE_TRANSPORT) += xfrm6_mode_transport.o | 26 | obj-$(CONFIG_INET6_XFRM_MODE_TRANSPORT) += xfrm6_mode_transport.o |
| 27 | obj-$(CONFIG_INET6_XFRM_MODE_TUNNEL) += xfrm6_mode_tunnel.o | 27 | obj-$(CONFIG_INET6_XFRM_MODE_TUNNEL) += xfrm6_mode_tunnel.o |
| 28 | obj-$(CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION) += xfrm6_mode_ro.o | 28 | obj-$(CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION) += xfrm6_mode_ro.o |
| 29 | obj-$(CONFIG_INET6_XFRM_MODE_BEET) += xfrm6_mode_beet.o | ||
| 29 | obj-$(CONFIG_NETFILTER) += netfilter/ | 30 | obj-$(CONFIG_NETFILTER) += netfilter/ |
| 30 | 31 | ||
| 31 | obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o | 32 | obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o |
diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c index a2860e35efd7..71f59f18ede8 100644 --- a/net/ipv6/ipcomp6.c +++ b/net/ipv6/ipcomp6.c | |||
| @@ -199,6 +199,7 @@ static void ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
| 199 | static struct xfrm_state *ipcomp6_tunnel_create(struct xfrm_state *x) | 199 | static struct xfrm_state *ipcomp6_tunnel_create(struct xfrm_state *x) |
| 200 | { | 200 | { |
| 201 | struct xfrm_state *t = NULL; | 201 | struct xfrm_state *t = NULL; |
| 202 | u8 mode = XFRM_MODE_TUNNEL; | ||
| 202 | 203 | ||
| 203 | t = xfrm_state_alloc(); | 204 | t = xfrm_state_alloc(); |
| 204 | if (!t) | 205 | if (!t) |
| @@ -212,7 +213,9 @@ static struct xfrm_state *ipcomp6_tunnel_create(struct xfrm_state *x) | |||
| 212 | memcpy(t->id.daddr.a6, x->id.daddr.a6, sizeof(struct in6_addr)); | 213 | memcpy(t->id.daddr.a6, x->id.daddr.a6, sizeof(struct in6_addr)); |
| 213 | memcpy(&t->sel, &x->sel, sizeof(t->sel)); | 214 | memcpy(&t->sel, &x->sel, sizeof(t->sel)); |
| 214 | t->props.family = AF_INET6; | 215 | t->props.family = AF_INET6; |
| 215 | t->props.mode = XFRM_MODE_TUNNEL; | 216 | if (x->props.mode == XFRM_MODE_BEET) |
| 217 | mode = x->props.mode; | ||
| 218 | t->props.mode = mode; | ||
| 216 | memcpy(t->props.saddr.a6, x->props.saddr.a6, sizeof(struct in6_addr)); | 219 | memcpy(t->props.saddr.a6, x->props.saddr.a6, sizeof(struct in6_addr)); |
| 217 | 220 | ||
| 218 | if (xfrm_init_state(t)) | 221 | if (xfrm_init_state(t)) |
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 9662561701d1..e0c3934a7e4b 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
| @@ -546,7 +546,7 @@ static int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
| 546 | struct in6_addr *daddr, *final_p = NULL, final; | 546 | struct in6_addr *daddr, *final_p = NULL, final; |
| 547 | struct ipv6_txoptions *opt = NULL; | 547 | struct ipv6_txoptions *opt = NULL; |
| 548 | struct ip6_flowlabel *flowlabel = NULL; | 548 | struct ip6_flowlabel *flowlabel = NULL; |
| 549 | struct flowi *fl = &inet->cork.fl; | 549 | struct flowi fl; |
| 550 | struct dst_entry *dst; | 550 | struct dst_entry *dst; |
| 551 | int addr_len = msg->msg_namelen; | 551 | int addr_len = msg->msg_namelen; |
| 552 | int ulen = len; | 552 | int ulen = len; |
| @@ -626,19 +626,19 @@ do_udp_sendmsg: | |||
| 626 | } | 626 | } |
| 627 | ulen += sizeof(struct udphdr); | 627 | ulen += sizeof(struct udphdr); |
| 628 | 628 | ||
| 629 | memset(fl, 0, sizeof(*fl)); | 629 | memset(&fl, 0, sizeof(fl)); |
| 630 | 630 | ||
| 631 | if (sin6) { | 631 | if (sin6) { |
| 632 | if (sin6->sin6_port == 0) | 632 | if (sin6->sin6_port == 0) |
| 633 | return -EINVAL; | 633 | return -EINVAL; |
| 634 | 634 | ||
| 635 | fl->fl_ip_dport = sin6->sin6_port; | 635 | fl.fl_ip_dport = sin6->sin6_port; |
| 636 | daddr = &sin6->sin6_addr; | 636 | daddr = &sin6->sin6_addr; |
| 637 | 637 | ||
| 638 | if (np->sndflow) { | 638 | if (np->sndflow) { |
| 639 | fl->fl6_flowlabel = sin6->sin6_flowinfo&IPV6_FLOWINFO_MASK; | 639 | fl.fl6_flowlabel = sin6->sin6_flowinfo&IPV6_FLOWINFO_MASK; |
| 640 | if (fl->fl6_flowlabel&IPV6_FLOWLABEL_MASK) { | 640 | if (fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) { |
| 641 | flowlabel = fl6_sock_lookup(sk, fl->fl6_flowlabel); | 641 | flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel); |
| 642 | if (flowlabel == NULL) | 642 | if (flowlabel == NULL) |
| 643 | return -EINVAL; | 643 | return -EINVAL; |
| 644 | daddr = &flowlabel->dst; | 644 | daddr = &flowlabel->dst; |
| @@ -656,32 +656,32 @@ do_udp_sendmsg: | |||
| 656 | if (addr_len >= sizeof(struct sockaddr_in6) && | 656 | if (addr_len >= sizeof(struct sockaddr_in6) && |
| 657 | sin6->sin6_scope_id && | 657 | sin6->sin6_scope_id && |
| 658 | ipv6_addr_type(daddr)&IPV6_ADDR_LINKLOCAL) | 658 | ipv6_addr_type(daddr)&IPV6_ADDR_LINKLOCAL) |
| 659 | fl->oif = sin6->sin6_scope_id; | 659 | fl.oif = sin6->sin6_scope_id; |
| 660 | } else { | 660 | } else { |
| 661 | if (sk->sk_state != TCP_ESTABLISHED) | 661 | if (sk->sk_state != TCP_ESTABLISHED) |
| 662 | return -EDESTADDRREQ; | 662 | return -EDESTADDRREQ; |
| 663 | 663 | ||
| 664 | fl->fl_ip_dport = inet->dport; | 664 | fl.fl_ip_dport = inet->dport; |
| 665 | daddr = &np->daddr; | 665 | daddr = &np->daddr; |
| 666 | fl->fl6_flowlabel = np->flow_label; | 666 | fl.fl6_flowlabel = np->flow_label; |
| 667 | connected = 1; | 667 | connected = 1; |
| 668 | } | 668 | } |
| 669 | 669 | ||
| 670 | if (!fl->oif) | 670 | if (!fl.oif) |
| 671 | fl->oif = sk->sk_bound_dev_if; | 671 | fl.oif = sk->sk_bound_dev_if; |
| 672 | 672 | ||
| 673 | if (msg->msg_controllen) { | 673 | if (msg->msg_controllen) { |
| 674 | opt = &opt_space; | 674 | opt = &opt_space; |
| 675 | memset(opt, 0, sizeof(struct ipv6_txoptions)); | 675 | memset(opt, 0, sizeof(struct ipv6_txoptions)); |
| 676 | opt->tot_len = sizeof(*opt); | 676 | opt->tot_len = sizeof(*opt); |
| 677 | 677 | ||
| 678 | err = datagram_send_ctl(msg, fl, opt, &hlimit, &tclass); | 678 | err = datagram_send_ctl(msg, &fl, opt, &hlimit, &tclass); |
| 679 | if (err < 0) { | 679 | if (err < 0) { |
| 680 | fl6_sock_release(flowlabel); | 680 | fl6_sock_release(flowlabel); |
| 681 | return err; | 681 | return err; |
| 682 | } | 682 | } |
| 683 | if ((fl->fl6_flowlabel&IPV6_FLOWLABEL_MASK) && !flowlabel) { | 683 | if ((fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) && !flowlabel) { |
| 684 | flowlabel = fl6_sock_lookup(sk, fl->fl6_flowlabel); | 684 | flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel); |
| 685 | if (flowlabel == NULL) | 685 | if (flowlabel == NULL) |
| 686 | return -EINVAL; | 686 | return -EINVAL; |
| 687 | } | 687 | } |
| @@ -695,39 +695,39 @@ do_udp_sendmsg: | |||
| 695 | opt = fl6_merge_options(&opt_space, flowlabel, opt); | 695 | opt = fl6_merge_options(&opt_space, flowlabel, opt); |
| 696 | opt = ipv6_fixup_options(&opt_space, opt); | 696 | opt = ipv6_fixup_options(&opt_space, opt); |
| 697 | 697 | ||
| 698 | fl->proto = IPPROTO_UDP; | 698 | fl.proto = IPPROTO_UDP; |
| 699 | ipv6_addr_copy(&fl->fl6_dst, daddr); | 699 | ipv6_addr_copy(&fl.fl6_dst, daddr); |
| 700 | if (ipv6_addr_any(&fl->fl6_src) && !ipv6_addr_any(&np->saddr)) | 700 | if (ipv6_addr_any(&fl.fl6_src) && !ipv6_addr_any(&np->saddr)) |
| 701 | ipv6_addr_copy(&fl->fl6_src, &np->saddr); | 701 | ipv6_addr_copy(&fl.fl6_src, &np->saddr); |
| 702 | fl->fl_ip_sport = inet->sport; | 702 | fl.fl_ip_sport = inet->sport; |
| 703 | 703 | ||
| 704 | /* merge ip6_build_xmit from ip6_output */ | 704 | /* merge ip6_build_xmit from ip6_output */ |
| 705 | if (opt && opt->srcrt) { | 705 | if (opt && opt->srcrt) { |
| 706 | struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt; | 706 | struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt; |
| 707 | ipv6_addr_copy(&final, &fl->fl6_dst); | 707 | ipv6_addr_copy(&final, &fl.fl6_dst); |
| 708 | ipv6_addr_copy(&fl->fl6_dst, rt0->addr); | 708 | ipv6_addr_copy(&fl.fl6_dst, rt0->addr); |
| 709 | final_p = &final; | 709 | final_p = &final; |
| 710 | connected = 0; | 710 | connected = 0; |
| 711 | } | 711 | } |
| 712 | 712 | ||
| 713 | if (!fl->oif && ipv6_addr_is_multicast(&fl->fl6_dst)) { | 713 | if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst)) { |
| 714 | fl->oif = np->mcast_oif; | 714 | fl.oif = np->mcast_oif; |
| 715 | connected = 0; | 715 | connected = 0; |
| 716 | } | 716 | } |
| 717 | 717 | ||
| 718 | security_sk_classify_flow(sk, fl); | 718 | security_sk_classify_flow(sk, &fl); |
| 719 | 719 | ||
| 720 | err = ip6_sk_dst_lookup(sk, &dst, fl); | 720 | err = ip6_sk_dst_lookup(sk, &dst, &fl); |
| 721 | if (err) | 721 | if (err) |
| 722 | goto out; | 722 | goto out; |
| 723 | if (final_p) | 723 | if (final_p) |
| 724 | ipv6_addr_copy(&fl->fl6_dst, final_p); | 724 | ipv6_addr_copy(&fl.fl6_dst, final_p); |
| 725 | 725 | ||
| 726 | if ((err = xfrm_lookup(&dst, fl, sk, 0)) < 0) | 726 | if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) |
| 727 | goto out; | 727 | goto out; |
| 728 | 728 | ||
| 729 | if (hlimit < 0) { | 729 | if (hlimit < 0) { |
| 730 | if (ipv6_addr_is_multicast(&fl->fl6_dst)) | 730 | if (ipv6_addr_is_multicast(&fl.fl6_dst)) |
| 731 | hlimit = np->mcast_hops; | 731 | hlimit = np->mcast_hops; |
| 732 | else | 732 | else |
| 733 | hlimit = np->hop_limit; | 733 | hlimit = np->hop_limit; |
| @@ -763,21 +763,23 @@ back_from_confirm: | |||
| 763 | do_append_data: | 763 | do_append_data: |
| 764 | up->len += ulen; | 764 | up->len += ulen; |
| 765 | err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov, ulen, | 765 | err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov, ulen, |
| 766 | sizeof(struct udphdr), hlimit, tclass, opt, fl, | 766 | sizeof(struct udphdr), hlimit, tclass, opt, &fl, |
| 767 | (struct rt6_info*)dst, | 767 | (struct rt6_info*)dst, |
| 768 | corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags); | 768 | corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags); |
| 769 | if (err) | 769 | if (err) |
| 770 | udp_v6_flush_pending_frames(sk); | 770 | udp_v6_flush_pending_frames(sk); |
| 771 | else if (!corkreq) | 771 | else if (!corkreq) |
| 772 | err = udp_v6_push_pending_frames(sk, up); | 772 | err = udp_v6_push_pending_frames(sk, up); |
| 773 | else if (unlikely(skb_queue_empty(&sk->sk_write_queue))) | ||
| 774 | up->pending = 0; | ||
| 773 | 775 | ||
| 774 | if (dst) { | 776 | if (dst) { |
| 775 | if (connected) { | 777 | if (connected) { |
| 776 | ip6_dst_store(sk, dst, | 778 | ip6_dst_store(sk, dst, |
| 777 | ipv6_addr_equal(&fl->fl6_dst, &np->daddr) ? | 779 | ipv6_addr_equal(&fl.fl6_dst, &np->daddr) ? |
| 778 | &np->daddr : NULL, | 780 | &np->daddr : NULL, |
| 779 | #ifdef CONFIG_IPV6_SUBTREES | 781 | #ifdef CONFIG_IPV6_SUBTREES |
| 780 | ipv6_addr_equal(&fl->fl6_src, &np->saddr) ? | 782 | ipv6_addr_equal(&fl.fl6_src, &np->saddr) ? |
| 781 | &np->saddr : | 783 | &np->saddr : |
| 782 | #endif | 784 | #endif |
| 783 | NULL); | 785 | NULL); |
diff --git a/net/ipv6/xfrm6_mode_beet.c b/net/ipv6/xfrm6_mode_beet.c new file mode 100644 index 000000000000..edcfffa9e87b --- /dev/null +++ b/net/ipv6/xfrm6_mode_beet.c | |||
| @@ -0,0 +1,107 @@ | |||
| 1 | /* | ||
| 2 | * xfrm6_mode_beet.c - BEET mode encapsulation for IPv6. | ||
| 3 | * | ||
| 4 | * Copyright (c) 2006 Diego Beltrami <diego.beltrami@gmail.com> | ||
| 5 | * Miika Komu <miika@iki.fi> | ||
| 6 | * Herbert Xu <herbert@gondor.apana.org.au> | ||
| 7 | * Abhinav Pathak <abhinav.pathak@hiit.fi> | ||
| 8 | * Jeff Ahrenholz <ahrenholz@gmail.com> | ||
| 9 | */ | ||
| 10 | |||
| 11 | #include <linux/init.h> | ||
| 12 | #include <linux/kernel.h> | ||
| 13 | #include <linux/module.h> | ||
| 14 | #include <linux/skbuff.h> | ||
| 15 | #include <linux/stringify.h> | ||
| 16 | #include <net/dsfield.h> | ||
| 17 | #include <net/dst.h> | ||
| 18 | #include <net/inet_ecn.h> | ||
| 19 | #include <net/ipv6.h> | ||
| 20 | #include <net/xfrm.h> | ||
| 21 | |||
| 22 | /* Add encapsulation header. | ||
| 23 | * | ||
| 24 | * The top IP header will be constructed per draft-nikander-esp-beet-mode-06.txt. | ||
| 25 | * The following fields in it shall be filled in by x->type->output: | ||
| 26 | * payload_len | ||
| 27 | * | ||
| 28 | * On exit, skb->h will be set to the start of the encapsulation header to be | ||
| 29 | * filled in by x->type->output and skb->nh will be set to the nextheader field | ||
| 30 | * of the extension header directly preceding the encapsulation header, or in | ||
| 31 | * its absence, that of the top IP header. The value of skb->data will always | ||
| 32 | * point to the top IP header. | ||
| 33 | */ | ||
| 34 | static int xfrm6_beet_output(struct xfrm_state *x, struct sk_buff *skb) | ||
| 35 | { | ||
| 36 | struct ipv6hdr *iph, *top_iph; | ||
| 37 | u8 *prevhdr; | ||
| 38 | int hdr_len; | ||
| 39 | |||
| 40 | skb_push(skb, x->props.header_len); | ||
| 41 | iph = skb->nh.ipv6h; | ||
| 42 | |||
| 43 | hdr_len = ip6_find_1stfragopt(skb, &prevhdr); | ||
| 44 | skb->nh.raw = prevhdr - x->props.header_len; | ||
| 45 | skb->h.raw = skb->data + hdr_len; | ||
| 46 | memmove(skb->data, iph, hdr_len); | ||
| 47 | |||
| 48 | skb->nh.raw = skb->data; | ||
| 49 | top_iph = skb->nh.ipv6h; | ||
| 50 | skb->nh.raw = &top_iph->nexthdr; | ||
| 51 | skb->h.ipv6h = top_iph + 1; | ||
| 52 | |||
| 53 | ipv6_addr_copy(&top_iph->saddr, (struct in6_addr *)&x->props.saddr); | ||
| 54 | ipv6_addr_copy(&top_iph->daddr, (struct in6_addr *)&x->id.daddr); | ||
| 55 | |||
| 56 | return 0; | ||
| 57 | } | ||
| 58 | |||
| 59 | static int xfrm6_beet_input(struct xfrm_state *x, struct sk_buff *skb) | ||
| 60 | { | ||
| 61 | struct ipv6hdr *ip6h; | ||
| 62 | int size = sizeof(struct ipv6hdr); | ||
| 63 | int err = -EINVAL; | ||
| 64 | |||
| 65 | if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) | ||
| 66 | goto out; | ||
| 67 | |||
| 68 | skb_push(skb, size); | ||
| 69 | memmove(skb->data, skb->nh.raw, size); | ||
| 70 | skb->nh.raw = skb->data; | ||
| 71 | |||
| 72 | skb->mac.raw = memmove(skb->data - skb->mac_len, | ||
| 73 | skb->mac.raw, skb->mac_len); | ||
| 74 | |||
| 75 | ip6h = skb->nh.ipv6h; | ||
| 76 | ip6h->payload_len = htons(skb->len - size); | ||
| 77 | ipv6_addr_copy(&ip6h->daddr, (struct in6_addr *) &x->sel.daddr.a6); | ||
| 78 | ipv6_addr_copy(&ip6h->saddr, (struct in6_addr *) &x->sel.saddr.a6); | ||
| 79 | err = 0; | ||
| 80 | out: | ||
| 81 | return err; | ||
| 82 | } | ||
| 83 | |||
| 84 | static struct xfrm_mode xfrm6_beet_mode = { | ||
| 85 | .input = xfrm6_beet_input, | ||
| 86 | .output = xfrm6_beet_output, | ||
| 87 | .owner = THIS_MODULE, | ||
| 88 | .encap = XFRM_MODE_BEET, | ||
| 89 | }; | ||
| 90 | |||
| 91 | static int __init xfrm6_beet_init(void) | ||
| 92 | { | ||
| 93 | return xfrm_register_mode(&xfrm6_beet_mode, AF_INET6); | ||
| 94 | } | ||
| 95 | |||
| 96 | static void __exit xfrm6_beet_exit(void) | ||
| 97 | { | ||
| 98 | int err; | ||
| 99 | |||
| 100 | err = xfrm_unregister_mode(&xfrm6_beet_mode, AF_INET6); | ||
| 101 | BUG_ON(err); | ||
| 102 | } | ||
| 103 | |||
| 104 | module_init(xfrm6_beet_init); | ||
| 105 | module_exit(xfrm6_beet_exit); | ||
| 106 | MODULE_LICENSE("GPL"); | ||
| 107 | MODULE_ALIAS_XFRM_MODE(AF_INET6, XFRM_MODE_BEET); | ||
