if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h))))
goto out;
- ipv6h = skb->nh.ipv6h;
+ ipv6h = ipv6_hdr(skb);
__skb_pull(skb, sizeof(*ipv6h));
err = -EPROTONOSUPPORT;
rcu_read_lock();
ops = ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr);
if (likely(ops && ops->gso_send_check)) {
- skb->h.raw = skb->data;
+ skb_reset_transport_header(skb);
err = ops->gso_send_check(skb);
}
rcu_read_unlock();
struct ipv6hdr *ipv6h;
struct inet6_protocol *ops;
- if (!(features & NETIF_F_HW_CSUM))
+ if (!(features & NETIF_F_V6_CSUM))
features &= ~NETIF_F_SG;
if (unlikely(skb_shinfo(skb)->gso_type &
if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h))))
goto out;
- ipv6h = skb->nh.ipv6h;
+ ipv6h = ipv6_hdr(skb);
__skb_pull(skb, sizeof(*ipv6h));
segs = ERR_PTR(-EPROTONOSUPPORT);
rcu_read_lock();
ops = ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr);
if (likely(ops && ops->gso_segment)) {
- skb->h.raw = skb->data;
+ skb_reset_transport_header(skb);
segs = ops->gso_segment(skb, features);
}
rcu_read_unlock();
goto out;
for (skb = segs; skb; skb = skb->next) {
- ipv6h = skb->nh.ipv6h;
+ ipv6h = ipv6_hdr(skb);
ipv6h->payload_len = htons(skb->len - skb->mac_len -
sizeof(*ipv6h));
}
}
if (ipv6_only_sock(sk) ||
- !(ipv6_addr_type(&np->daddr) & IPV6_ADDR_MAPPED)) {
+ !ipv6_addr_v4mapped(&np->daddr)) {
retv = -EADDRNOTAVAIL;
break;
}
struct inet_connection_sock *icsk = inet_csk(sk);
local_bh_disable();
- sock_prot_dec_use(sk->sk_prot);
- sock_prot_inc_use(&tcp_prot);
+ sock_prot_inuse_add(sk->sk_prot, -1);
+ sock_prot_inuse_add(&tcp_prot, 1);
local_bh_enable();
sk->sk_prot = &tcp_prot;
icsk->icsk_af_ops = &ipv4_specific;
if (sk->sk_protocol == IPPROTO_UDPLITE)
prot = &udplite_prot;
local_bh_disable();
- sock_prot_dec_use(sk->sk_prot);
- sock_prot_inc_use(prot);
+ sock_prot_inuse_add(sk->sk_prot, -1);
+ sock_prot_inuse_add(prot, 1);
local_bh_enable();
sk->sk_prot = prot;
sk->sk_socket->ops = &inet_dgram_ops;
break;
case IPV6_RECVRTHDR:
- if (val < 0 || val > 2)
- goto e_inval;
- np->rxopt.bits.srcrt = val;
+ np->rxopt.bits.srcrt = valbool;
retv = 0;
break;
case IPV6_2292RTHDR:
- if (val < 0 || val > 2)
- goto e_inval;
- np->rxopt.bits.osrcrt = val;
+ np->rxopt.bits.osrcrt = valbool;
retv = 0;
break;
}
/* routing header option needs extra check */
- if (optname == IPV6_RTHDR && opt->srcrt) {
+ if (optname == IPV6_RTHDR && opt && opt->srcrt) {
struct ipv6_rt_hdr *rthdr = opt->srcrt;
switch (rthdr->type) {
- case IPV6_SRCRT_TYPE_0:
-#ifdef CONFIG_IPV6_MIP6
+#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
case IPV6_SRCRT_TYPE_2:
-#endif
break;
+#endif
default:
goto sticky_done;
}
case IPV6_MULTICAST_IF:
if (sk->sk_type == SOCK_STREAM)
goto e_inval;
- if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != val)
- goto e_inval;
- if (__dev_get_by_index(val) == NULL) {
- retv = -ENODEV;
- break;
+ if (val) {
+ if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != val)
+ goto e_inval;
+
+ if (__dev_get_by_index(&init_net, val) == NULL) {
+ retv = -ENODEV;
+ break;
+ }
}
np->mcast_oif = val;
retv = 0;
{
struct ipv6_mreq mreq;
+ retv = -EPROTO;
+ if (inet_sk(sk)->is_icsk)
+ break;
+
retv = -EFAULT;
if (copy_from_user(&mreq, optval, sizeof(struct ipv6_mreq)))
break;
break;
}
gsf = kmalloc(optlen,GFP_KERNEL);
- if (gsf == 0) {
+ if (!gsf) {
retv = -ENOBUFS;
break;
}
retv = ip6_ra_control(sk, val, NULL);
break;
case IPV6_MTU_DISCOVER:
- if (val<0 || val>2)
+ if (val<0 || val>3)
goto e_inval;
np->pmtudisc = val;
retv = 0;
return err;
}
+EXPORT_SYMBOL(ipv6_setsockopt);
#ifdef CONFIG_COMPAT
int compat_ipv6_setsockopt(struct sock *sk, int level, int optname,
#endif
static int ipv6_getsockopt_sticky(struct sock *sk, struct ipv6_txoptions *opt,
- char __user *optval, int len)
+ int optname, char __user *optval, int len)
{
struct ipv6_opt_hdr *hdr;
- if (!opt || !opt->hopopt)
+ if (!opt)
+ return 0;
+
+ switch(optname) {
+ case IPV6_HOPOPTS:
+ hdr = opt->hopopt;
+ break;
+ case IPV6_RTHDRDSTOPTS:
+ hdr = opt->dst0opt;
+ break;
+ case IPV6_RTHDR:
+ hdr = (struct ipv6_opt_hdr *)opt->srcrt;
+ break;
+ case IPV6_DSTOPTS:
+ hdr = opt->dst1opt;
+ break;
+ default:
+ return -EINVAL; /* should not happen */
+ }
+
+ if (!hdr)
return 0;
- hdr = opt->hopopt;
- len = min_t(int, len, ipv6_optlen(hdr));
- if (copy_to_user(optval, hdr, ipv6_optlen(hdr)))
+ len = min_t(unsigned int, len, ipv6_optlen(hdr));
+ if (copy_to_user(optval, hdr, len))
return -EFAULT;
- return len;
+ return ipv6_optlen(hdr);
}
static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
lock_sock(sk);
len = ipv6_getsockopt_sticky(sk, np->opt,
- optval, len);
+ optname, optval, len);
release_sock(sk);
return put_user(len, optlen);
}
break;
default:
- return -EINVAL;
+ return -ENOPROTOOPT;
}
len = min_t(unsigned int, sizeof(int), len);
if(put_user(len, optlen))
err = do_ipv6_getsockopt(sk, level, optname, optval, optlen);
#ifdef CONFIG_NETFILTER
- /* we need to exclude all possible EINVALs except default case */
- if (err == -EINVAL && optname != IPV6_ADDRFORM &&
- optname != MCAST_MSFILTER) {
+ /* we need to exclude all possible ENOPROTOOPTs except default case */
+ if (err == -ENOPROTOOPT && optname != IPV6_2292PKTOPTIONS) {
int len;
if (get_user(len, optlen))
return err;
}
+EXPORT_SYMBOL(ipv6_getsockopt);
+
#ifdef CONFIG_COMPAT
int compat_ipv6_getsockopt(struct sock *sk, int level, int optname,
char __user *optval, int __user *optlen)
err = do_ipv6_getsockopt(sk, level, optname, optval, optlen);
#ifdef CONFIG_NETFILTER
- /* we need to exclude all possible EINVALs except default case */
- if (err == -EINVAL && optname != IPV6_ADDRFORM &&
- optname != MCAST_MSFILTER) {
+ /* we need to exclude all possible ENOPROTOOPTs except default case */
+ if (err == -ENOPROTOOPT && optname != IPV6_2292PKTOPTIONS) {
int len;
if (get_user(len, optlen))
EXPORT_SYMBOL(compat_ipv6_getsockopt);
#endif
-void __init ipv6_packet_init(void)
+int __init ipv6_packet_init(void)
{
dev_add_pack(&ipv6_packet_type);
+ return 0;
}
void ipv6_packet_cleanup(void)