summaryrefslogtreecommitdiffstats
path: root/src/net/ipv6.c
diff options
context:
space:
mode:
authorMichael Brown2013-10-21 15:06:07 +0200
committerMichael Brown2013-10-21 15:34:08 +0200
commit2c76c1a6d801a5290c25c2d7bb3632e4af2f61c6 (patch)
tree5c40fdc68b1a6d92741b18a2e64b9e124e1d8511 /src/net/ipv6.c
parent[ipv4] Add IPv4 socket address converter (diff)
downloadipxe-2c76c1a6d801a5290c25c2d7bb3632e4af2f61c6.tar.gz
ipxe-2c76c1a6d801a5290c25c2d7bb3632e4af2f61c6.tar.xz
ipxe-2c76c1a6d801a5290c25c2d7bb3632e4af2f61c6.zip
[ipv6] Add IPv6 socket address converter
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/net/ipv6.c')
-rw-r--r--src/net/ipv6.c99
1 files changed, 98 insertions, 1 deletions
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
*