X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=net%2Fipv6%2Fraw.c;h=2b3be68b70a7ee6d8f2ae912de4dbd1600f5ab89;hb=628592ccdbbb5bb751217cf02e2e7abb500d7ffe;hp=c2e629d6aea40e5519c3b865d62e1a092e6c9b60;hpb=651857a1ecaf97a8ad9d324dd2a61675c53e541e;p=deliverable%2Flinux.git diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index c2e629d6aea4..2b3be68b70a7 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -1,9 +1,9 @@ /* * RAW sockets for IPv6 - * Linux INET6 implementation + * Linux INET6 implementation * * Authors: - * Pedro Roque + * Pedro Roque * * Adapted from linux/net/ipv4/raw.c * @@ -11,7 +11,7 @@ * * Fixes: * Hideaki YOSHIFUJI : sin6_scope_id support - * YOSHIFUJI,H.@USAGI : raw checksum (RFC2292(bis) compliance) + * YOSHIFUJI,H.@USAGI : raw checksum (RFC2292(bis) compliance) * Kazunori MIYAZAWA @USAGI: change process style to use ip6_append_data * * This program is free software; you can redistribute it and/or @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include @@ -71,12 +70,12 @@ static void raw_v6_hash(struct sock *sk) write_lock_bh(&raw_v6_lock); sk_add_node(sk, list); sock_prot_inc_use(sk->sk_prot); - write_unlock_bh(&raw_v6_lock); + write_unlock_bh(&raw_v6_lock); } static void raw_v6_unhash(struct sock *sk) { - write_lock_bh(&raw_v6_lock); + write_lock_bh(&raw_v6_lock); if (sk_del_node_init(sk)) sock_prot_dec_use(sk->sk_prot); write_unlock_bh(&raw_v6_lock); @@ -153,7 +152,7 @@ int ipv6_raw_deliver(struct sk_buff *skb, int nexthdr) int delivered = 0; __u8 hash; - saddr = &skb->nh.ipv6h->saddr; + saddr = &ipv6_hdr(skb)->saddr; daddr = saddr + 1; hash = nexthdr & (MAX_INET_PROTOS - 1); @@ -250,7 +249,7 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) */ sk->sk_bound_dev_if = addr->sin6_scope_id; } - + /* Binding to link-local address requires an interface */ if (!sk->sk_bound_dev_if) goto out; @@ -261,7 +260,7 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) goto out; } } - + /* ipv4 addr of the socket is invalid. Only the * unspecified and mapped address have a v4 equivalent. */ @@ -324,7 +323,7 @@ void rawv6_err(struct sock *sk, struct sk_buff *skb, static inline int rawv6_rcv_skb(struct sock * sk, struct sk_buff * skb) { - if ((raw6_sk(sk)->checksum || sk->sk_filter) && + if ((raw6_sk(sk)->checksum || sk->sk_filter) && skb_checksum_complete(skb)) { /* FIXME: increment a raw6 drops counter here */ kfree_skb(skb); @@ -342,10 +341,10 @@ static inline int rawv6_rcv_skb(struct sock * sk, struct sk_buff * skb) } /* - * This is next to useless... + * This is next to useless... * if we demultiplex in network layer we don't need the extra call - * just to queue the skb... - * maybe we could have the network decide upon a hint if it + * just to queue the skb... + * maybe we could have the network decide upon a hint if it * should call raw_rcv for demultiplexing */ int rawv6_rcv(struct sock *sk, struct sk_buff *skb) @@ -353,26 +352,27 @@ int rawv6_rcv(struct sock *sk, struct sk_buff *skb) struct inet_sock *inet = inet_sk(sk); struct raw6_sock *rp = raw6_sk(sk); - if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) { - kfree_skb(skb); - return NET_RX_DROP; - } + if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) { + kfree_skb(skb); + return NET_RX_DROP; + } if (!rp->checksum) skb->ip_summed = CHECKSUM_UNNECESSARY; if (skb->ip_summed == CHECKSUM_COMPLETE) { - skb_postpull_rcsum(skb, skb->nh.raw, - skb->h.raw - skb->nh.raw); - if (!csum_ipv6_magic(&skb->nh.ipv6h->saddr, - &skb->nh.ipv6h->daddr, + skb_postpull_rcsum(skb, skb_network_header(skb), + skb_network_header_len(skb)); + if (!csum_ipv6_magic(&ipv6_hdr(skb)->saddr, + &ipv6_hdr(skb)->daddr, skb->len, inet->num, skb->csum)) skb->ip_summed = CHECKSUM_UNNECESSARY; } if (skb->ip_summed != CHECKSUM_UNNECESSARY) - skb->csum = ~csum_unfold(csum_ipv6_magic(&skb->nh.ipv6h->saddr, - &skb->nh.ipv6h->daddr, - skb->len, inet->num, 0)); + skb->csum = ~csum_unfold(csum_ipv6_magic(&ipv6_hdr(skb)->saddr, + &ipv6_hdr(skb)->daddr, + skb->len, + inet->num, 0)); if (inet->hdrincl) { if (skb_checksum_complete(skb)) { @@ -404,8 +404,8 @@ static int rawv6_recvmsg(struct kiocb *iocb, struct sock *sk, if (flags & MSG_OOB) return -EOPNOTSUPP; - - if (addr_len) + + if (addr_len) *addr_len=sizeof(*sin6); if (flags & MSG_ERRQUEUE) @@ -416,10 +416,10 @@ static int rawv6_recvmsg(struct kiocb *iocb, struct sock *sk, goto out; copied = skb->len; - if (copied > len) { - copied = len; - msg->msg_flags |= MSG_TRUNC; - } + if (copied > len) { + copied = len; + msg->msg_flags |= MSG_TRUNC; + } if (skb->ip_summed==CHECKSUM_UNNECESSARY) { err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); @@ -439,7 +439,7 @@ static int rawv6_recvmsg(struct kiocb *iocb, struct sock *sk, if (sin6) { sin6->sin6_family = AF_INET6; sin6->sin6_port = 0; - ipv6_addr_copy(&sin6->sin6_addr, &skb->nh.ipv6h->saddr); + ipv6_addr_copy(&sin6->sin6_addr, &ipv6_hdr(skb)->saddr); sin6->sin6_flowinfo = 0; sin6->sin6_scope_id = 0; if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) @@ -489,7 +489,8 @@ static int rawv6_push_pending_frames(struct sock *sk, struct flowi *fl, goto out; offset = rp->offset; - total_len = inet_sk(sk)->cork.length - (skb->nh.raw - skb->data); + total_len = inet_sk(sk)->cork.length - (skb_network_header(skb) - + skb->data); if (offset >= total_len - 1) { err = -EINVAL; ip6_flush_pending_frames(sk); @@ -512,7 +513,7 @@ static int rawv6_push_pending_frames(struct sock *sk, struct flowi *fl, if (csum_skb) continue; - len = skb->len - (skb->h.raw - skb->data); + len = skb->len - skb_transport_offset(skb); if (offset >= len) { offset -= len; continue; @@ -524,7 +525,7 @@ static int rawv6_push_pending_frames(struct sock *sk, struct flowi *fl, skb = csum_skb; } - offset += skb->h.raw - skb->data; + offset += skb_transport_offset(skb); if (skb_copy_bits(skb, offset, &csum, 2)) BUG(); @@ -549,7 +550,7 @@ out: } static int rawv6_send_hdrinc(struct sock *sk, void *from, int length, - struct flowi *fl, struct rt6_info *rt, + struct flowi *fl, struct rt6_info *rt, unsigned int flags) { struct ipv6_pinfo *np = inet6_sk(sk); @@ -570,17 +571,19 @@ static int rawv6_send_hdrinc(struct sock *sk, void *from, int length, skb = sock_alloc_send_skb(sk, length+hh_len+15, flags&MSG_DONTWAIT, &err); if (skb == NULL) - goto error; + goto error; skb_reserve(skb, hh_len); skb->priority = sk->sk_priority; skb->dst = dst_clone(&rt->u.dst); - skb->nh.ipv6h = iph = (struct ipv6hdr *)skb_put(skb, length); + skb_put(skb, length); + skb_reset_network_header(skb); + iph = ipv6_hdr(skb); skb->ip_summed = CHECKSUM_NONE; - skb->h.raw = skb->nh.raw; + skb->transport_header = skb->network_header; err = memcpy_fromiovecend((void *)iph, from, 0, length); if (err) goto error_fault; @@ -600,7 +603,7 @@ error_fault: kfree_skb(skb); error: IP6_INC_STATS(rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS); - return err; + return err; } static int rawv6_probe_proto_opt(struct flowi *fl, struct msghdr *msg) @@ -688,25 +691,25 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, int err; /* Rough check on arithmetic overflow, - better check is made in ip6_build_xmit + better check is made in ip6_append_data(). */ - if (len < 0) + if (len > INT_MAX) return -EMSGSIZE; /* Mirror BSD error message compatibility */ - if (msg->msg_flags & MSG_OOB) + if (msg->msg_flags & MSG_OOB) return -EOPNOTSUPP; /* - * Get and verify the address. + * Get and verify the address. */ memset(&fl, 0, sizeof(fl)); if (sin6) { - if (addr_len < SIN6_LEN_RFC2133) + if (addr_len < SIN6_LEN_RFC2133) return -EINVAL; - if (sin6->sin6_family && sin6->sin6_family != AF_INET6) + if (sin6->sin6_family && sin6->sin6_family != AF_INET6) return(-EAFNOSUPPORT); /* port is the proto value [0..255] carried in nexthdr */ @@ -744,17 +747,17 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, ipv6_addr_type(daddr)&IPV6_ADDR_LINKLOCAL) fl.oif = sin6->sin6_scope_id; } else { - if (sk->sk_state != TCP_ESTABLISHED) + if (sk->sk_state != TCP_ESTABLISHED) return -EDESTADDRREQ; - + proto = inet->num; daddr = &np->daddr; fl.fl6_flowlabel = np->flow_label; } if (ipv6_addr_any(daddr)) { - /* - * unspecified destination address + /* + * unspecified destination address * treated as error... is this correct ? */ fl6_sock_release(flowlabel); @@ -792,7 +795,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, err = rawv6_probe_proto_opt(&fl, msg); if (err) goto out; - + ipv6_addr_copy(&fl.fl6_dst, daddr); if (ipv6_addr_any(&fl.fl6_src) && !ipv6_addr_any(&np->saddr)) ipv6_addr_copy(&fl.fl6_src, &np->saddr); @@ -815,7 +818,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, if (final_p) ipv6_addr_copy(&fl.fl6_dst, final_p); - if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) + if ((err = xfrm_lookup(&dst, &fl, sk, 1)) < 0) goto out; if (hlimit < 0) { @@ -854,8 +857,9 @@ back_from_confirm: } done: dst_release(dst); - release_sock(sk); -out: + if (!inet->hdrincl) + release_sock(sk); +out: fl6_sock_release(flowlabel); return err<0?err:len; do_confirm: @@ -866,7 +870,7 @@ do_confirm: goto done; } -static int rawv6_seticmpfilter(struct sock *sk, int level, int optname, +static int rawv6_seticmpfilter(struct sock *sk, int level, int optname, char __user *optval, int optlen) { switch (optname) { @@ -883,7 +887,7 @@ static int rawv6_seticmpfilter(struct sock *sk, int level, int optname, return 0; } -static int rawv6_geticmpfilter(struct sock *sk, int level, int optname, +static int rawv6_geticmpfilter(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen) { int len; @@ -915,7 +919,7 @@ static int do_rawv6_setsockopt(struct sock *sk, int level, int optname, struct raw6_sock *rp = raw6_sk(sk); int val; - if (get_user(val, (int __user *)optval)) + if (get_user(val, (int __user *)optval)) return -EFAULT; switch (optname) { @@ -1073,7 +1077,7 @@ static int rawv6_ioctl(struct sock *sk, int cmd, unsigned long arg) spin_lock_bh(&sk->sk_receive_queue.lock); skb = skb_peek(&sk->sk_receive_queue); if (skb != NULL) - amount = skb->tail - skb->h.raw; + amount = skb->tail - skb->transport_header; spin_unlock_bh(&sk->sk_receive_queue.lock); return put_user(amount, (int __user *)arg); } @@ -1093,10 +1097,19 @@ static void rawv6_close(struct sock *sk, long timeout) static int rawv6_init_sk(struct sock *sk) { - if (inet_sk(sk)->num == IPPROTO_ICMPV6) { - struct raw6_sock *rp = raw6_sk(sk); + struct raw6_sock *rp = raw6_sk(sk); + + switch (inet_sk(sk)->num) { + case IPPROTO_ICMPV6: rp->checksum = 1; rp->offset = 2; + break; + case IPPROTO_MH: + rp->checksum = 1; + rp->offset = 4; + break; + default: + break; } return(0); } @@ -1214,7 +1227,7 @@ static void raw6_sock_seq_show(struct seq_file *seq, struct sock *sp, int i) src->s6_addr32[2], src->s6_addr32[3], srcp, dest->s6_addr32[0], dest->s6_addr32[1], dest->s6_addr32[2], dest->s6_addr32[3], destp, - sp->sk_state, + sp->sk_state, atomic_read(&sp->sk_wmem_alloc), atomic_read(&sp->sk_rmem_alloc), 0, 0L, 0, @@ -1263,7 +1276,7 @@ out_kfree: goto out; } -static struct file_operations raw6_seq_fops = { +static const struct file_operations raw6_seq_fops = { .owner = THIS_MODULE, .open = raw6_seq_open, .read = seq_read,