Index: ChangeLog =================================================================== RCS file: /sources/hurd/hurd/pfinet/ChangeLog,v retrieving revision 1.86 diff -u -p -r1.86 ChangeLog --- ChangeLog 14 Oct 2007 02:26:10 -0000 1.86 +++ ChangeLog 14 Oct 2007 12:23:33 -0000 @@ -1,3 +1,28 @@ +2007-10-14 Christian Dietrich + * options.c (options): Marked -a, -g -m, -p, -A, -G + OPTION_ARG_OPTIONAL. Adding -d option. + (parse_interface_copy_device): New function. + (parse_opt): When selecting another interface with -i + set the options from e.g. a prior fsysopts call as default + values. For -a, -g, -p, -g, -A, -G set the optional + argument as value. When there is no argument, delete the + value (e.g. unset default gateway). Delete delete default gateways + only if the set gateway is on an interface modified in this call. + Add always an route for dhcp packages on all devices. By doing + this we can send dhcp renew packages. + (trivfs_append_args): Add --gateway only once. + +2007-10-14 Marco Gerards + * options.c (options): Add the option `dhcp'. + (parse_hook_add_interface): Initialize the `dhcp' member for the + parse hook. + (parse_opt): In case pfinet is started with the argument `--dhcp', + set the address to `0.0.0.0', the netmask to `255.0.0.0' and add + the route for `0.0.0.0' so broadcasting works. + + * linux-src/net/ipv4/devinet.c (inet_insert_ifa) [_HURD_]: Don't + fail when the address is `0.0.0.0'. + 2007-10-14 Stefan Siegl * options.c (ipv6_get_dflt_router) [CONFIG_IPV6]: New function. Index: options.c =================================================================== RCS file: /sources/hurd/hurd/pfinet/options.c,v retrieving revision 1.14 diff -u -p -r1.14 options.c --- options.c 14 Oct 2007 02:26:10 -0000 1.14 +++ options.c 14 Oct 2007 12:23:35 -0000 @@ -66,16 +66,17 @@ static const struct argp_option options[ { {"interface", 'i', "DEVICE", 0, "Network interface to use", 1}, {0,0,0,0,"These apply to a given interface:", 2}, - {"address", 'a', "ADDRESS", 0, "Set the network address"}, - {"netmask", 'm', "MASK", 0, "Set the netmask"}, - {"peer", 'p', "ADDRESS", 0, "Set the peer address"}, - {"gateway", 'g', "ADDRESS", 0, "Set the default gateway"}, + {"address", 'a', "ADDRESS", OPTION_ARG_OPTIONAL, "Set the network address"}, + {"netmask", 'm', "MASK", OPTION_ARG_OPTIONAL, "Set the netmask"}, + {"peer", 'p', "ADDRESS", OPTION_ARG_OPTIONAL, "Set the peer address"}, + {"gateway", 'g', "ADDRESS", OPTION_ARG_OPTIONAL, "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"}, + {"address6", 'A', "ADDR/LEN",OPTION_ARG_OPTIONAL, "Set the global IPv6 address"}, + {"gateway6", 'G', "ADDRESS", OPTION_ARG_OPTIONAL, "Set the IPv6 default gateway"}, #endif + {"dhcp", 'd', 0 , 0, "Prepare pfinet for dhcp"}, {"shutdown", 's', 0, 0, "Shut it down"}, {0} }; @@ -112,6 +113,53 @@ struct parse_hook struct parse_interface *curint; }; +static void +parse_interface_copy_device(struct device *src, + struct parse_interface *dst) +{ + uint32_t broad; + struct rt_key key = { 0 }; + struct inet6_dev *idev = NULL; + struct fib_result res; + + inquire_device (src, &dst->address, &dst->netmask, + &dst->peer, &broad); + /* Get gateway */ + dst->gateway = INADDR_NONE; + key.oif = src->ifindex; + if (! main_table->tb_lookup (main_table, &key, &res) + && FIB_RES_GW(res) != INADDR_ANY) + dst->gateway = FIB_RES_GW (res); +#ifdef CONFIG_IPV6 + if (trivfs_protid_portclasses[PORTCLASS_INET6] != MACH_PORT_NULL) + idev = ipv6_find_idev(src); + + if (idev) + { + struct inet6_ifaddr *ifa = idev->addr_list; + struct in6_addr daddr; + + /* 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; + if(rt6i->rt6i_dev == src) + memcpy(&dst->gateway6, &rt6i->rt6i_gateway, sizeof(struct in6_addr)); + /* Search for global address and set it in dst */ + do + { + if(!IN6_IS_ADDR_LINKLOCAL(&ifa->addr)) { + memcpy(&dst->address6, ifa, sizeof(struct inet6_ifaddr)); + break; + } + } + while ((ifa = ifa->if_next)); + } +#endif +} + /* Adds an empty interface slot to H, and sets H's current interface to it, or returns an error. */ static error_t @@ -152,6 +200,7 @@ ipv6_get_dflt_router (void) #endif /* CONFIG_IPV6 */ + static error_t parse_opt (int opt, char *arg, struct argp_state *state) { @@ -185,8 +234,7 @@ parse_opt (int opt, char *arg, struct ar switch (opt) { - struct parse_interface *in; - uint32_t gateway; + struct parse_interface *in, *gw4_in; #ifdef CONFIG_IPV6 struct parse_interface *gw6_in; char *ptr; @@ -212,35 +260,63 @@ parse_opt (int opt, char *arg, struct ar } in = h->curint; - if (! err) + if (! err) err = find_device (arg, &in->device); + if (err) FAIL (err, 10, err, "%s", arg); - + /* Set old interface values */ + parse_interface_copy_device(in->device, in); break; case 'a': - h->curint->address = ADDR (arg, "address"); - if (!IN_CLASSA (ntohl (h->curint->address)) - && !IN_CLASSB (ntohl (h->curint->address)) - && !IN_CLASSC (ntohl (h->curint->address))) - { - if (IN_MULTICAST (ntohl (h->curint->address))) - FAIL (EINVAL, 1, 0, - "%s: Cannot set interface address to multicast address", - arg); - else - FAIL (EINVAL, 1, 0, - "%s: Illegal or undefined network address", arg); - } + if (arg) { + h->curint->address = ADDR (arg, "address"); + if (!IN_CLASSA (ntohl (h->curint->address)) + && !IN_CLASSB (ntohl (h->curint->address)) + && !IN_CLASSC (ntohl (h->curint->address))) + { + if (IN_MULTICAST (ntohl (h->curint->address))) + FAIL (EINVAL, 1, 0, + "%s: Cannot set interface address to multicast address", + arg); + else + FAIL (EINVAL, 1, 0, + "%s: Illegal or undefined network address", arg); + } + } else { + h->curint->address = ADDR ("0.0.0.0", "address"); + h->curint->netmask = ADDR ("255.0.0.0", "netmask"); + h->curint->gateway = INADDR_NONE; + } + break; + case 'd': + h->curint->address = ADDR ("0.0.0.0", "address"); + h->curint->netmask = ADDR ("255.0.0.0", "netmask"); break; case 'm': - h->curint->netmask = ADDR (arg, "netmask"); break; + if (arg) + h->curint->netmask = ADDR (arg, "netmask"); + else + h->curint->netmask = INADDR_NONE; + break; case 'p': - h->curint->peer = ADDR (arg, "peer"); break; + if (arg) + h->curint->peer = ADDR (arg, "peer"); + else + h->curint->peer = INADDR_NONE; + break; case 'g': - h->curint->gateway = ADDR (arg, "gateway"); break; - + if (arg) { + /* Remove an possible other default gateway */ + for (in = h->interfaces; in < h->interfaces + h->num_interfaces; + in++) + in->gateway = INADDR_NONE; + h->curint->gateway = ADDR (arg, "gateway"); + } + else + h->curint->gateway = INADDR_NONE; + break; case '4': pfinet_bind (PORTCLASS_INET, arg); @@ -254,36 +330,42 @@ parse_opt (int opt, char *arg, struct ar 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); + if (arg) { + 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); + } else + memset (&h->curint->address6, 0, sizeof (struct inet6_ifaddr)); 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); + if (arg) { + 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); + } else + memset (&h->curint->gateway6, 0, sizeof (struct in6_addr)); break; #endif /* CONFIG_IPV6 */ @@ -323,20 +405,19 @@ parse_opt (int opt, char *arg, struct ar /* Specifying a netmask for an address-less interface is a no-no. */ FAIL (EDESTADDRREQ, 14, 0, "Cannot set netmask"); #endif - - gateway = INADDR_NONE; #ifdef CONFIG_IPV6 gw6_in = NULL; #endif + gw4_in = NULL; for (in = h->interfaces; in < h->interfaces + h->num_interfaces; in++) { + /* delete interface if it doesn't match the actual netmask */ + if (! ( (h->curint->address & h->curint->netmask) + == (h->curint->gateway & h->curint->netmask))) + h->curint->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; - } + gw4_in = in; #ifdef CONFIG_IPV6 if (!IN6_IS_ADDR_UNSPECIFIED (&in->gateway6)) @@ -377,24 +458,24 @@ parse_opt (int opt, char *arg, struct ar continue; /* First let's remove all non-local addresses. */ - struct inet6_ifaddr *ifa = idev->addr_list; - - while (ifa) - { - struct inet6_ifaddr *c_ifa = ifa; - ifa = ifa->if_next; - - if (IN6_ARE_ADDR_EQUAL (&c_ifa->addr, &in->address6.addr)) - memset (&in->address6, 0, sizeof (struct inet6_ifaddr)); - - else if (!IN6_IS_ADDR_LINKLOCAL (&c_ifa->addr) - && !IN6_IS_ADDR_SITELOCAL (&c_ifa->addr)) - inet6_addr_del (in->device->ifindex, &c_ifa->addr, - c_ifa->prefix_len); - } - - if (!IN6_IS_ADDR_UNSPECIFIED (&in->address6.addr)) - { + struct inet6_ifaddr *ifa = idev->addr_list; + + while (ifa) + { + struct inet6_ifaddr *c_ifa = ifa; + ifa = ifa->if_next; + + if (IN6_ARE_ADDR_EQUAL (&c_ifa->addr, &in->address6.addr)) + memset (&in->address6, 0, sizeof (struct inet6_ifaddr)); + + else if (!IN6_IS_ADDR_LINKLOCAL (&c_ifa->addr) + && !IN6_IS_ADDR_SITELOCAL (&c_ifa->addr)) + inet6_addr_del (in->device->ifindex, &c_ifa->addr, + c_ifa->prefix_len); + } + + if (!IN6_IS_ADDR_UNSPECIFIED (&in->address6.addr)) + { /* Now assign the new address */ inet6_addr_add (in->device->ifindex, &in->address6.addr, in->address6.prefix_len); @@ -423,28 +504,35 @@ parse_opt (int opt, char *arg, struct ar req.rtm.rtm_scope = RT_SCOPE_UNIVERSE; req.rtm.rtm_type = RTN_UNICAST; req.rtm.rtm_protocol = RTPROT_STATIC; - rta.rta_gw = &gateway; - if (gateway == INADDR_NONE) + if (!gw4_in) { - /* Delete any existing default route. */ - req.nlh.nlmsg_type = RTM_DELROUTE; - req.nlh.nlmsg_flags = 0; - tb = fib_get_table (req.rtm.rtm_table); - if (tb) - { - err = - (*tb->tb_delete) (tb, &req.rtm, &rta, &req.nlh, 0); - if (err && err != ESRCH) - { - __mutex_unlock (&global_lock); - FAIL (err, 17, 0, "cannot remove old default gateway"); - } - err = 0; - } + /* Delete any existing dflt route on configured devices */ + for (in = h->interfaces; in < h->interfaces + h->num_interfaces; + in++) { + req.nlh.nlmsg_type = RTM_DELROUTE; + req.nlh.nlmsg_flags = 0; + rta.rta_oif = &in->device->ifindex; + tb = fib_get_table (req.rtm.rtm_table); + if (tb) + { + err = - (*tb->tb_delete) + (tb, &req.rtm, &rta, &req.nlh, 0); + if (err && err != ESRCH) + { + __mutex_unlock (&global_lock); + FAIL (err, 17, 0, + "cannot remove old default gateway"); + } + err = 0; + } + } } else { /* Add a default route, replacing any existing one. */ + rta.rta_oif = &gw4_in->device->ifindex; + rta.rta_gw = &gw4_in->gateway; req.nlh.nlmsg_type = RTM_NEWROUTE; req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE; tb = fib_new_table (req.rtm.rtm_table); @@ -467,13 +555,69 @@ parse_opt (int opt, char *arg, struct ar if (!gw6_in || rt6i->rt6i_dev != gw6_in->device || !IN6_ARE_ADDR_EQUAL (&rt6i->rt6i_gateway, &gw6_in->gateway6)) { - rt6_purge_dflt_routers (0); + /* Delete any existing dflt route on configured devices */ + for (in = h->interfaces; in < h->interfaces + + h->num_interfaces; in++) + if (rt6i->rt6i_dev == in->device || gw6_in ) + rt6_purge_dflt_routers (0); + if (gw6_in) rt6_add_dflt_router (&gw6_in->gateway6, gw6_in->device); } } #endif + /* Setup the routing required for DHCP. */ + for (in = h->interfaces; in < h->interfaces + h->num_interfaces; in++) + { + struct kern_rta rta; + struct + { + struct nlmsghdr nlh; + struct rtmsg rtm; + } req; + struct fib_table *tb; + struct rtentry route; + struct sockaddr_in *dst; + struct device *dev; + + dst = (struct sockaddr_in *) &route.rt_dst; + + dev = dev_get (in->device->name); + if (!dev) + { + __mutex_unlock (&global_lock); + FAIL (ENODEV, 17, 0, "unknown device"); + } + + /* Simulate the SIOCADDRT behavior. */ + bzero (&route, sizeof (struct rtentry)); + bzero (&req.rtm, sizeof req.rtm); + bzero (&rta, sizeof rta); + req.nlh.nlmsg_type = RTM_NEWROUTE; + /* Append this routing for 0.0.0.0. By this way we can send always + * dhcp messages (e.g dhcp renew + */ + req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE + | NLM_F_APPEND; + req.rtm.rtm_protocol = RTPROT_BOOT; + req.rtm.rtm_scope = RT_SCOPE_LINK; + req.rtm.rtm_type = RTN_UNICAST; + rta.rta_dst = &dst->sin_addr.s_addr; + rta.rta_oif = &dev->ifindex; + tb = fib_new_table (req.rtm.rtm_table); + if (tb) + err = tb->tb_insert (tb, &req.rtm, &rta, &req.nlh, NULL); + else + err = ENOBUFS; + + if (err) + { + __mutex_unlock (&global_lock); + FAIL (err, 17, 0, "cannot add route"); + } + } + __mutex_unlock (&global_lock); /* Fall through to free hook. */ @@ -526,8 +670,9 @@ trivfs_append_args (struct trivfs_contro ADD_ADDR_OPT ("netmask", mask); if (peer != addr) ADD_ADDR_OPT ("peer", peer); - key.iif = dev->ifindex; - if (! main_table->tb_lookup (main_table, &key, &res)) + key.oif = dev->ifindex; + if (! main_table->tb_lookup (main_table, &key, &res) + && FIB_RES_GW(res) != INADDR_ANY) ADD_ADDR_OPT ("gateway", FIB_RES_GW (res)); #undef ADD_ADDR_OPT Index: timer-emul.c =================================================================== RCS file: /sources/hurd/hurd/pfinet/timer-emul.c,v retrieving revision 1.13 diff -u -p -r1.13 timer-emul.c --- timer-emul.c 5 May 2002 03:25:53 -0000 1.13 +++ timer-emul.c 14 Oct 2007 12:23:35 -0000 @@ -132,7 +132,7 @@ del_timer (struct timer_list *timer) timer->prev = 0; return 1; } - else + else return 0; } Index: linux-src/net/ipv4/devinet.c =================================================================== RCS file: /sources/hurd/hurd/pfinet/linux-src/net/ipv4/devinet.c,v retrieving revision 1.8 diff -u -p -r1.8 devinet.c --- linux-src/net/ipv4/devinet.c 18 Jul 2001 17:37:13 -0000 1.8 +++ linux-src/net/ipv4/devinet.c 14 Oct 2007 12:23:40 -0000 @@ -214,10 +214,12 @@ inet_insert_ifa(struct in_device *in_dev { struct in_ifaddr *ifa1, **ifap, **last_primary; +#ifndef _HURD_ if (ifa->ifa_local == 0) { inet_free_ifa(ifa); return 0; } +#endif ifa->ifa_flags &= ~IFA_F_SECONDARY; last_primary = &in_dev->ifa_list;