patch-2.1.89 linux/net/ipv4/devinet.c

Next file: linux/net/ipv4/fib_frontend.c
Previous file: linux/net/ipv4/arp.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.88/linux/net/ipv4/devinet.c linux/net/ipv4/devinet.c
@@ -57,6 +57,9 @@
 #include <net/route.h>
 #include <net/ip_fib.h>
 
+struct ipv4_devconf ipv4_devconf = { 1, 1, 1, 1, 0, };
+static struct ipv4_devconf ipv4_devconf_dflt = { 1, 1, 1, 1, 1, };
+
 #ifdef CONFIG_RTNETLINK
 static void rtmsg_ifa(int event, struct in_ifaddr *);
 #else
@@ -65,7 +68,10 @@
 
 static struct notifier_block *inetaddr_chain;
 static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, int destroy);
-
+#ifdef CONFIG_SYSCTL
+static void devinet_sysctl_register(struct in_device *in_dev, struct ipv4_devconf *p);
+static void devinet_sysctl_unregister(struct ipv4_devconf *p);
+#endif
 
 int inet_ifa_count;
 int inet_dev_count;
@@ -98,15 +104,20 @@
 		return NULL;
 	inet_dev_count++;
 	memset(in_dev, 0, sizeof(*in_dev));
+	memcpy(&in_dev->cnf, &ipv4_devconf_dflt, sizeof(in_dev->cnf));
+	in_dev->cnf.sysctl = NULL;
 	in_dev->dev = dev;
-	if ((in_dev->arp_parms = neigh_parms_alloc(&arp_tbl)) == NULL)
-		in_dev->arp_parms = &arp_tbl.parms;
+	if ((in_dev->arp_parms = neigh_parms_alloc(dev, &arp_tbl)) == NULL) {
+		kfree(in_dev);
+		return NULL;
+	}
 #ifdef CONFIG_SYSCTL
-	else
-		in_dev->arp_parms->sysctl_table =
-			neigh_sysctl_register(dev, in_dev->arp_parms, NET_IPV4, NET_IPV4_NEIGH, "ipv4");
+	neigh_sysctl_register(dev, in_dev->arp_parms, NET_IPV4, NET_IPV4_NEIGH, "ipv4");
 #endif
 	dev->ip_ptr = in_dev;
+#ifdef CONFIG_SYSCTL
+	devinet_sysctl_register(in_dev, &in_dev->cnf);
+#endif
 	if (dev->flags&IFF_UP)
 		ip_mc_up(in_dev);
 	return in_dev;
@@ -123,6 +134,9 @@
 		inet_free_ifa(ifa);
 	}
 
+#ifdef CONFIG_SYSCTL
+	devinet_sysctl_unregister(&in_dev->cnf);
+#endif
 	in_dev->dev->ip_ptr = NULL;
 	neigh_parms_release(&arp_tbl, in_dev->arp_parms);
 	kfree(in_dev);
@@ -277,7 +291,7 @@
 int
 inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
-	struct kern_ifa  *k_ifa = arg;
+	struct rtattr  **rta = arg;
 	struct in_device *in_dev;
 	struct ifaddrmsg *ifm = NLMSG_DATA(nlh);
 	struct in_ifaddr *ifa, **ifap;
@@ -286,11 +300,11 @@
 		return -EADDRNOTAVAIL;
 
 	for (ifap=&in_dev->ifa_list; (ifa=*ifap)!=NULL; ifap=&ifa->ifa_next) {
-		if ((k_ifa->ifa_local && memcmp(k_ifa->ifa_local, &ifa->ifa_local, 4)) ||
-		    (k_ifa->ifa_label && strcmp(k_ifa->ifa_label, ifa->ifa_label)) ||
-		    (k_ifa->ifa_address &&
+		if ((rta[IFA_LOCAL-1] && memcmp(RTA_DATA(rta[IFA_LOCAL-1]), &ifa->ifa_local, 4)) ||
+		    (rta[IFA_LABEL-1] && strcmp(RTA_DATA(rta[IFA_LABEL-1]), ifa->ifa_label)) ||
+		    (rta[IFA_ADDRESS-1] &&
 		     (ifm->ifa_prefixlen != ifa->ifa_prefixlen ||
-		      !inet_ifa_match(*(u32*)k_ifa->ifa_address, ifa))))
+		      !inet_ifa_match(*(u32*)RTA_DATA(rta[IFA_ADDRESS-1]), ifa))))
 			continue;
 		inet_del_ifa(in_dev, ifap, 1);
 		return 0;
@@ -302,13 +316,13 @@
 int
 inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
-	struct kern_ifa *k_ifa = arg;
+	struct rtattr **rta = arg;
 	struct device *dev;
 	struct in_device *in_dev;
 	struct ifaddrmsg *ifm = NLMSG_DATA(nlh);
 	struct in_ifaddr *ifa;
 
-	if (ifm->ifa_prefixlen > 32 || k_ifa->ifa_local == NULL)
+	if (ifm->ifa_prefixlen > 32 || rta[IFA_LOCAL-1] == NULL)
 		return -EINVAL;
 
 	if ((dev = dev_get_by_index(ifm->ifa_index)) == NULL)
@@ -323,21 +337,21 @@
 	if ((ifa = inet_alloc_ifa()) == NULL)
 		return -ENOBUFS;
 
-	if (k_ifa->ifa_address == NULL)
-		k_ifa->ifa_address = k_ifa->ifa_local;
-	memcpy(&ifa->ifa_local, k_ifa->ifa_local, 4);
-	memcpy(&ifa->ifa_address, k_ifa->ifa_address, 4);
+	if (rta[IFA_ADDRESS-1] == NULL)
+		rta[IFA_ADDRESS-1] = rta[IFA_LOCAL-1];
+	memcpy(&ifa->ifa_local, RTA_DATA(rta[IFA_LOCAL-1]), 4);
+	memcpy(&ifa->ifa_address, RTA_DATA(rta[IFA_ADDRESS-1]), 4);
 	ifa->ifa_prefixlen = ifm->ifa_prefixlen;
 	ifa->ifa_mask = inet_make_mask(ifm->ifa_prefixlen);
-	if (k_ifa->ifa_broadcast)
-		memcpy(&ifa->ifa_broadcast, k_ifa->ifa_broadcast, 4);
-	if (k_ifa->ifa_anycast)
-		memcpy(&ifa->ifa_anycast, k_ifa->ifa_anycast, 4);
+	if (rta[IFA_BROADCAST-1])
+		memcpy(&ifa->ifa_broadcast, RTA_DATA(rta[IFA_BROADCAST-1]), 4);
+	if (rta[IFA_ANYCAST-1])
+		memcpy(&ifa->ifa_anycast, RTA_DATA(rta[IFA_ANYCAST-1]), 4);
 	ifa->ifa_flags = ifm->ifa_flags;
 	ifa->ifa_scope = ifm->ifa_scope;
 	ifa->ifa_dev = in_dev;
-	if (k_ifa->ifa_label)
-		memcpy(ifa->ifa_label, k_ifa->ifa_label, IFNAMSIZ);
+	if (rta[IFA_LABEL-1])
+		memcpy(ifa->ifa_label, RTA_DATA(rta[IFA_LABEL-1]), IFNAMSIZ);
 	else
 		memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
 
@@ -408,7 +422,6 @@
 	case SIOCGIFBRDADDR:	/* Get the broadcast address */
 	case SIOCGIFDSTADDR:	/* Get the destination address */
 	case SIOCGIFNETMASK:	/* Get the netmask for the interface */
-	case SIOCGIFPFLAGS:	/* Get per device sysctl controls */	
 		/* Note that this ioctls will not sleep,
 		   so that we do not impose a lock.
 		   One day we will be forced to put shlock here (I mean SMP)
@@ -418,7 +431,6 @@
 		break;
 
 	case SIOCSIFFLAGS:
-	case SIOCSIFPFLAGS:	/* Set per device sysctl controls */	
 		if (!suser())
 			return -EACCES;
 		rtnl_lock();
@@ -478,10 +490,6 @@
 			sin->sin_addr.s_addr = ifa->ifa_mask;
 			goto rarok;
 
