patch-1.3.22 linux/net/ipv4/ip.c
Next file: linux/net/ipv4/ip_fw.c
Previous file: linux/net/ipv4/igmp.c
Back to the patch index
Back to the overall index
- Lines: 240
- Date:
Fri Sep 1 14:31:56 1995
- Orig file:
v1.3.21/linux/net/ipv4/ip.c
- Orig date:
Mon Aug 28 14:52:26 1995
diff -u --recursive --new-file v1.3.21/linux/net/ipv4/ip.c linux/net/ipv4/ip.c
@@ -88,6 +88,8 @@
* Alan Cox : Fixed forwarding (by even more popular demand 8))
* Alan Cox : Fixed SNMP statistics [I think]
* Gerhard Koerting : IP fragmentation forwarding fix
+ * Alan Cox : Device lock against page fault.
+ * Alan Cox : IP_HDRINCL facility.
*
*
*
@@ -143,6 +145,7 @@
#include <net/checksum.h>
#include <linux/igmp.h>
#include <linux/ip_fw.h>
+#include <linux/mroute.h>
#define CONFIG_IP_DEFRAG
@@ -1523,8 +1526,7 @@
if ( iph->daddr == skb->dev->pa_addr || (brd = ip_chk_addr(iph->daddr)) != 0)
{
#ifdef CONFIG_IP_MULTICAST
-
- if(brd==IS_MULTICAST && iph->daddr!=IGMP_ALL_HOSTS && !(dev->flags&IFF_LOOPBACK))
+ if(!(dev->flags&IFF_ALLMULTI) && brd==IS_MULTICAST && iph->daddr!=IGMP_ALL_HOSTS && !(dev->flags&IFF_LOOPBACK))
{
/*
* Check it is for one of our groups
@@ -1729,7 +1731,7 @@
static void ip_loopback(struct device *old_dev, struct sk_buff *skb)
{
struct device *dev=&loopback_dev;
- int len=skb->len-old_dev->hard_header_len;
+ int len=ntohs(skb->ip_hdr->tot_len);
struct sk_buff *newskb=dev_alloc_skb(len+dev->hard_header_len+15);
if(newskb==NULL)
@@ -1932,8 +1934,10 @@
{
if(sk==NULL || sk->ip_mc_loop)
{
- if(iph->daddr==IGMP_ALL_HOSTS)
+ if(iph->daddr==IGMP_ALL_HOSTS || (dev->flags&IFF_ALLMULTI))
+ {
ip_loopback(dev,skb);
+ }
else
{
struct ip_mc_list *imc=dev->ip_mc_list;
@@ -1978,6 +1982,8 @@
}
else
{
+ if(sk)
+ sk->err = ENETDOWN;
ip_statistics.IpOutDiscards++;
if (free)
kfree_skb(skb, FREE_WRITE);
@@ -2069,18 +2075,28 @@
struct ip_fw tmp_fw;
#endif
if (optval == NULL)
- return(-EINVAL);
-
- err=verify_area(VERIFY_READ, optval, sizeof(int));
- if(err)
- return err;
-
- val = get_user((int *) optval);
- ucval=get_user((unsigned char *) optval);
-
+ {
+ val=0;
+ ucval=0;
+ }
+ else
+ {
+ err=verify_area(VERIFY_READ, optval, sizeof(int));
+ if(err)
+ return err;
+ val = get_user((int *) optval);
+ ucval=get_user((unsigned char *) optval);
+ }
+
if(level!=SOL_IP)
return -EOPNOTSUPP;
-
+#ifdef CONFIG_IP_MROUTE
+ if(optname>=MRT_BASE && optname <=MRT_BASE+10)
+ {
+ return ip_mroute_setsockopt(sk,optname,optval,optlen);
+ }
+#endif
+
switch(optname)
{
case IP_TOS:
@@ -2097,6 +2113,11 @@
return -EINVAL;
sk->ip_ttl=val;
return 0;
+ case IP_HDRINCL:
+ if(sk->type!=SOCK_RAW)
+ return -ENOPROTOOPT;
+ sk->ip_hdrincl=val?1:0;
+ return 0;
#ifdef CONFIG_IP_MULTICAST
case IP_MULTICAST_TTL:
{
@@ -2324,6 +2345,13 @@
if(level!=SOL_IP)
return -EOPNOTSUPP;
+#ifdef CONFIG_IP_MROUTE
+ if(optname>=MRT_BASE && optname <=MRT_BASE+10)
+ {
+ return ip_mroute_getsockopt(sk,optname,optval,optlen);
+ }
+#endif
+
switch(optname)
{
case IP_TOS:
@@ -2332,6 +2360,9 @@
case IP_TTL:
val=sk->ip_ttl;
break;
+ case IP_HDRINCL:
+ val=sk->ip_hdrincl;
+ break;
#ifdef CONFIG_IP_MULTICAST
case IP_MULTICAST_TTL:
val=sk->ip_mc_ttl;
@@ -2526,7 +2557,8 @@
skb->arp=1;
}
skb->ip_hdr=iph=(struct iphdr *)skb_put(skb,length);
- if(type!=IPPROTO_RAW)
+ dev_lock_list();
+ if(!sk->ip_hdrincl)
{
iph->version=4;
iph->ihl=5;
@@ -2544,6 +2576,7 @@
}
else
getfrag(frag,saddr,(void *)iph,0,length);
+ dev_unlock_list();
#ifdef CONFIG_IP_ACCT
ip_fw_chk((void *)skb->data,dev,ip_acct_chain, IP_FW_F_ACCEPT,1);
#endif
@@ -2559,7 +2592,7 @@
fragheaderlen = dev->hard_header_len;
- if(type != IPPROTO_RAW)
+ if(!sk->ip_hdrincl)
fragheaderlen += 20;
/*
@@ -2598,10 +2631,16 @@
* Can't fragment raw packets
*/
- if (type == IPPROTO_RAW && offset > 0)
+ if (sk->ip_hdrincl && offset > 0)
return(-EMSGSIZE);
/*
+ * Lock the device lists.
+ */
+
+ dev_lock_list();
+
+ /*
* Get an identifier
*/
@@ -2627,6 +2666,7 @@
ip_statistics.IpOutDiscards++;
if(nfrags>1)
ip_statistics.IpFragCreates++;
+ dev_unlock_list();
return(error);
}
@@ -2674,7 +2714,7 @@
* Only write IP header onto non-raw packets
*/
- if(type != IPPROTO_RAW)
+ if(!sk->ip_hdrincl)
{
iph->version = 4;
@@ -2732,11 +2772,13 @@
/*
* Loop back any frames. The check for IGMP_ALL_HOSTS is because
* you are always magically a member of this group.
+ *
+ * Always loop back all host messages when running as a multicast router.
*/
- if(sk==NULL || sk->ip_mc_loop)
+ if(sk==NULL || sk->ip_mc_loop)
{
- if(skb->daddr==IGMP_ALL_HOSTS)
+ if(skb->daddr==IGMP_ALL_HOSTS || (dev->flags&IFF_ALLMULTI))
ip_loopback(rt?rt->rt_dev:dev,skb);
else
{
@@ -2784,22 +2826,25 @@
{
/*
* Whoops...
- *
- * FIXME: There is a small nasty here. During the ip_build_xmit we could
- * page fault between the route lookup and device send, the device might be
- * removed and unloaded.... We need to add device locks on this.
*/
ip_statistics.IpOutDiscards++;
if(nfrags>1)
ip_statistics.IpFragCreates+=nfrags;
kfree_skb(skb, FREE_WRITE);
+ dev_unlock_list();
+ /*
+ * BSD behaviour.
+ */
+ if(sk!=NULL)
+ sk->err=ENETDOWN;
return(0); /* lose rest of fragments */
}
}
while (offset >= 0);
if(nfrags>1)
ip_statistics.IpFragCreates+=nfrags;
+ dev_unlock_list();
return(0);
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this