From 2c76c1a6d801a5290c25c2d7bb3632e4af2f61c6 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 21 Oct 2013 14:06:07 +0100 Subject: [PATCH] [ipv6] Add IPv6 socket address converter Signed-off-by: Michael Brown --- src/include/ipxe/netdevice.h | 5 +- src/net/ipv6.c | 99 +++++++++++++++++++++++++++++++++++- 2 files changed, 102 insertions(+), 2 deletions(-) diff --git a/src/include/ipxe/netdevice.h b/src/include/ipxe/netdevice.h index 2d08f34f..ae6e5585 100644 --- a/src/include/ipxe/netdevice.h +++ b/src/include/ipxe/netdevice.h @@ -292,6 +292,9 @@ struct net_device_stats { struct net_device_error errors[NETDEV_MAX_UNIQUE_ERRORS]; }; +/** Maximum length of a network device name */ +#define NETDEV_NAME_LEN 12 + /** * A network device * @@ -312,7 +315,7 @@ struct net_device { /** Index of this network device */ unsigned int index; /** Name of this network device */ - char name[12]; + char name[NETDEV_NAME_LEN]; /** Underlying hardware device */ struct device *dev; diff --git a/src/net/ipv6.c b/src/net/ipv6.c index 8dc251ba..08e8e100 100644 --- a/src/net/ipv6.c +++ b/src/net/ipv6.c @@ -190,7 +190,7 @@ static void del_ipv6_miniroute ( struct ipv6_miniroute *miniroute ) { * @ret miniroute Routing table entry to use, or NULL if no route */ static struct ipv6_miniroute * ipv6_route ( unsigned int scope_id, - struct in6_addr **dest ) { + struct in6_addr **dest ) { struct ipv6_miniroute *miniroute; int local; @@ -749,6 +749,96 @@ static const char * ipv6_ntoa ( const void *net_addr ) { return inet6_ntoa ( net_addr ); } +/** + * Transcribe IPv6 socket address + * + * @v sa Socket address + * @ret string Socket address in standard notation + */ +static const char * ipv6_sock_ntoa ( struct sockaddr *sa ) { + static char buf[ 39 /* "xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx" */ + + 1 /* "%" */ + NETDEV_NAME_LEN + 1 /* NUL */ ]; + struct sockaddr_in6 *sin6 = ( ( struct sockaddr_in6 * ) sa ); + struct in6_addr *in = &sin6->sin6_addr; + struct net_device *netdev; + const char *netdev_name; + + /* Identify network device, if applicable */ + if ( IN6_IS_ADDR_LINKLOCAL ( in ) ) { + netdev = find_netdev_by_index ( sin6->sin6_scope_id ); + netdev_name = ( netdev ? netdev->name : "UNKNOWN" ); + } else { + netdev_name = NULL; + } + + /* Format socket address */ + snprintf ( buf, sizeof ( buf ), "%s%s%s", inet6_ntoa ( in ), + ( netdev_name ? "%" : "" ), + ( netdev_name ? netdev_name : "" ) ); + return buf; +} + +/** + * Parse IPv6 socket address + * + * @v string Socket address string + * @v sa Socket address to fill in + * @ret rc Return status code + */ +static int ipv6_sock_aton ( const char *string, struct sockaddr *sa ) { + struct sockaddr_in6 *sin6 = ( ( struct sockaddr_in6 * ) sa ); + struct in6_addr in; + struct net_device *netdev; + size_t len; + char *tmp; + char *in_string; + char *netdev_string; + int rc; + + /* Create modifiable copy of string */ + tmp = strdup ( string ); + if ( ! tmp ) { + rc = -ENOMEM; + goto err_alloc; + } + in_string = tmp; + + /* Strip surrounding "[...]", if present */ + len = strlen ( in_string ); + if ( ( in_string[0] == '[' ) && ( in_string[ len - 1 ] == ']' ) ) { + in_string[ len - 1 ] = '\0'; + in_string++; + } + + /* Split at network device name, if present */ + netdev_string = strchr ( in_string, '%' ); + if ( netdev_string ) + *(netdev_string++) = '\0'; + + /* Parse IPv6 address portion */ + if ( ( rc = inet6_aton ( in_string, &in ) ) != 0 ) + goto err_inet6_aton; + + /* Parse network device name, if present */ + if ( netdev_string ) { + netdev = find_netdev ( netdev_string ); + if ( ! netdev ) { + rc = -ENODEV; + goto err_find_netdev; + } + sin6->sin6_scope_id = netdev->index; + } + + /* Copy IPv6 address portion to socket address */ + memcpy ( &sin6->sin6_addr, &in, sizeof ( sin6->sin6_addr ) ); + + err_find_netdev: + err_inet6_aton: + free ( tmp ); + err_alloc: + return rc; +} + /** IPv6 protocol */ struct net_protocol ipv6_protocol __net_protocol = { .name = "IPv6", @@ -765,6 +855,13 @@ struct tcpip_net_protocol ipv6_tcpip_protocol __tcpip_net_protocol = { .tx = ipv6_tx, }; +/** IPv6 socket address converter */ +struct sockaddr_converter ipv6_sockaddr_converter __sockaddr_converter = { + .family = AF_INET6, + .ntoa = ipv6_sock_ntoa, + .aton = ipv6_sock_aton, +}; + /** * Create IPv6 network device *