patch-2.1.124 linux/net/ipv4/ip_sockglue.c
Next file: linux/net/ipv4/ipip.c
Previous file: linux/net/ipv4/ip_output.c
Back to the patch index
Back to the overall index
- Lines: 301
- Date:
Sun Oct 4 10:21:45 1998
- Orig file:
v2.1.123/linux/net/ipv4/ip_sockglue.c
- Orig date:
Sat Sep 5 16:46:42 1998
diff -u --recursive --new-file v2.1.123/linux/net/ipv4/ip_sockglue.c linux/net/ipv4/ip_sockglue.c
@@ -5,7 +5,7 @@
*
* The IP to API glue.
*
- * Version: $Id: ip_sockglue.c,v 1.37 1998/08/26 12:03:57 davem Exp $
+ * Version: $Id: ip_sockglue.c,v 1.39 1998/10/03 09:37:33 davem Exp $
*
* Authors: see ip.c
*
@@ -41,6 +41,11 @@
#include <net/transp_v6.h>
#endif
+#ifdef CONFIG_IP_MASQUERADE
+#include <linux/ip_masq.h>
+#endif
+
+#include <linux/errqueue.h>
#include <asm/uaccess.h>
#define MAX(a,b) ((a)>(b)?(a):(b))
@@ -74,7 +79,8 @@
static void ip_cmsg_recv_ttl(struct msghdr *msg, struct sk_buff *skb)
{
- put_cmsg(msg, SOL_IP, IP_TTL, 1, &skb->nh.iph->ttl);
+ int ttl = skb->nh.iph->ttl;
+ put_cmsg(msg, SOL_IP, IP_TTL, sizeof(int), &ttl);
}
static void ip_cmsg_recv_tos(struct msghdr *msg, struct sk_buff *skb)
@@ -221,6 +227,140 @@
return 0;
}
+void ip_icmp_error(struct sock *sk, struct sk_buff *skb, int err,
+ u16 port, u32 info, u8 *payload)
+{
+ struct sock_exterr_skb *serr;
+
+ if (!sk->ip_recverr)
+ return;
+
+ skb = skb_clone(skb, GFP_ATOMIC);
+ if (!skb)
+ return;
+
+ serr = SKB_EXT_ERR(skb);
+ serr->ee.ee_errno = err;
+ serr->ee.ee_origin = SO_EE_ORIGIN_ICMP;
+ serr->ee.ee_type = skb->h.icmph->type;
+ serr->ee.ee_code = skb->h.icmph->code;
+ serr->ee.ee_pad = 0;
+ serr->ee.ee_info = info;
+ serr->ee.ee_data = 0;
+ serr->addr_offset = (u8*)&(((struct iphdr*)(skb->h.icmph+1))->daddr) - skb->nh.raw;
+ serr->port = port;
+
+ skb->h.raw = payload;
+ skb_pull(skb, payload - skb->data);
+
+ if (sock_queue_err_skb(sk, skb))
+ kfree_skb(skb);
+}
+
+void ip_local_error(struct sock *sk, int err, u32 daddr, u16 port, u32 info)
+{
+ struct sock_exterr_skb *serr;
+ struct iphdr *iph;
+ struct sk_buff *skb;
+
+ if (!sk->ip_recverr)
+ return;
+
+ skb = alloc_skb(sizeof(struct iphdr), GFP_ATOMIC);
+ if (!skb)
+ return;
+
+ iph = (struct iphdr*)skb_put(skb, sizeof(struct iphdr));
+ skb->nh.iph = iph;
+ iph->daddr = daddr;
+
+ serr = SKB_EXT_ERR(skb);
+ serr->ee.ee_errno = err;
+ serr->ee.ee_origin = SO_EE_ORIGIN_LOCAL;
+ serr->ee.ee_type = 0;
+ serr->ee.ee_code = 0;
+ serr->ee.ee_pad = 0;
+ serr->ee.ee_info = info;
+ serr->ee.ee_data = 0;
+ serr->addr_offset = (u8*)&iph->daddr - skb->nh.raw;
+ serr->port = port;
+
+ skb->h.raw = skb->tail;
+ skb_pull(skb, skb->tail - skb->data);
+
+ if (sock_queue_err_skb(sk, skb))
+ kfree_skb(skb);
+}
+
+/*
+ * Handle MSG_ERRQUEUE
+ */
+int ip_recv_error(struct sock *sk, struct msghdr *msg, int len)
+{
+ struct sock_exterr_skb *serr;
+ struct sk_buff *skb, *skb2;
+ struct sockaddr_in *sin;
+ struct {
+ struct sock_extended_err ee;
+ struct sockaddr_in offender;
+ } errhdr;
+ int err;
+ int copied;
+
+ err = -EAGAIN;
+ skb = skb_dequeue(&sk->error_queue);
+ if (skb == NULL)
+ goto out;
+
+ copied = skb->len;
+ if (copied > len) {
+ msg->msg_flags |= MSG_TRUNC;
+ copied = len;
+ }
+ err = memcpy_toiovec(msg->msg_iov, skb->data, copied);
+ if (err)
+ goto out_free_skb;
+
+ serr = SKB_EXT_ERR(skb);
+
+ sin = (struct sockaddr_in *)msg->msg_name;
+ if (sin) {
+ sin->sin_family = AF_INET;
+ sin->sin_addr.s_addr = *(u32*)(skb->nh.raw + serr->addr_offset);
+ sin->sin_port = serr->port;
+ }
+
+ memcpy(&errhdr.ee, &serr->ee, sizeof(struct sock_extended_err));
+ sin = &errhdr.offender;
+ sin->sin_family = AF_UNSPEC;
+ 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)
+ ip_cmsg_recv(msg, skb);
+ }
+
+ put_cmsg(msg, SOL_IP, IP_RECVERR, sizeof(errhdr), &errhdr);
+
+ /* Now we could try to dump offended packet options */
+
+ msg->msg_flags |= MSG_ERRQUEUE;
+ err = copied;
+
+ /* Reset and regenerate socket error */
+ sk->err = 0;
+ if ((skb2 = skb_peek(&sk->error_queue)) != NULL) {
+ sk->err = SKB_EXT_ERR(skb2)->ee.ee_errno;
+ sk->error_report(sk);
+ }
+
+out_free_skb:
+ kfree_skb(skb);
+out:
+ return err;
+}
+
+
/*
* Socket option code for IP. This is the end of the line after any TCP,UDP etc options on
* an IP socket.
@@ -234,10 +374,6 @@
#if defined(CONFIG_IP_FIREWALL)
char tmp_fw[MAX(sizeof(struct ip_fwtest),sizeof(struct ip_fwnew))];
#endif
-#ifdef CONFIG_IP_MASQUERADE
- char masq_ctl[IP_FW_MASQCTL_MAX];
-#endif
-
if(optlen>=sizeof(int)) {
if(get_user(val, (int *) optval))
return -EFAULT;
@@ -347,23 +483,15 @@
return -ENOPROTOOPT;
sk->ip_hdrincl=val?1:0;
return 0;
- case IP_PMTUDISC:
+ case IP_MTU_DISCOVER:
if (val<0 || val>2)
return -EINVAL;
sk->ip_pmtudisc = val;
return 0;
case IP_RECVERR:
- if (sk->type==SOCK_STREAM)
- return -ENOPROTOOPT;
- lock_sock(sk);
- if (sk->ip_recverr && !val) {
- struct sk_buff *skb;
- /* Drain queued errors */
- while((skb=skb_dequeue(&sk->error_queue))!=NULL)
- kfree_skb(skb);
- }
- sk->ip_recverr = val?1:0;
- release_sock(sk);
+ sk->ip_recverr = !!val;
+ if (!val)
+ skb_queue_purge(&sk->error_queue);
return 0;
case IP_MULTICAST_TTL:
if (optlen<1)
@@ -466,17 +594,13 @@
return -err; /* -0 is 0 after all */
#endif /* CONFIG_IP_FIREWALL */
#ifdef CONFIG_IP_MASQUERADE
- case IP_FW_MASQ_ADD:
- case IP_FW_MASQ_DEL:
- case IP_FW_MASQ_FLUSH:
+ case IP_FW_MASQ_CTL:
if(!capable(CAP_NET_ADMIN))
return -EPERM;
- if(optlen>sizeof(masq_ctl) || optlen<1)
+ if(optlen<1)
return -EINVAL;
- if(copy_from_user(masq_ctl,optval,optlen))
- return -EFAULT;
- err=ip_masq_ctl(optname, masq_ctl,optlen);
- return -err; /* -0 is 0 after all */
+ err=ip_masq_uctl(optname, optval ,optlen);
+ return err;
#endif
default:
@@ -491,7 +615,7 @@
int ip_getsockopt(struct sock *sk, int level, int optname, char *optval, int *optlen)
{
- int val,err;
+ int val;
int len;
if(level!=SOL_IP)
@@ -554,9 +678,18 @@
case IP_HDRINCL:
val=sk->ip_hdrincl;
break;
- case IP_PMTUDISC:
+ case IP_MTU_DISCOVER:
val=sk->ip_pmtudisc;
break;
+ case IP_MTU:
+ val = 0;
+ lock_sock(sk);
+ if (sk->dst_cache)
+ val = sk->dst_cache->pmtu;
+ release_sock(sk);
+ if (!val)
+ return -ENOTCONN;
+ break;
case IP_RECVERR:
val=sk->ip_recverr;
break;
@@ -566,7 +699,6 @@
case IP_MULTICAST_LOOP:
val=sk->ip_mc_loop;
break;
-#if 0
case IP_MULTICAST_IF:
{
struct ip_mreqn mreq;
@@ -579,30 +711,6 @@
if(copy_to_user((void *)optval, &mreq, len))
return -EFAULT;
return 0;
- }
-#endif
- case IP_MULTICAST_IF:
- {
- struct device *dev = dev_get_by_index(sk->ip_mc_index);
-
- printk(KERN_INFO "application %s uses old get IP_MULTICAST_IF. Please, report!\n", current->comm);
-
- if (dev == NULL)
- {
- len = 0;
- return put_user(len, optlen);
- }
- dev_lock_list();
- len = min(len,strlen(dev->name));
- err = put_user(len, optlen);
- if (!err)
- {
- err = copy_to_user((void *)optval,dev->name, len);
- if(err)
- err=-EFAULT;
- }
- dev_unlock_list();
- return err;
}
default:
return(-ENOPROTOOPT);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov