diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1998-03-17 22:05:47 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1998-03-17 22:05:47 +0000 |
commit | 27cfca1ec98e91261b1a5355d10a8996464b63af (patch) | |
tree | 8e895a53e372fa682b4c0a585b9377d67ed70d0e /net/ipv4/devinet.c | |
parent | 6a76fb7214c477ccf6582bd79c5b4ccc4f9c41b1 (diff) |
Look Ma' what I found on my harddisk ...
o New faster syscalls for 2.1.x, too
o Upgrade to 2.1.89.
Don't try to run this. It's flaky as hell. But feel free to debug ...
Diffstat (limited to 'net/ipv4/devinet.c')
-rw-r--r-- | net/ipv4/devinet.c | 234 |
1 files changed, 198 insertions, 36 deletions
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 269361e35..7d5f0021f 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -1,7 +1,7 @@ /* * NET3 IP device support routines. * - * Version: $Id: devinet.c,v 1.14 1997/10/10 22:40:44 davem Exp $ + * Version: $Id: devinet.c,v 1.3 1997/12/16 05:37:35 ralf Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -46,6 +46,9 @@ #include <linux/notifier.h> #include <linux/inetdevice.h> #include <linux/igmp.h> +#ifdef CONFIG_SYSCTL +#include <linux/sysctl.h> +#endif #ifdef CONFIG_KERNELD #include <linux/kerneld.h> #endif @@ -54,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 @@ -62,7 +68,10 @@ static void rtmsg_ifa(int event, struct in_ifaddr *); 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; @@ -95,9 +104,22 @@ struct in_device *inetdev_init(struct device *dev) 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(dev, &arp_tbl)) == NULL) { + kfree(in_dev); + return NULL; + } +#ifdef CONFIG_SYSCTL + neigh_sysctl_register(dev, in_dev->arp_parms, NET_IPV4, NET_IPV4_NEIGH, "ipv4"); +#endif dev->ip_ptr = in_dev; - ip_mc_init_dev(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; } @@ -112,7 +134,11 @@ static void inetdev_destroy(struct in_device *in_dev) 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); } @@ -201,8 +227,10 @@ inet_insert_ifa(struct in_device *in_dev, struct in_ifaddr *ifa) } } - if (!(ifa->ifa_flags&IFA_F_SECONDARY)) + if (!(ifa->ifa_flags&IFA_F_SECONDARY)) { + net_srandom(ifa->ifa_local); ifap = last_primary; + } cli(); ifa->ifa_next = *ifap; @@ -263,7 +291,7 @@ struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, u32 prefix, u32 ma 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; @@ -272,11 +300,11 @@ inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) 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; @@ -288,13 +316,13 @@ inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) 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) @@ -309,21 +337,21 @@ inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) 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); @@ -394,7 +422,6 @@ int devinet_ioctl(unsigned int cmd, void *arg) 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) @@ -413,7 +440,6 @@ int devinet_ioctl(unsigned int cmd, void *arg) case SIOCSIFBRDADDR: /* Set the broadcast address */ case SIOCSIFDSTADDR: /* Set the destination address */ case SIOCSIFNETMASK: /* Set the netmask for the interface */ - case SIOCSIFPFLAGS: /* Set per device sysctl controls */ if (!suser()) return -EACCES; if (sin->sin_family != AF_INET) @@ -464,10 +490,6 @@ int devinet_ioctl(unsigned int cmd, void *arg) 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) { @@ -483,10 +505,6 @@ int devinet_ioctl(unsigned int cmd, void *arg) 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; @@ -592,7 +610,7 @@ inet_gifconf(struct device *dev, char *buf, int len) 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) @@ -704,7 +722,7 @@ static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa, ifm = NLMSG_DATA(nlh); ifm->ifa_family = AF_INET; ifm->ifa_prefixlen = ifa->ifa_prefixlen; - ifm->ifa_flags = ifa->ifa_flags; + ifm->ifa_flags = ifa->ifa_flags|IFA_F_PERMANENT; ifm->ifa_scope = ifa->ifa_scope; ifm->ifa_index = ifa->ifa_dev->dev->ifindex; if (ifa->ifa_prefixlen) @@ -722,7 +740,7 @@ static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa, nlmsg_failure: rtattr_failure: - skb_put(skb, b - skb->tail); + skb_trim(skb, b - skb->data); return -1; } @@ -770,7 +788,7 @@ static void rtmsg_ifa(int event, struct in_ifaddr * ifa) return; } if (inet_fill_ifaddr(skb, ifa, 0, 0, event) < 0) { - kfree_skb(skb, 0); + kfree_skb(skb); netlink_set_err(rtnl, 0, RTMGRP_IPV4_IFADDR, EINVAL); return; } @@ -783,7 +801,7 @@ static struct rtnetlink_link inet_rtnetlink_table[RTM_MAX-RTM_BASE+1] = { { NULL, NULL, }, { NULL, NULL, }, - { NULL, rtnetlink_dump_ifinfo, }, + { NULL, NULL, }, { NULL, NULL, }, { inet_rtm_newaddr, NULL, }, @@ -816,6 +834,145 @@ static struct rtnetlink_link inet_rtnetlink_table[RTM_MAX-RTM_BASE+1] = #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 /* @@ -856,4 +1013,9 @@ __initfunc(void devinet_init(void)) #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 } |