]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[ipv6] Add inet6_aton()
authorMichael Brown <mcb30@ipxe.org>
Wed, 11 Sep 2013 03:26:39 +0000 (04:26 +0100)
committerMichael Brown <mcb30@ipxe.org>
Wed, 11 Sep 2013 10:27:13 +0000 (11:27 +0100)
Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/include/ipxe/in.h
src/net/ipv6.c
src/tests/ipv6_test.c

index a1821b1fbe35192c1af0f9bd370870739cf0e502..a37784e2e488d331a455e2eecc5768c9da44ed46 100644 (file)
@@ -120,6 +120,7 @@ struct sockaddr_in6 {
 
 extern int inet_aton ( const char *cp, struct in_addr *inp );
 extern char * inet_ntoa ( struct in_addr in );
-extern char * inet6_ntoa ( const struct in6_addr *in6 );
+extern int inet6_aton ( const char *string, struct in6_addr *in );
+extern char * inet6_ntoa ( const struct in6_addr *in );
 
 #endif /* _IPXE_IN_H */
index 69feba193cd848df7583c22989a6c77ebfc76dd5..8dc251ba33315fb26cf4195a0bdbb25548ab912a 100644 (file)
@@ -622,11 +622,80 @@ static int ipv6_rx ( struct io_buffer *iobuf, struct net_device *netdev,
        return rc;
 }
 
+/**
+ * Parse IPv6 address
+ *
+ * @v string           IPv6 address string
+ * @ret in             IPv6 address to fill in
+ * @ret rc             Return status code
+ */
+int inet6_aton ( const char *string, struct in6_addr *in ) {
+       uint16_t *word = in->s6_addr16;
+       uint16_t *end = ( word + ( sizeof ( in->s6_addr16 ) /
+                                  sizeof ( in->s6_addr16[0] ) ) );
+       uint16_t *pad = NULL;
+       const char *nptr = string;
+       char *endptr;
+       unsigned long value;
+       size_t pad_len;
+       size_t move_len;
+
+       /* Parse string */
+       while ( 1 ) {
+
+               /* Parse current word */
+               value = strtoul ( nptr, &endptr, 16 );
+               if ( value > 0xffff ) {
+                       DBG ( "IPv6 invalid word value %#lx in \"%s\"\n",
+                             value, string );
+                       return -EINVAL;
+               }
+               *(word++) = htons ( value );
+
+               /* Parse separator */
+               if ( ! *endptr )
+                       break;
+               if ( *endptr != ':' ) {
+                       DBG ( "IPv6 invalid separator '%c' in \"%s\"\n",
+                             *endptr, string );
+                       return -EINVAL;
+               }
+               if ( ( endptr == nptr ) && ( nptr != string ) ) {
+                       if ( pad ) {
+                               DBG ( "IPv6 invalid multiple \"::\" in "
+                                     "\"%s\"\n", string );
+                               return -EINVAL;
+                       }
+                       pad = word;
+               }
+               nptr = ( endptr + 1 );
+
+               /* Check for overrun */
+               if ( word == end ) {
+                       DBG ( "IPv6 too many words in \"%s\"\n", string );
+                       return -EINVAL;
+               }
+       }
+
+       /* Insert padding if specified */
+       if ( pad ) {
+               move_len = ( ( ( void * ) word ) - ( ( void * ) pad ) );
+               pad_len = ( ( ( void * ) end ) - ( ( void * ) word ) );
+               memmove ( ( ( ( void * ) pad ) + pad_len ), pad, move_len );
+               memset ( pad, 0, pad_len );
+       } else if ( word != end ) {
+               DBG ( "IPv6 underlength address \"%s\"\n", string );
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 /**
  * Convert IPv6 address to standard notation
  *
- * @v in       IPv6 address
- * @ret string IPv6 address in standard notation
+ * @v in               IPv6 address
+ * @ret string         IPv6 address string in canonical format
  *
  * RFC5952 defines the canonical format for IPv6 textual representation.
  */
@@ -672,8 +741,8 @@ char * inet6_ntoa ( const struct in6_addr *in ) {
 /**
  * Transcribe IPv6 address
  *
- * @v net_addr IPv6 address
- * @ret string IPv6 address in standard notation
+ * @v net_addr         IPv6 address
+ * @ret string         IPv6 address in standard notation
  *
  */
 static const char * ipv6_ntoa ( const void *net_addr ) {
index 10e964d9f05c550915e10b5d05587e45810f236f..4de310ab00e2bced6113b7af19369c01d9b0f34d 100644 (file)
@@ -60,6 +60,37 @@ FILE_LICENCE ( GPL2_OR_LATER );
        ok ( strcmp ( actual, expected ) == 0 );                        \
        } while ( 0 )
 
+/**
+ * Report an inet6_aton() test result
+ *
+ * @v text             Textual representation
+ * @v addr             Expected IPv6 address
+ */
+#define inet6_aton_ok( text, addr ) do {                               \
+       static const char string[] = text;                              \
+       static const struct in6_addr expected = {                       \
+               .s6_addr = addr,                                        \
+       };                                                              \
+       struct in6_addr actual;                                         \
+                                                                       \
+       ok ( inet6_aton ( string, &actual ) == 0 );                     \
+       DBG ( "inet6_aton ( \"%s\" ) = %s\n", string,                   \
+             inet6_ntoa ( &actual ) );                                 \
+       ok ( memcmp ( &actual, &expected, sizeof ( actual ) ) == 0 );   \
+       } while ( 0 )
+
+/**
+ * Report an inet6_aton() failure test result
+ *
+ * @v text             Textual representation
+ */
+#define inet6_aton_fail_ok( text ) do {                                        \
+       static const char string[] = text;                              \
+       struct in6_addr dummy;                                          \
+                                                                       \
+       ok ( inet6_aton ( string, &dummy ) != 0 );                      \
+       } while ( 0 )
+
 /**
  * Perform IPv6 self-tests
  *
@@ -106,6 +137,41 @@ static void ipv6_test_exec ( void ) {
        inet6_ntoa_ok ( IPV6 ( 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
                               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ),
                        "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" );
+
+       /* inet6_aton() tests */
+       inet6_aton_ok ( "2001:ba8:0:1d4::6950:5845",
+                       IPV6 ( 0x20, 0x01, 0x0b, 0xa8, 0x00, 0x00, 0x01, 0xd4,
+                              0x00, 0x00, 0x00, 0x00, 0x69, 0x50, 0x58, 0x45));
+       /* No zeros */
+       inet6_aton_ok ( "2001:db8:1:1:1:1:1:1",
+                       IPV6 ( 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x01, 0x00, 0x01,
+                              0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01));
+       /* All intervening zeros */
+       inet6_aton_ok ( "fe80::1",
+                       IPV6 ( 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01));
+       /* Trailing run of zeros */
+       inet6_aton_ok ( "fe80::",
+                       IPV6 ( 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00));
+       /* Leading run of zeros */
+       inet6_aton_ok ( "::1",
+                       IPV6 ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01));
+       /* All zeros */
+       inet6_aton_ok ( "::",
+                       IPV6 ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00));
+
+       /* inet6_aton() failure tests */
+       inet6_aton_fail_ok ( "20012:ba8:0:1d4::6950:5845" );
+       inet6_aton_fail_ok ( "200z:ba8:0:1d4::6950:5845" );
+       inet6_aton_fail_ok ( "2001.ba8:0:1d4::6950:5845" );
+       inet6_aton_fail_ok ( "2001:db8:1:1:1:1:1" );
+       inet6_aton_fail_ok ( "2001:db8:1:1:1:1:1:1:2" );
+       inet6_aton_fail_ok ( "2001:db8::1::2" );
+       inet6_aton_fail_ok ( "2001:ba8:0:1d4:::6950:5845" );
+       inet6_aton_fail_ok ( ":::" );
 }
 
 /** IPv6 self-test */