summaryrefslogtreecommitdiffstats
path: root/net/ipv4/ip_sockglue.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1999-10-09 00:00:47 +0000
committerRalf Baechle <ralf@linux-mips.org>1999-10-09 00:00:47 +0000
commitd6434e1042f3b0a6dfe1b1f615af369486f9b1fa (patch)
treee2be02f33984c48ec019c654051d27964e42c441 /net/ipv4/ip_sockglue.c
parent609d1e803baf519487233b765eb487f9ec227a18 (diff)
Merge with 2.3.19.
Diffstat (limited to 'net/ipv4/ip_sockglue.c')
-rw-r--r--net/ipv4/ip_sockglue.c352
1 files changed, 201 insertions, 151 deletions
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index 369a6770c..7278a0b4a 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -5,7 +5,7 @@
*
* The IP to API glue.
*
- * Version: $Id: ip_sockglue.c,v 1.42 1999/04/22 10:07:34 davem Exp $
+ * Version: $Id: ip_sockglue.c,v 1.45 1999/09/06 04:58:03 davem Exp $
*
* Authors: see ip.c
*
@@ -32,8 +32,7 @@
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/igmp.h>
-#include <linux/firewall.h>
-#include <linux/ip_fw.h>
+#include <linux/netfilter.h>
#include <linux/route.h>
#include <linux/mroute.h>
#include <net/route.h>
@@ -41,10 +40,6 @@
#include <net/transp_v6.h>
#endif
-#ifdef CONFIG_IP_MASQUERADE
-#include <linux/ip_masq.h>
-#endif
-
#include <linux/errqueue.h>
#include <asm/uaccess.h>
@@ -117,7 +112,7 @@ void ip_cmsg_recv_retopts(struct msghdr *msg, struct sk_buff *skb)
void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb)
{
- unsigned flags = skb->sk->ip_cmsg_flags;
+ unsigned flags = skb->sk->protinfo.af_inet.cmsg_flags;
/* Ordered by supposed usage frequency */
if (flags & 1)
@@ -193,6 +188,7 @@ int ip_cmsg_send(struct msghdr *msg, struct ipcm_cookie *ipc)
sent to multicast group to reach destination designated router.
*/
struct ip_ra_chain *ip_ra_chain;
+rwlock_t ip_ra_lock = RW_LOCK_UNLOCKED;
int ip_ra_control(struct sock *sk, unsigned char on, void (*destructor)(struct sock *))
{
@@ -203,30 +199,36 @@ int ip_ra_control(struct sock *sk, unsigned char on, void (*destructor)(struct s
new_ra = on ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL;
+ write_lock_bh(&ip_ra_lock);
for (rap = &ip_ra_chain; (ra=*rap) != NULL; rap = &ra->next) {
if (ra->sk == sk) {
if (on) {
+ write_unlock_bh(&ip_ra_lock);
if (new_ra)
kfree(new_ra);
return -EADDRINUSE;
}
*rap = ra->next;
- synchronize_bh();
+ write_unlock_bh(&ip_ra_lock);
if (ra->destructor)
ra->destructor(sk);
+ sock_put(sk);
kfree(ra);
return 0;
}
}
- if (new_ra == NULL)
+ if (new_ra == NULL) {
+ write_unlock_bh(&ip_ra_lock);
return -ENOBUFS;
+ }
new_ra->sk = sk;
new_ra->destructor = destructor;
new_ra->next = ra;
- wmb();
*rap = new_ra;
+ sock_hold(sk);
+ write_unlock_bh(&ip_ra_lock);
return 0;
}
@@ -236,7 +238,7 @@ void ip_icmp_error(struct sock *sk, struct sk_buff *skb, int err,
{
struct sock_exterr_skb *serr;
- if (!sk->ip_recverr)
+ if (!sk->protinfo.af_inet.recverr)
return;
skb = skb_clone(skb, GFP_ATOMIC);
@@ -267,7 +269,7 @@ void ip_local_error(struct sock *sk, int err, u32 daddr, u16 port, u32 info)
struct iphdr *iph;
struct sk_buff *skb;
- if (!sk->ip_recverr)
+ if (!sk->protinfo.af_inet.recverr)
return;
skb = alloc_skb(sizeof(struct iphdr), GFP_ATOMIC);
@@ -340,7 +342,7 @@ int ip_recv_error(struct sock *sk, struct msghdr *msg, int len)
if (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP) {
sin->sin_family = AF_INET;
sin->sin_addr.s_addr = skb->nh.iph->saddr;
- if (sk->ip_cmsg_flags)
+ if (sk->protinfo.af_inet.cmsg_flags)
ip_cmsg_recv(msg, skb);
}
@@ -375,9 +377,7 @@ out:
int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int optlen)
{
int val=0,err;
-#if defined(CONFIG_IP_FIREWALL)
- char tmp_fw[MAX(sizeof(struct ip_fwtest),sizeof(struct ip_fwnew))];
-#endif
+
if(optlen>=sizeof(int)) {
if(get_user(val, (int *) optval))
return -EFAULT;
@@ -397,18 +397,20 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int opt
return ip_mroute_setsockopt(sk,optname,optval,optlen);
}
#endif
-
+
+ err = 0;
+ lock_sock(sk);
+
switch(optname)
{
case IP_OPTIONS:
{
struct ip_options * opt = NULL;
if (optlen > 40 || optlen < 0)
- return -EINVAL;
+ goto e_inval;
err = ip_options_get(&opt, optval, optlen, 1);
if (err)
- return err;
- lock_sock(sk);
+ break;
if (sk->type == SOCK_STREAM) {
struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
@@ -423,194 +425,192 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int opt
}
#endif
}
- opt = xchg(&sk->opt, opt);
- release_sock(sk);
+ opt = xchg(&sk->protinfo.af_inet.opt, opt);
if (opt)
kfree_s(opt, sizeof(struct ip_options) + opt->optlen);
- return 0;
+ break;
}
case IP_PKTINFO:
if (val)
- sk->ip_cmsg_flags |= IP_CMSG_PKTINFO;
+ sk->protinfo.af_inet.cmsg_flags |= IP_CMSG_PKTINFO;
else
- sk->ip_cmsg_flags &= ~IP_CMSG_PKTINFO;
- return 0;
+ sk->protinfo.af_inet.cmsg_flags &= ~IP_CMSG_PKTINFO;
+ break;
case IP_RECVTTL:
if (val)
- sk->ip_cmsg_flags |= IP_CMSG_TTL;
+ sk->protinfo.af_inet.cmsg_flags |= IP_CMSG_TTL;
else
- sk->ip_cmsg_flags &= ~IP_CMSG_TTL;
- return 0;
+ sk->protinfo.af_inet.cmsg_flags &= ~IP_CMSG_TTL;
+ break;
case IP_RECVTOS:
if (val)
- sk->ip_cmsg_flags |= IP_CMSG_TOS;
+ sk->protinfo.af_inet.cmsg_flags |= IP_CMSG_TOS;
else
- sk->ip_cmsg_flags &= ~IP_CMSG_TOS;
- return 0;
+ sk->protinfo.af_inet.cmsg_flags &= ~IP_CMSG_TOS;
+ break;
case IP_RECVOPTS:
if (val)
- sk->ip_cmsg_flags |= IP_CMSG_RECVOPTS;
+ sk->protinfo.af_inet.cmsg_flags |= IP_CMSG_RECVOPTS;
else
- sk->ip_cmsg_flags &= ~IP_CMSG_RECVOPTS;
- return 0;
+ sk->protinfo.af_inet.cmsg_flags &= ~IP_CMSG_RECVOPTS;
+ break;
case IP_RETOPTS:
if (val)
- sk->ip_cmsg_flags |= IP_CMSG_RETOPTS;
+ sk->protinfo.af_inet.cmsg_flags |= IP_CMSG_RETOPTS;
else
- sk->ip_cmsg_flags &= ~IP_CMSG_RETOPTS;
- return 0;
+ sk->protinfo.af_inet.cmsg_flags &= ~IP_CMSG_RETOPTS;
+ break;
case IP_TOS: /* This sets both TOS and Precedence */
/* Reject setting of unused bits */
if (val & ~(IPTOS_TOS_MASK|IPTOS_PREC_MASK))
- return -EINVAL;
+ goto e_inval;
if (IPTOS_PREC(val) >= IPTOS_PREC_CRITIC_ECP &&
- !capable(CAP_NET_ADMIN))
- return -EPERM;
- if (sk->ip_tos != val) {
- lock_sock(sk);
- sk->ip_tos=val;
+ !capable(CAP_NET_ADMIN)) {
+ err = -EPERM;
+ break;
+ }
+ if (sk->protinfo.af_inet.tos != val) {
+ sk->protinfo.af_inet.tos=val;
sk->priority = rt_tos2priority(val);
- dst_release(xchg(&sk->dst_cache, NULL));
- release_sock(sk);
+ sk_dst_reset(sk);
}
- return 0;
+ break;
case IP_TTL:
if (optlen<1)
- return -EINVAL;
+ goto e_inval;
if(val==-1)
val = ip_statistics.IpDefaultTTL;
if(val<1||val>255)
- return -EINVAL;
- sk->ip_ttl=val;
- return 0;
+ goto e_inval;
+ sk->protinfo.af_inet.ttl=val;
+ break;
case IP_HDRINCL:
- if(sk->type!=SOCK_RAW)
- return -ENOPROTOOPT;
- sk->ip_hdrincl=val?1:0;
- return 0;
+ if(sk->type!=SOCK_RAW) {
+ err = -ENOPROTOOPT;
+ break;
+ }
+ sk->protinfo.af_inet.hdrincl=val?1:0;
+ break;
case IP_MTU_DISCOVER:
if (val<0 || val>2)
- return -EINVAL;
- sk->ip_pmtudisc = val;
- return 0;
+ goto e_inval;
+ sk->protinfo.af_inet.pmtudisc = val;
+ break;
case IP_RECVERR:
- sk->ip_recverr = !!val;
+ sk->protinfo.af_inet.recverr = !!val;
if (!val)
skb_queue_purge(&sk->error_queue);
- return 0;
- case IP_MULTICAST_TTL:
+ break;
+ case IP_MULTICAST_TTL:
+ if (sk->type == SOCK_STREAM)
+ goto e_inval;
if (optlen<1)
- return -EINVAL;
+ goto e_inval;
if (val==-1)
val = 1;
if (val < 0 || val > 255)
- return -EINVAL;
- sk->ip_mc_ttl=val;
- return 0;
+ goto e_inval;
+ sk->protinfo.af_inet.mc_ttl=val;
+ break;
case IP_MULTICAST_LOOP:
if (optlen<1)
- return -EINVAL;
- sk->ip_mc_loop = val ? 1 : 0;
- return 0;
+ goto e_inval;
+ sk->protinfo.af_inet.mc_loop = val ? 1 : 0;
+ break;
case IP_MULTICAST_IF:
{
struct ip_mreqn mreq;
- struct device *dev = NULL;
-
+ struct net_device *dev = NULL;
+
+ if (sk->type == SOCK_STREAM)
+ goto e_inval;
/*
* Check the arguments are allowable
*/
+ err = -EFAULT;
if (optlen >= sizeof(struct ip_mreqn)) {
if (copy_from_user(&mreq,optval,sizeof(mreq)))
- return -EFAULT;
+ break;
} else {
memset(&mreq, 0, sizeof(mreq));
if (optlen >= sizeof(struct in_addr) &&
copy_from_user(&mreq.imr_address,optval,sizeof(struct in_addr)))
- return -EFAULT;
+ break;
}
if (!mreq.imr_ifindex) {
if (mreq.imr_address.s_addr == INADDR_ANY) {
- sk->ip_mc_index = 0;
- sk->ip_mc_addr = 0;
- return 0;
+ sk->protinfo.af_inet.mc_index = 0;
+ sk->protinfo.af_inet.mc_addr = 0;
+ err = 0;
+ break;
}
dev = ip_dev_find(mreq.imr_address.s_addr);
+ if (dev) {
+ mreq.imr_ifindex = dev->ifindex;
+ dev_put(dev);
+ }
} else
- dev = dev_get_by_index(mreq.imr_ifindex);
+ dev = __dev_get_by_index(mreq.imr_ifindex);
+
+ err = -EADDRNOTAVAIL;
if (!dev)
- return -EADDRNOTAVAIL;
+ break;
- if (sk->bound_dev_if && dev->ifindex != sk->bound_dev_if)
- return -EINVAL;
+ err = -EINVAL;
+ if (sk->bound_dev_if && mreq.imr_ifindex != sk->bound_dev_if)
+ break;
- sk->ip_mc_index = mreq.imr_ifindex;
- sk->ip_mc_addr = mreq.imr_address.s_addr;
- return 0;
+ sk->protinfo.af_inet.mc_index = mreq.imr_ifindex;
+ sk->protinfo.af_inet.mc_addr = mreq.imr_address.s_addr;
+ err = 0;
+ break;
}
case IP_ADD_MEMBERSHIP:
case IP_DROP_MEMBERSHIP:
{
struct ip_mreqn mreq;
-
+
if (optlen < sizeof(struct ip_mreq))
- return -EINVAL;
+ goto e_inval;
+ err = -EFAULT;
if (optlen >= sizeof(struct ip_mreqn)) {
if(copy_from_user(&mreq,optval,sizeof(mreq)))
- return -EFAULT;
+ break;
} else {
memset(&mreq, 0, sizeof(mreq));
if (copy_from_user(&mreq,optval,sizeof(struct ip_mreq)))
- return -EFAULT;
+ break;
}
if (optname == IP_ADD_MEMBERSHIP)
- return ip_mc_join_group(sk,&mreq);
+ err = ip_mc_join_group(sk,&mreq);
else
- return ip_mc_leave_group(sk,&mreq);
+ err = ip_mc_leave_group(sk,&mreq);
+ break;
}
case IP_ROUTER_ALERT:
- return ip_ra_control(sk, val ? 1 : 0, NULL);
-
-#ifdef CONFIG_IP_FIREWALL
- case IP_FW_MASQ_TIMEOUTS:
- case IP_FW_APPEND:
- case IP_FW_REPLACE:
- case IP_FW_DELETE:
- case IP_FW_DELETE_NUM:
- case IP_FW_INSERT:
- case IP_FW_FLUSH:
- case IP_FW_ZERO:
- case IP_FW_CHECK:
- case IP_FW_CREATECHAIN:
- case IP_FW_DELETECHAIN:
- case IP_FW_POLICY:
- if(!capable(CAP_NET_ADMIN))
- return -EACCES;
- if(optlen>sizeof(tmp_fw) || optlen<1)
- return -EINVAL;
- if(copy_from_user(&tmp_fw,optval,optlen))
- return -EFAULT;
- err=ip_fw_ctl(optname, &tmp_fw,optlen);
- return -err; /* -0 is 0 after all */
-#endif /* CONFIG_IP_FIREWALL */
-#ifdef CONFIG_IP_MASQUERADE
- case IP_FW_MASQ_CTL:
- if(!capable(CAP_NET_ADMIN))
- return -EPERM;
- if(optlen<1)
- return -EINVAL;
- err=ip_masq_uctl(optname, optval ,optlen);
- return err;
-
-#endif
+ err = ip_ra_control(sk, val ? 1 : 0, NULL);
+ break;
+
default:
- return(-ENOPROTOOPT);
+#ifdef CONFIG_NETFILTER
+ err = nf_setsockopt(sk, PF_INET, optname, optval,
+ optlen);
+#else
+ err = -ENOPROTOOPT;
+#endif
+ break;
}
+ release_sock(sk);
+ return err;
+
+e_inval:
+ release_sock(sk);
+ return -EINVAL;
}
/*
@@ -636,17 +636,20 @@ int ip_getsockopt(struct sock *sk, int level, int optname, char *optval, int *op
if(get_user(len,optlen))
return -EFAULT;
- switch(optname)
- {
+ lock_sock(sk);
+
+ switch(optname) {
case IP_OPTIONS:
{
unsigned char optbuf[sizeof(struct ip_options)+40];
struct ip_options * opt = (struct ip_options*)optbuf;
- lock_sock(sk);
opt->optlen = 0;
- if (sk->opt)
- memcpy(optbuf, sk->opt, sizeof(struct ip_options)+sk->opt->optlen);
+ if (sk->protinfo.af_inet.opt)
+ memcpy(optbuf, sk->protinfo.af_inet.opt,
+ sizeof(struct ip_options)+
+ sk->protinfo.af_inet.opt->optlen);
release_sock(sk);
+
if (opt->optlen == 0)
return put_user(0, optlen);
@@ -660,66 +663,113 @@ int ip_getsockopt(struct sock *sk, int level, int optname, char *optval, int *op
return 0;
}
case IP_PKTINFO:
- val = (sk->ip_cmsg_flags & IP_CMSG_PKTINFO) != 0;
+ val = (sk->protinfo.af_inet.cmsg_flags & IP_CMSG_PKTINFO) != 0;
break;
case IP_RECVTTL:
- val = (sk->ip_cmsg_flags & IP_CMSG_TTL) != 0;
+ val = (sk->protinfo.af_inet.cmsg_flags & IP_CMSG_TTL) != 0;
break;
case IP_RECVTOS:
- val = (sk->ip_cmsg_flags & IP_CMSG_TOS) != 0;
+ val = (sk->protinfo.af_inet.cmsg_flags & IP_CMSG_TOS) != 0;
break;
case IP_RECVOPTS:
- val = (sk->ip_cmsg_flags & IP_CMSG_RECVOPTS) != 0;
+ val = (sk->protinfo.af_inet.cmsg_flags & IP_CMSG_RECVOPTS) != 0;
break;
case IP_RETOPTS:
- val = (sk->ip_cmsg_flags & IP_CMSG_RETOPTS) != 0;
+ val = (sk->protinfo.af_inet.cmsg_flags & IP_CMSG_RETOPTS) != 0;
break;
case IP_TOS:
- val=sk->ip_tos;
+ val=sk->protinfo.af_inet.tos;
break;
case IP_TTL:
- val=sk->ip_ttl;
+ val=sk->protinfo.af_inet.ttl;
break;
case IP_HDRINCL:
- val=sk->ip_hdrincl;
+ val=sk->protinfo.af_inet.hdrincl;
break;
case IP_MTU_DISCOVER:
- val=sk->ip_pmtudisc;
+ val=sk->protinfo.af_inet.pmtudisc;
break;
case IP_MTU:
- val = 0;
- lock_sock(sk);
- if (sk->dst_cache)
- val = sk->dst_cache->pmtu;
- release_sock(sk);
- if (!val)
+ {
+ struct dst_entry *dst;
+ val = 0;
+ dst = sk_dst_get(sk);
+ if (dst) {
+ val = dst->pmtu;
+ dst_release(dst);
+ }
+ if (!val) {
+ release_sock(sk);
return -ENOTCONN;
+ }
break;
+ }
case IP_RECVERR:
- val=sk->ip_recverr;
+ val=sk->protinfo.af_inet.recverr;
break;
case IP_MULTICAST_TTL:
- val=sk->ip_mc_ttl;
+ val=sk->protinfo.af_inet.mc_ttl;
break;
case IP_MULTICAST_LOOP:
- val=sk->ip_mc_loop;
+ val=sk->protinfo.af_inet.mc_loop;
break;
case IP_MULTICAST_IF:
{
struct ip_mreqn mreq;
len = min(len,sizeof(struct ip_mreqn));
+ mreq.imr_ifindex = sk->protinfo.af_inet.mc_index;
+ mreq.imr_address.s_addr = sk->protinfo.af_inet.mc_addr;
+ mreq.imr_multiaddr.s_addr = 0;
+ release_sock(sk);
+
if(put_user(len, optlen))
return -EFAULT;
- mreq.imr_ifindex = sk->ip_mc_index;
- mreq.imr_address.s_addr = sk->ip_mc_addr;
- mreq.imr_multiaddr.s_addr = 0;
if(copy_to_user((void *)optval, &mreq, len))
return -EFAULT;
return 0;
}
+ case IP_PKTOPTIONS:
+ {
+ struct msghdr msg;
+
+ release_sock(sk);
+
+ if (sk->type != SOCK_STREAM)
+ return -ENOPROTOOPT;
+
+ msg.msg_control = optval;
+ msg.msg_controllen = len;
+ msg.msg_flags = 0;
+
+ if (sk->protinfo.af_inet.cmsg_flags&IP_CMSG_PKTINFO) {
+ struct in_pktinfo info;
+
+ info.ipi_addr.s_addr = sk->rcv_saddr;
+ info.ipi_spec_dst.s_addr = sk->rcv_saddr;
+ info.ipi_ifindex = sk->protinfo.af_inet.mc_index;
+ put_cmsg(&msg, SOL_IP, IP_PKTINFO, sizeof(info), &info);
+ }
+ if (sk->protinfo.af_inet.cmsg_flags&IP_CMSG_TTL) {
+ int hlim = sk->protinfo.af_inet.mc_ttl;
+ put_cmsg(&msg, SOL_IP, IP_TTL, sizeof(hlim), &hlim);
+ }
+ len -= msg.msg_controllen;
+ return put_user(len, optlen);
+ }
default:
- return(-ENOPROTOOPT);
+#ifdef CONFIG_NETFILTER
+ val = nf_getsockopt(sk, PF_INET, optname, optval,
+ &len);
+ release_sock(sk);
+ if (val >= 0)
+ val = put_user(len, optlen);
+ return val;
+#else
+ release_sock(sk);
+ return -ENOPROTOOPT;
+#endif
}
+ release_sock(sk);
if (len < sizeof(int) && len > 0 && val>=0 && val<255) {
unsigned char ucval = (unsigned char)val;