-		case SIOCGIFPFLAGS:
-			ifr.ifr_flags = in_dev->flags;
-			goto rarok;
-
 		case SIOCSIFFLAGS:
 #ifdef CONFIG_IP_ALIAS
 			if (colon) {
@@ -497,10 +505,6 @@
 			ret = dev_change_flags(dev, ifr.ifr_flags);
 			break;
 	
-		case SIOCSIFPFLAGS:
-			in_dev->flags = ifr.ifr_flags;
-			break;
-
 		case SIOCSIFADDR:	/* Set interface address (and family) */
 			if (inet_abc_len(sin->sin_addr.s_addr) < 0) {
 				ret = -EINVAL;
@@ -606,7 +610,7 @@
 			done += sizeof(ifr);
 			continue;
 		}
-		if (len < sizeof(ifr))
+		if (len < (int) sizeof(ifr))
 			return done;
 		memset(&ifr, 0, sizeof(struct ifreq));
 		if (ifa->ifa_label)
@@ -736,7 +740,7 @@
 
 nlmsg_failure:
 rtattr_failure:
-	skb_put(skb, b - skb->tail);
+	skb_trim(skb, b - skb->data);
 	return -1;
 }
 
@@ -797,7 +801,7 @@
 {
 	{ NULL,			NULL,			},
 	{ NULL,			NULL,			},
-	{ NULL,			rtnetlink_dump_ifinfo,	},
+	{ NULL,			NULL,			},
 	{ NULL,			NULL,			},
 
 	{ inet_rtm_newaddr,	NULL,			},
@@ -810,9 +814,9 @@
 	{ inet_rtm_getroute,	inet_dump_fib,		},
 	{ NULL,			NULL,			},
 
-	{ neigh_add,		NULL,			},
-	{ neigh_delete,		NULL,			},
-	{ NULL,			neigh_dump_info,	},
+	{ NULL,			NULL,			},
+	{ NULL,			NULL,			},
+	{ NULL,			NULL,			},
 	{ NULL,			NULL,			},
 
 #ifdef CONFIG_IP_MULTIPLE_TABLES
@@ -830,6 +834,145 @@
 
 #endif /* CONFIG_RTNETLINK */
 
+
+#ifdef CONFIG_SYSCTL
+
+void inet_forward_change()
+{
+	struct device *dev;
+	int on = ipv4_devconf.forwarding;
+
+	ipv4_devconf.accept_redirects = !on;
+	ipv4_devconf_dflt.forwarding = on;
+
+	for (dev = dev_base; dev; dev = dev->next) {
+		struct in_device *in_dev = dev->ip_ptr;
+		if (in_dev)
+			in_dev->cnf.forwarding = on;
+	}
+
+	rt_cache_flush(0);
+
+	ip_statistics.IpForwarding = on ? 1 : 2;
+}
+
+static
+int devinet_sysctl_forward(ctl_table *ctl, int write, struct file * filp,
+			   void *buffer, size_t *lenp)
+{
+	int *valp = ctl->data;
+	int val = *valp;
+	int ret;
+
+	ret = proc_dointvec(ctl, write, filp, buffer, lenp);
+
+	if (write && *valp != val) {
+		if (valp == &ipv4_devconf.forwarding)
+			inet_forward_change();
+		else if (valp != &ipv4_devconf_dflt.forwarding)
+			rt_cache_flush(0);
+	}
+
+        return ret;
+}
+
+static struct devinet_sysctl_table
+{
+	struct ctl_table_header *sysctl_header;
+	ctl_table devinet_vars[12];
+	ctl_table devinet_dev[2];
+	ctl_table devinet_conf_dir[2];
+	ctl_table devinet_proto_dir[2];
+	ctl_table devinet_root_dir[2];
+} devinet_sysctl = {
+	NULL,
+	{{NET_IPV4_CONF_FORWARDING, "forwarding",
+         &ipv4_devconf.forwarding, sizeof(int), 0644, NULL,
+         &devinet_sysctl_forward},
+	{NET_IPV4_CONF_MC_FORWARDING, "mc_forwarding",
+         &ipv4_devconf.mc_forwarding, sizeof(int), 0444, NULL,
+         &proc_dointvec},
+	{NET_IPV4_CONF_ACCEPT_REDIRECTS, "accept_redirects",
+         &ipv4_devconf.accept_redirects, sizeof(int), 0644, NULL,
+         &proc_dointvec},
+	{NET_IPV4_CONF_SECURE_REDIRECTS, "secure_redirects",
+         &ipv4_devconf.secure_redirects, sizeof(int), 0644, NULL,
+         &proc_dointvec},
+	{NET_IPV4_CONF_SHARED_MEDIA, "shared_media",
+         &ipv4_devconf.shared_media, sizeof(int), 0644, NULL,
+         &proc_dointvec},
+	{NET_IPV4_CONF_RP_FILTER, "rp_filter",
+         &ipv4_devconf.rp_filter, sizeof(int), 0644, NULL,
+         &proc_dointvec},
+	{NET_IPV4_CONF_SEND_REDIRECTS, "send_redirects",
+         &ipv4_devconf.send_redirects, sizeof(int), 0644, NULL,
+         &proc_dointvec},
+	{NET_IPV4_CONF_ACCEPT_SOURCE_ROUTE, "accept_source_route",
+         &ipv4_devconf.accept_source_route, sizeof(int), 0644, NULL,
+         &proc_dointvec},
+	{NET_IPV4_CONF_PROXY_ARP, "proxy_arp",
+         &ipv4_devconf.proxy_arp, sizeof(int), 0644, NULL,
+         &proc_dointvec},
+	{NET_IPV4_CONF_BOOTP_RELAY, "bootp_relay",
+         &ipv4_devconf.bootp_relay, sizeof(int), 0644, NULL,
+         &proc_dointvec},
+        {NET_IPV4_CONF_LOG_MARTIANS, "log_martians",
+         &ipv4_devconf.log_martians, sizeof(int), 0644, NULL,
+         &proc_dointvec},
+	 {0}},
+
+	{{NET_PROTO_CONF_ALL, "all", NULL, 0, 0555, devinet_sysctl.devinet_vars},{0}},
+	{{NET_IPV4_CONF, "conf", NULL, 0, 0555, devinet_sysctl.devinet_dev},{0}},
+	{{NET_IPV4, "ipv4", NULL, 0, 0555, devinet_sysctl.devinet_conf_dir},{0}},
+	{{CTL_NET, "net", NULL, 0, 0555, devinet_sysctl.devinet_proto_dir},{0}}
+};
+
+static void devinet_sysctl_register(struct in_device *in_dev, struct ipv4_devconf *p)
+{
+	int i;
+	struct device *dev = in_dev ? in_dev->dev : NULL;
+	struct devinet_sysctl_table *t;
+
+	t = kmalloc(sizeof(*t), GFP_KERNEL);
+	if (t == NULL)
+		return;
+	memcpy(t, &devinet_sysctl, sizeof(*t));
+	for (i=0; i<sizeof(t->devinet_vars)/sizeof(t->devinet_vars[0])-1; i++) {
+		t->devinet_vars[i].data += (char*)p - (char*)&ipv4_devconf;
+		t->devinet_vars[i].de = NULL;
+	}
+	if (dev) {
+		t->devinet_dev[0].procname = dev->name;
+		t->devinet_dev[0].ctl_name = dev->ifindex;
+	} else {
+		t->devinet_dev[0].procname = "default";
+		t->devinet_dev[0].ctl_name = NET_PROTO_CONF_DEFAULT;
+	}
+	t->devinet_dev[0].child = t->devinet_vars;
+	t->devinet_dev[0].de = NULL;
+	t->devinet_conf_dir[0].child = t->devinet_dev;
+	t->devinet_conf_dir[0].de = NULL;
+	t->devinet_proto_dir[0].child = t->devinet_conf_dir;
+	t->devinet_proto_dir[0].de = NULL;
+	t->devinet_root_dir[0].child = t->devinet_proto_dir;
+	t->devinet_root_dir[0].de = NULL;
+
+	t->sysctl_header = register_sysctl_table(t->devinet_root_dir, 0);
+	if (t->sysctl_header == NULL)
+		kfree(t);
+}
+
+static void devinet_sysctl_unregister(struct ipv4_devconf *p)
+{
+	if (p->sysctl) {
+		struct devinet_sysctl_table *t = p->sysctl;
+		p->sysctl = NULL;
+		unregister_sysctl_table(t->sysctl_header);
+		kfree(t);
+	}
+}
+#endif
+
 #ifdef CONFIG_IP_PNP_BOOTP
 
 /*
@@ -869,5 +1012,10 @@
 	register_netdevice_notifier(&ip_netdev_notifier);
 #ifdef CONFIG_RTNETLINK
 	rtnetlink_links[AF_INET] = inet_rtnetlink_table;
+#endif
+#ifdef CONFIG_SYSCTL
+	devinet_sysctl.sysctl_header =
+		register_sysctl_table(devinet_sysctl.devinet_root_dir, 0);
+	devinet_sysctl_register(NULL, &ipv4_devconf_dflt);
 #endif
 }

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov