summaryrefslogtreecommitdiff
path: root/pfinet/options.c
diff options
context:
space:
mode:
authorStefan Siegl <stesie@brokenpipe.de>2007-10-08 21:59:10 +0000
committerStefan Siegl <stesie@brokenpipe.de>2007-10-08 21:59:10 +0000
commit1145e4da1321f80b8f1fe9184bdd8e596f2dcd2a (patch)
treeebdd0cc6a174d8a585fa93fadfbde01c5f4a96ac /pfinet/options.c
parent9ef3092f3172c049beb847d1dca602e2b4b755c5 (diff)
2007-10-08 Stefan Siegl <stesie@brokenpipe.de>
* config.h (CONFIG_IPV6, CONFIG_IPV6_EUI64): New defines, set to 1. * Makefile (ipv6-srcs): New variable. (LINUXSRCS): Add ipv6-srcs. * ethernet.c (ethernet_demuxer): Call skb_put instead of changing skb->len directly, and thus now update skb->tail accordingly. * pfinet.h (PORTCLASS_INET, PORTCLASS_INET6): New enums. (trivfs_protid_portclasses, trivfs_protid_nportclasses) (trivfs_cntl_portclasses, trivfs_cntl_nportclasses): Declare these. (pfinet_bootstrap_portclass): New variable. (pfinet_bind): New function. * main.c: Define _HACK_ERRNO_H. Include <errno.h>. (trivfs_protid_portclasses, trivfs_cntl_portclasses): New slots for PORTCLASS_INET6. (trivfs_protid_nportclasses, trivfs_cntl_nportclasses): Set to 2. (pfinet_bootstrap_portclass): New variable. (pfinet_bind): New function. (pfinet_activate_ipv6) [CONFIG_IPV6]: New function. (main) [CONFIG_IPV6]: Call inet6_proto_init. (main): Reordered to allow pfinet to not be started as a translator, if pfinet_bind is used. If started as a translator, treat pfinet_bootstrap_portclass when calling trivfs_startup. * options.c: Include <net/sock.h>, <net/ip6_fib.h>, <net/ip6_route.h> and <net/addrconf.h>. (options): New option `ipv4'. (options) [CONFIG_IPV6]: New options `ipv6', `address6' and `gateway6'. (parse_interface) [CONFIG_IPV6]: Add address6 and gateway6. (parse_hook_add_interface) [CONFIG_IPV6]: Initialize address6 and gateway6. (parse_opt): Parse new args. * socket-ops.c (S_socket_create): Call either net_families[PF_INET]->create or net_families[PF_INET6]->create, depending on receiving master. (S_socket_create_address): Allow creation of AF_INET6 addresses. * glue-include/asm/delay.h: New stub file. * glue-include/linux/ipv6.h: Merged many bits unmodified from Linux header file. * glue-include/linux/in6.h: Likewise. (ipv6mr_ifindex): New define, glue to ipv6mr_interface. * glue-include/linux/socket.h (SOL_IPV6, SOL_ICMPV6): New defines. * linux-src/net/ipv6/addrconf.c (ipv6_find_idev, inet6_addr_add) (inet6_addr_del) [_HURD_]: Make these non-static. (addrconf_set_dstaddr, addrconf_add_ifaddr, addrconf_del_ifaddr) [_HURD_]: Don't define these functions. * linux-src/net/ipv6/route_ipv6.c (ipv6_route_ioctl) [_HURD_]: Likewise. * linux-src/net/ipv6/af_inet6.c (inet6_ioctl) [_HURD_]: Don't define the function, instead #define it to 0. (inet6_proto_init) [_HURD_]: Don't call sit_init. * linux-src/net/ipv6/udp_ipv6.c (udp_ioctl) [_HURD_]: Define to 0. (udp_v6_get_port): Put empty statement after label to silence compiler. * linux-src/net/ipv6/tcp_ipv6.c (tcp_v6_get_port, tcp_v6_rcv): Likewise. * linux-src/net/ipv6/icmpv6.c (icmpv6_rcv): Likewise. (icmpv6_init) [_HURD_]: Don't initialize i_uid and i_gid. * linux-src/net/ipv6/mcast.c (igmp6_init): Likewise. * linux-src/net/ipv6/ndisc.c (ndisc_init): Likewise. * linux-src/net/ipv6/ip6_fib.c (BUG_TRAP): Don't use __FUNCTION__ as a string but a variable, to keep gcc happy. (fib6_walker_list): Make it non-static, to keep gcc happy. * linux-src/net/ipv6/ip6_flowlabel.c (fl_create) [_HURD_]: Drop IPV6_FL_S_USER support, since current->euid is not available.
Diffstat (limited to 'pfinet/options.c')
-rw-r--r--pfinet/options.c210
1 files changed, 190 insertions, 20 deletions
diff --git a/pfinet/options.c b/pfinet/options.c
index d05ac6d0..85738a5b 100644
--- a/pfinet/options.c
+++ b/pfinet/options.c
@@ -1,6 +1,6 @@
/* Pfinet option parsing
- Copyright (C) 1996, 1997, 2000, 2001, 2006 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1997, 2000, 2001, 2006, 2007 Free Software Foundation, Inc.
Written by Miles Bader <miles@gnu.org>
@@ -37,7 +37,11 @@
#include <linux/route.h>
#include <linux/rtnetlink.h>
#include <net/route.h>
+#include <net/sock.h>
#include <net/ip_fib.h>
+#include <net/ip6_fib.h>
+#include <net/ip6_route.h>
+#include <net/addrconf.h>
/* Our interface to the set of devices. */
extern error_t find_device (char *name, struct device **device);
@@ -50,6 +54,12 @@ extern error_t configure_device (struct device *dev, uint32_t addr,
extern void inquire_device (struct device *dev, uint32_t *addr,
uint32_t *netmask, uint32_t *peer,
uint32_t *broadcast);
+
+/* addrconf.c */
+extern struct inet6_dev *ipv6_find_idev (struct device *dev);
+extern int inet6_addr_add (int ifindex, struct in6_addr *pfx, int plen);
+extern int inet6_addr_del (int ifindex, struct in6_addr *pfx, int plen);
+
/* Pfinet options. Used for both startup and runtime. */
static const struct argp_option options[] =
@@ -60,6 +70,12 @@ static const struct argp_option options[] =
{"netmask", 'm', "MASK", 0, "Set the netmask"},
{"peer", 'p', "ADDRESS", 0, "Set the peer address"},
{"gateway", 'g', "ADDRESS", 0, "Set the default gateway"},
+ {"ipv4", '4', "NAME", 0, "Put active IPv4 translator on NAME"},
+#ifdef CONFIG_IPV6
+ {"ipv6", '6', "NAME", 0, "Put active IPv6 translator on NAME"},
+ {"address6", 'A', "ADDR/LEN",0, "Set the global IPv6 address"},
+ {"gateway6", 'G', "ADDRESS", 0, "Set the IPv6 default gateway"},
+#endif
{"shutdown", 's', 0, 0, "Shut it down"},
{0}
};
@@ -74,8 +90,14 @@ struct parse_interface
/* The network interface in question. */
struct device *device;
- /* New values to apply to it. */
+ /* New values to apply to it. (IPv4) */
uint32_t address, netmask, peer, gateway;
+
+#ifdef CONFIG_IPV6
+ /* New IPv6 configuration to apply. */
+ struct inet6_ifaddr address6;
+ struct in6_addr gateway6;
+#endif
};
/* Used to hold data during argument parsing. */
@@ -108,6 +130,12 @@ parse_hook_add_interface (struct parse_hook *h)
h->curint->netmask = INADDR_NONE;
h->curint->peer = INADDR_NONE;
h->curint->gateway = INADDR_NONE;
+
+#ifdef CONFIG_IPV6
+ memset (&h->curint->address6, 0, sizeof (struct inet6_ifaddr));
+ memset (&h->curint->gateway6, 0, sizeof (struct in6_addr));
+#endif
+
return 0;
}
@@ -146,6 +174,10 @@ parse_opt (int opt, char *arg, struct argp_state *state)
{
struct parse_interface *in;
uint32_t gateway;
+#ifdef CONFIG_IPV6
+ struct parse_interface *gw6_in;
+ char *ptr;
+#endif
case 'i':
/* An interface. */
@@ -196,6 +228,52 @@ parse_opt (int opt, char *arg, struct argp_state *state)
case 'g':
h->curint->gateway = ADDR (arg, "gateway"); break;
+ case '4':
+ pfinet_bind (PORTCLASS_INET, arg);
+
+ /* Install IPv6 port class on bootstrap port. */
+ pfinet_bootstrap_portclass = PORTCLASS_INET6;
+ break;
+
+#ifdef CONFIG_IPV6
+ case '6':
+ pfinet_bind (PORTCLASS_INET6, arg);
+ break;
+
+ case 'A':
+ if ((ptr = strchr (arg, '/')))
+ {
+ h->curint->address6.prefix_len = atoi (ptr + 1);
+ if (h->curint->address6.prefix_len > 128)
+ FAIL (EINVAL, 1, 0, "%s: The prefix-length is invalid", arg);
+
+ *ptr = 0;
+ }
+ else
+ {
+ h->curint->address6.prefix_len = 64;
+ fprintf (stderr, "No prefix-length given, defaulting to %s/64.\n",
+ arg);
+ }
+
+ if (inet_pton (AF_INET6, arg, &h->curint->address6.addr) <= 0)
+ PERR (EINVAL, "Malformed address");
+
+ if (IN6_IS_ADDR_MULTICAST (&h->curint->address6.addr))
+ FAIL (EINVAL, 1, 0, "%s: Cannot set interface address to "
+ "multicast address", arg);
+ break;
+
+ case 'G':
+ if (inet_pton (AF_INET6, arg, &h->curint->gateway6) <= 0)
+ PERR (EINVAL, "Malformed gateway");
+
+ if (IN6_IS_ADDR_MULTICAST (&h->curint->gateway6))
+ FAIL (EINVAL, 1, 0, "%s: Cannot set gateway to "
+ "multicast address", arg);
+ break;
+#endif /* CONFIG_IPV6 */
+
case ARGP_KEY_INIT:
/* Initialize our parsing state. */
h = malloc (sizeof (struct parse_hook));
@@ -234,30 +312,74 @@ parse_opt (int opt, char *arg, struct argp_state *state)
#endif
gateway = INADDR_NONE;
+#ifdef CONFIG_IPV6
+ gw6_in = NULL;
+#endif
for (in = h->interfaces; in < h->interfaces + h->num_interfaces; in++)
- if (in->gateway != INADDR_NONE)
- {
- if (gateway != INADDR_NONE)
- FAIL (err, 15, 0, "Cannot have multiple default gateways");
- gateway = in->gateway;
- in->gateway = INADDR_NONE;
- }
-
+ {
+ if (in->gateway != INADDR_NONE)
+ {
+ if (gateway != INADDR_NONE)
+ FAIL (err, 15, 0, "Cannot have multiple default gateways");
+ gateway = in->gateway;
+ in->gateway = INADDR_NONE;
+ }
+
+#ifdef CONFIG_IPV6
+ if (!IN6_IS_ADDR_UNSPECIFIED (&in->gateway6))
+ {
+ if (gw6_in != NULL)
+ FAIL (err, 15, 0, "Cannot have multiple IPv6 "
+ "default gateways");
+ gw6_in = in;
+ }
+#endif
+ }
/* Successfully finished parsing, return a result. */
__mutex_lock (&global_lock);
for (in = h->interfaces; in < h->interfaces + h->num_interfaces; in++)
- if (in->address != INADDR_NONE || in->netmask != INADDR_NONE)
- {
- err = configure_device (in->device, in->address, in->netmask,
- in->peer, INADDR_NONE);
- if (err)
- {
- __mutex_unlock (&global_lock);
- FAIL (err, 16, 0, "cannot configure interface");
- }
- }
+ {
+#ifdef CONFIG_IPV6
+ struct inet6_dev *idev = NULL;
+ if (trivfs_protid_portclasses[PORTCLASS_INET6] != MACH_PORT_NULL
+ && in->device)
+ idev = ipv6_find_idev(in->device);
+#endif
+
+ if (in->address != INADDR_NONE || in->netmask != INADDR_NONE)
+ {
+ err = configure_device (in->device, in->address, in->netmask,
+ in->peer, INADDR_NONE);
+ if (err)
+ {
+ __mutex_unlock (&global_lock);
+ FAIL (err, 16, 0, "cannot configure interface");
+ }
+ }
+
+#ifdef CONFIG_IPV6
+ if (!idev)
+ continue;
+
+ if (!IN6_IS_ADDR_UNSPECIFIED (&in->address6.addr))
+ {
+ /* First let's remove all non-local addresses. */
+ struct inet6_ifaddr *ifa = idev->addr_list;
+ do
+ if (!IN6_IS_ADDR_LINKLOCAL (&ifa->addr)
+ && !IN6_IS_ADDR_SITELOCAL (&ifa->addr))
+ inet6_addr_del (in->device->ifindex, &ifa->addr,
+ ifa->prefix_len);
+ while ((ifa = ifa->if_next));
+
+ /* Now assign the new address */
+ inet6_addr_add (in->device->ifindex, &in->address6.addr,
+ in->address6.prefix_len);
+ }
+#endif /* CONFIG_IPV6 */
+ }
/* Set the default gateway. This code is cobbled together from what
the SIOCADDRT ioctl code does, and from the apparent functionality
@@ -315,6 +437,16 @@ parse_opt (int opt, char *arg, struct argp_state *state)
}
}
+ /* Set IPv6 default router. */
+#ifdef CONFIG_IPV6
+ if (trivfs_protid_portclasses[PORTCLASS_INET6] != MACH_PORT_NULL)
+ {
+ rt6_purge_dflt_routers (0);
+ if (gw6_in)
+ rt6_add_dflt_router (&gw6_in->gateway6, gw6_in->device);
+ }
+#endif
+
__mutex_unlock (&global_lock);
/* Fall through to free hook. */
@@ -372,6 +504,44 @@ trivfs_append_args (struct trivfs_control *fsys, char **argz, size_t *argz_len)
ADD_ADDR_OPT ("gateway", FIB_RES_GW (res));
#undef ADD_ADDR_OPT
+
+#ifdef CONFIG_IPV6
+ struct inet6_dev *idev = NULL;
+
+ if (trivfs_protid_portclasses[PORTCLASS_INET6] != MACH_PORT_NULL)
+ idev = ipv6_find_idev(dev);
+
+ if (idev)
+ {
+ struct inet6_ifaddr *ifa = idev->addr_list;
+ struct in6_addr daddr;
+ static char addr_buf[INET6_ADDRSTRLEN];
+
+ /* Look for IPv6 default route (we use the first ifa->addr as
+ source address), but don't yet push it to the option stack. */
+ memset (&daddr, 0, sizeof(daddr));
+ struct fib6_node *fib = fib6_lookup
+ (&ip6_routing_table, &daddr, &ifa->addr);
+ struct rt6_info *rt6i = fib->leaf;
+
+ /* Push all IPv6 addresses assigned to the interface. */
+ do
+ {
+ inet_ntop (AF_INET6, &ifa->addr, addr_buf, INET6_ADDRSTRLEN);
+ ADD_OPT ("--address6=%s/%d", addr_buf, ifa->prefix_len);
+ }
+ while ((ifa = ifa->if_next));
+
+ /* Last not least push --gateway6 option. */
+ if(rt6i->rt6i_dev == dev)
+ {
+ inet_ntop (AF_INET6, &rt6i->rt6i_gateway, addr_buf,
+ INET6_ADDRSTRLEN);
+ ADD_OPT ("--gateway6=%s", addr_buf);
+ }
+ }
+#endif /* CONFIG_IPV6 */
+
#undef ADD_OPT
return err;