diff options
Diffstat (limited to 'net/ipv6/raw.c')
| -rw-r--r-- | net/ipv6/raw.c | 52 |
1 files changed, 49 insertions, 3 deletions
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index fa1ce0ae123e..d09329ca3267 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c | |||
| @@ -50,6 +50,9 @@ | |||
| 50 | #include <net/udp.h> | 50 | #include <net/udp.h> |
| 51 | #include <net/inet_common.h> | 51 | #include <net/inet_common.h> |
| 52 | #include <net/tcp_states.h> | 52 | #include <net/tcp_states.h> |
| 53 | #ifdef CONFIG_IPV6_MIP6 | ||
| 54 | #include <net/mip6.h> | ||
| 55 | #endif | ||
| 53 | 56 | ||
| 54 | #include <net/rawv6.h> | 57 | #include <net/rawv6.h> |
| 55 | #include <net/xfrm.h> | 58 | #include <net/xfrm.h> |
| @@ -169,8 +172,32 @@ int ipv6_raw_deliver(struct sk_buff *skb, int nexthdr) | |||
| 169 | sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr, IP6CB(skb)->iif); | 172 | sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr, IP6CB(skb)->iif); |
| 170 | 173 | ||
| 171 | while (sk) { | 174 | while (sk) { |
| 175 | int filtered; | ||
| 176 | |||
| 172 | delivered = 1; | 177 | delivered = 1; |
| 173 | if (nexthdr != IPPROTO_ICMPV6 || !icmpv6_filter(sk, skb)) { | 178 | switch (nexthdr) { |
| 179 | case IPPROTO_ICMPV6: | ||
| 180 | filtered = icmpv6_filter(sk, skb); | ||
| 181 | break; | ||
| 182 | #ifdef CONFIG_IPV6_MIP6 | ||
| 183 | case IPPROTO_MH: | ||
| 184 | /* XXX: To validate MH only once for each packet, | ||
| 185 | * this is placed here. It should be after checking | ||
| 186 | * xfrm policy, however it doesn't. The checking xfrm | ||
| 187 | * policy is placed in rawv6_rcv() because it is | ||
| 188 | * required for each socket. | ||
| 189 | */ | ||
| 190 | filtered = mip6_mh_filter(sk, skb); | ||
| 191 | break; | ||
| 192 | #endif | ||
| 193 | default: | ||
| 194 | filtered = 0; | ||
| 195 | break; | ||
| 196 | } | ||
| 197 | |||
| 198 | if (filtered < 0) | ||
| 199 | break; | ||
| 200 | if (filtered == 0) { | ||
| 174 | struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC); | 201 | struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC); |
| 175 | 202 | ||
| 176 | /* Not releasing hash table! */ | 203 | /* Not releasing hash table! */ |
| @@ -334,7 +361,7 @@ int rawv6_rcv(struct sock *sk, struct sk_buff *skb) | |||
| 334 | if (!rp->checksum) | 361 | if (!rp->checksum) |
| 335 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 362 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
| 336 | 363 | ||
| 337 | if (skb->ip_summed == CHECKSUM_HW) { | 364 | if (skb->ip_summed == CHECKSUM_COMPLETE) { |
| 338 | skb_postpull_rcsum(skb, skb->nh.raw, | 365 | skb_postpull_rcsum(skb, skb->nh.raw, |
| 339 | skb->h.raw - skb->nh.raw); | 366 | skb->h.raw - skb->nh.raw); |
| 340 | if (!csum_ipv6_magic(&skb->nh.ipv6h->saddr, | 367 | if (!csum_ipv6_magic(&skb->nh.ipv6h->saddr, |
| @@ -411,6 +438,7 @@ static int rawv6_recvmsg(struct kiocb *iocb, struct sock *sk, | |||
| 411 | /* Copy the address. */ | 438 | /* Copy the address. */ |
| 412 | if (sin6) { | 439 | if (sin6) { |
| 413 | sin6->sin6_family = AF_INET6; | 440 | sin6->sin6_family = AF_INET6; |
| 441 | sin6->sin6_port = 0; | ||
| 414 | ipv6_addr_copy(&sin6->sin6_addr, &skb->nh.ipv6h->saddr); | 442 | ipv6_addr_copy(&sin6->sin6_addr, &skb->nh.ipv6h->saddr); |
| 415 | sin6->sin6_flowinfo = 0; | 443 | sin6->sin6_flowinfo = 0; |
| 416 | sin6->sin6_scope_id = 0; | 444 | sin6->sin6_scope_id = 0; |
| @@ -581,6 +609,9 @@ static void rawv6_probe_proto_opt(struct flowi *fl, struct msghdr *msg) | |||
| 581 | struct iovec *iov; | 609 | struct iovec *iov; |
| 582 | u8 __user *type = NULL; | 610 | u8 __user *type = NULL; |
| 583 | u8 __user *code = NULL; | 611 | u8 __user *code = NULL; |
| 612 | #ifdef CONFIG_IPV6_MIP6 | ||
| 613 | u8 len = 0; | ||
| 614 | #endif | ||
| 584 | int probed = 0; | 615 | int probed = 0; |
| 585 | int i; | 616 | int i; |
| 586 | 617 | ||
| @@ -612,6 +643,20 @@ static void rawv6_probe_proto_opt(struct flowi *fl, struct msghdr *msg) | |||
| 612 | probed = 1; | 643 | probed = 1; |
| 613 | } | 644 | } |
| 614 | break; | 645 | break; |
| 646 | #ifdef CONFIG_IPV6_MIP6 | ||
| 647 | case IPPROTO_MH: | ||
| 648 | if (iov->iov_base && iov->iov_len < 1) | ||
| 649 | break; | ||
| 650 | /* check if type field is readable or not. */ | ||
| 651 | if (iov->iov_len > 2 - len) { | ||
| 652 | u8 __user *p = iov->iov_base; | ||
| 653 | get_user(fl->fl_mh_type, &p[2 - len]); | ||
| 654 | probed = 1; | ||
| 655 | } else | ||
| 656 | len += iov->iov_len; | ||
| 657 | |||
| 658 | break; | ||
| 659 | #endif | ||
| 615 | default: | 660 | default: |
| 616 | probed = 1; | 661 | probed = 1; |
| 617 | break; | 662 | break; |
| @@ -758,6 +803,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
| 758 | 803 | ||
| 759 | if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst)) | 804 | if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst)) |
| 760 | fl.oif = np->mcast_oif; | 805 | fl.oif = np->mcast_oif; |
| 806 | security_sk_classify_flow(sk, &fl); | ||
| 761 | 807 | ||
| 762 | err = ip6_dst_lookup(sk, &dst, &fl); | 808 | err = ip6_dst_lookup(sk, &dst, &fl); |
| 763 | if (err) | 809 | if (err) |
| @@ -780,7 +826,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
| 780 | } | 826 | } |
| 781 | 827 | ||
| 782 | if (tclass < 0) { | 828 | if (tclass < 0) { |
| 783 | tclass = np->cork.tclass; | 829 | tclass = np->tclass; |
| 784 | if (tclass < 0) | 830 | if (tclass < 0) |
| 785 | tclass = 0; | 831 | tclass = 0; |
| 786 | } | 832 | } |
