diff options
author | Joan Lledó <joanlluislledo@gmail.com> | 2017-11-13 08:31:46 +0100 |
---|---|---|
committer | Samuel Thibault <samuel.thibault@ens-lyon.org> | 2017-12-18 00:01:02 +0100 |
commit | d3594ddad8fdd4f28f2362ad288acd03ed60eb41 (patch) | |
tree | f76d7dffd2f6e8de6011b0333481a51c70f3c6d2 /lwip/options.c | |
parent | 0ca198f1f90071a054287c204a3fd1b4ea315e18 (diff) | |
download | hurd-d3594ddad8fdd4f28f2362ad288acd03ed60eb41.tar.gz hurd-d3594ddad8fdd4f28f2362ad288acd03ed60eb41.tar.bz2 hurd-d3594ddad8fdd4f28f2362ad288acd03ed60eb41.zip |
lwip: Add LwIP-based TCP/IP translator
* Makefile (prog-subdirs): Add lwip.
* config.make.in (HAVE_LIBLWIP, liblwip_CFLAGS, liblwip_LIBS): Define
variables.
* configure.ac: Check for liblwip.
* lwip/: New directory.
Diffstat (limited to 'lwip/options.c')
-rw-r--r-- | lwip/options.c | 342 |
1 files changed, 342 insertions, 0 deletions
diff --git a/lwip/options.c b/lwip/options.c new file mode 100644 index 00000000..6591ac52 --- /dev/null +++ b/lwip/options.c @@ -0,0 +1,342 @@ +/* + Copyright (C) 1996, 1997, 2000, 2001, 2006, 2007, 2017 + Free Software Foundation, Inc. + + Written by Miles Bader <miles@gnu.org> + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + The GNU Hurd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the GNU Hurd. If not, see <http://www.gnu.org/licenses/>. +*/ + +/* Fsysopts and command line option parsing */ + +#include <options.h> + +#include <stdlib.h> +#include <argp.h> +#include <argz.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <net/if_arp.h> +#include <error.h> + +#include <lwip/netif.h> +#include <lwip/tcpip.h> + +#include <lwip-hurd.h> +#include <lwip-util.h> +#include <netif/ifcommon.h> + +/* Fsysopts and command line option parsing */ + +/* Adds an empty interface slot to H, and sets H's current interface to it, or + returns an error. */ +static error_t +parse_hook_add_interface (struct parse_hook *h) +{ + int i; + + struct parse_interface *new = realloc (h->interfaces, + (h->num_interfaces + + 1) * + sizeof (struct parse_interface)); + if (!new) + return ENOMEM; + + h->interfaces = new; + h->num_interfaces++; + h->curint = new + h->num_interfaces - 1; + memset (&h->curint->dev_name, 0, DEV_NAME_LEN); + h->curint->address.addr = INADDR_NONE; + h->curint->netmask.addr = INADDR_NONE; + h->curint->peer.addr = INADDR_NONE; + h->curint->gateway.addr = INADDR_NONE; + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) + ip6_addr_set_zero ((ip6_addr_t *) & h->curint->addr6[i]); + + return 0; +} + +/* Option parser */ +static error_t +parse_opt (int opt, char *arg, struct argp_state *state) +{ + error_t err = 0; + struct parse_hook *h = state->hook; + int i; + + /* Return _ERR from this routine */ +#define RETURN(_err) \ + do { return _err; } while (0) + + /* Print a parsing error message and (if exiting is turned off) return the + error code ERR. */ +#define PERR(err, fmt, args...) \ + do { argp_error (state, fmt , ##args); RETURN (err); } while (0) + + /* Like PERR but for non-parsing errors. */ +#define FAIL(rerr, status, perr, fmt, args...) \ + do{ argp_failure (state, status, perr, fmt , ##args); RETURN (rerr); } while(0) + + /* Parse STR and return the corresponding internet address. If STR is not + a valid internet address, signal an error mentioned TYPE. */ +#undef ADDR +#define ADDR(str, type) \ + ({ unsigned long addr = inet_addr (str); \ + if (addr == INADDR_NONE) PERR (EINVAL, "Malformed %s", type); \ + addr; }) + + if (!arg && state->next < state->argc && (*state->argv[state->next] != '-')) + { + arg = state->argv[state->next]; + state->next++; + } + + switch (opt) + { + struct parse_interface *in; + uint8_t addr6_prefix_len; + ip6_addr_t *address6; + char *ptr; + + case 'i': + /* An interface. */ + err = 0; + + /* First see if a previously specified one is being re-specified. */ + for (in = h->interfaces; in < h->interfaces + h->num_interfaces; in++) + if (strcmp (in->dev_name, arg) == 0) + /* Re-use an old slot. */ + { + h->curint = in; + return 0; + } + + if (h->curint->dev_name[0]) + /* The current interface slot is not available. */ + { + /* Add a new interface entry. */ + err = parse_hook_add_interface (h); + } + in = h->curint; + + strncpy (in->dev_name, arg, DEV_NAME_LEN); + break; + + case 'a': + /* An address */ + if (arg) + { + /* Check if it's legal */ + h->curint->address.addr = ADDR (arg, "address"); + if (!IN_CLASSA (ntohl (h->curint->address.addr)) + && !IN_CLASSB (ntohl (h->curint->address.addr)) + && !IN_CLASSC (ntohl (h->curint->address.addr))) + { + if (IN_MULTICAST (ntohl (h->curint->address.addr))) + 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 + { + /* No address given, set default values */ + h->curint->address.addr = ADDR ("0.0.0.0", "address"); + h->curint->netmask.addr = ADDR ("255.0.0.0", "netmask"); + h->curint->gateway.addr = INADDR_NONE; + } + break; + + case 'm': + /* Netmask */ + if (arg) + h->curint->netmask.addr = ADDR (arg, "netmask"); + else + h->curint->netmask.addr = INADDR_NONE; + break; + + case 'p': + /* Peer address */ + if (arg) + h->curint->peer.addr = ADDR (arg, "peer"); + else + h->curint->peer.addr = INADDR_NONE; + break; + + case 'g': + /* Gateway for the current interface */ + if (arg) + { + h->curint->gateway.addr = ADDR (arg, "gateway"); + } + else + h->curint->gateway.addr = INADDR_NONE; + break; + + case '4': + translator_bind (PORTCLASS_INET, arg); + + /* Install IPv6 port class on bootstrap port. */ + lwip_bootstrap_portclass = PORTCLASS_INET6; + break; + + case '6': + translator_bind (PORTCLASS_INET6, arg); + break; + + case 'A': + /* IPv6 address */ + if (arg) + { + /* Check prefix */ + if ((ptr = strchr (arg, '/'))) + { + addr6_prefix_len = atoi (ptr + 1); + if (addr6_prefix_len > 128) + FAIL (EINVAL, 1, 0, "%s: The prefix-length is invalid", arg); + + /* Remove the prefix from the address */ + *ptr = 0; + + if (addr6_prefix_len != 64) + { + error (0, 0, + "The only supported value for the prefix-length" + " is /64. Defaulting to %s/64.\n", arg); + } + } + else + { + error (0, 0, "No prefix-length given, " + "defaulting to %s/64.\n", arg); + } + + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) + { + address6 = (ip6_addr_t *) & h->curint->addr6[i]; + + /* Is the slot free? */ + if (!ip6_addr_isany (address6)) + continue; + + /* Use the slot */ + if (ip6addr_aton (arg, address6) <= 0) + PERR (EINVAL, "Malformed address"); + + break; + } + } + + break; + + case ARGP_KEY_INIT: + /* Initialize our parsing state. */ + h = malloc (sizeof (struct parse_hook)); + if (!h) + FAIL (ENOMEM, 11, ENOMEM, "option parsing"); + + h->interfaces = 0; + h->num_interfaces = 0; + err = parse_hook_add_interface (h); + if (err) + FAIL (err, 12, err, "option parsing"); + + state->hook = h; + break; + + case ARGP_KEY_SUCCESS: + /* If the interface list is not empty, a previous configuration exists */ + if (netif_list == 0) + /* Inititalize LwIP */ + tcpip_init (init_ifs, h); + else + /* No need to initialize the stack again */ + init_ifs (h); + break; + + case ARGP_KEY_ERROR: + /* Parsing error occurred, free everything. */ + free (h->interfaces); + free (h); + break; + + default: + return ARGP_ERR_UNKNOWN; + } + + return err; +} + +/* Create the output for fsysopts */ +error_t +trivfs_append_args (struct trivfs_control * fsys, char **argz, + size_t * argz_len) +{ + error_t err = 0; + struct netif *netif; + int i; + uint32_t addr, netmask, gateway; + uint32_t addr6[LWIP_IPV6_NUM_ADDRESSES][4]; + uint8_t addr6_prefix_len[LWIP_IPV6_NUM_ADDRESSES]; + +#define ADD_OPT(fmt, args...) \ + do { char buf[100]; \ + if (! err) { \ + snprintf (buf, sizeof buf, fmt , ##args); \ + err = argz_add (argz, argz_len, buf); } } while (0) +#define ADD_ADDR_OPT(name, addr) \ + do { struct in_addr i; \ + i.s_addr = (addr); \ + ADD_OPT ("--%s=%s", name, inet_ntoa (i)); } while (0) + + for (netif = netif_list; netif != 0; netif = netif->next) + { + /* Skip the loopback interface */ + if (netif_get_state (netif)->type == ARPHRD_LOOPBACK) + { + continue; + } + + inquire_device (netif, &addr, &netmask, 0, 0, &gateway, + (uint32_t *) addr6, addr6_prefix_len); + + ADD_OPT ("--interface=%s", netif_get_state (netif)->devname); + if (addr != INADDR_NONE) + ADD_ADDR_OPT ("address", addr); + if (netmask != INADDR_NONE) + ADD_ADDR_OPT ("netmask", netmask); + if (gateway != INADDR_NONE) + ADD_ADDR_OPT ("gateway", gateway); + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) + if (!ip6_addr_isany (((ip6_addr_t *) & addr6[i]))) + ADD_OPT ("--address6=%s/%d", + ip6addr_ntoa (((ip6_addr_t *) & addr6[i])), + addr6_prefix_len[i]); + } + +#undef ADD_ADDR_OPT + +#undef ADD_OPT + return err; +} + +struct argp lwip_argp = { options, parse_opt, 0, doc }; + +struct argp *trivfs_runtime_argp = &lwip_argp; |