Browse Source

[ipv6] Add inet6_aton()

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 11 years ago
parent
commit
a9fa0d5f2b
3 changed files with 141 additions and 5 deletions
  1. 2
    1
      src/include/ipxe/in.h
  2. 73
    4
      src/net/ipv6.c
  3. 66
    0
      src/tests/ipv6_test.c

+ 2
- 1
src/include/ipxe/in.h View File

@@ -120,6 +120,7 @@ struct sockaddr_in6 {
120 120
 
121 121
 extern int inet_aton ( const char *cp, struct in_addr *inp );
122 122
 extern char * inet_ntoa ( struct in_addr in );
123
-extern char * inet6_ntoa ( const struct in6_addr *in6 );
123
+extern int inet6_aton ( const char *string, struct in6_addr *in );
124
+extern char * inet6_ntoa ( const struct in6_addr *in );
124 125
 
125 126
 #endif	/* _IPXE_IN_H */

+ 73
- 4
src/net/ipv6.c View File

@@ -622,11 +622,80 @@ static int ipv6_rx ( struct io_buffer *iobuf, struct net_device *netdev,
622 622
 	return rc;
623 623
 }
624 624
 
625
+/**
626
+ * Parse IPv6 address
627
+ *
628
+ * @v string		IPv6 address string
629
+ * @ret in		IPv6 address to fill in
630
+ * @ret rc		Return status code
631
+ */
632
+int inet6_aton ( const char *string, struct in6_addr *in ) {
633
+	uint16_t *word = in->s6_addr16;
634
+	uint16_t *end = ( word + ( sizeof ( in->s6_addr16 ) /
635
+				   sizeof ( in->s6_addr16[0] ) ) );
636
+	uint16_t *pad = NULL;
637
+	const char *nptr = string;
638
+	char *endptr;
639
+	unsigned long value;
640
+	size_t pad_len;
641
+	size_t move_len;
642
+
643
+	/* Parse string */
644
+	while ( 1 ) {
645
+
646
+		/* Parse current word */
647
+		value = strtoul ( nptr, &endptr, 16 );
648
+		if ( value > 0xffff ) {
649
+			DBG ( "IPv6 invalid word value %#lx in \"%s\"\n",
650
+			      value, string );
651
+			return -EINVAL;
652
+		}
653
+		*(word++) = htons ( value );
654
+
655
+		/* Parse separator */
656
+		if ( ! *endptr )
657
+			break;
658
+		if ( *endptr != ':' ) {
659
+			DBG ( "IPv6 invalid separator '%c' in \"%s\"\n",
660
+			      *endptr, string );
661
+			return -EINVAL;
662
+		}
663
+		if ( ( endptr == nptr ) && ( nptr != string ) ) {
664
+			if ( pad ) {
665
+				DBG ( "IPv6 invalid multiple \"::\" in "
666
+				      "\"%s\"\n", string );
667
+				return -EINVAL;
668
+			}
669
+			pad = word;
670
+		}
671
+		nptr = ( endptr + 1 );
672
+
673
+		/* Check for overrun */
674
+		if ( word == end ) {
675
+			DBG ( "IPv6 too many words in \"%s\"\n", string );
676
+			return -EINVAL;
677
+		}
678
+	}
679
+
680
+	/* Insert padding if specified */
681
+	if ( pad ) {
682
+		move_len = ( ( ( void * ) word ) - ( ( void * ) pad ) );
683
+		pad_len = ( ( ( void * ) end ) - ( ( void * ) word ) );
684
+		memmove ( ( ( ( void * ) pad ) + pad_len ), pad, move_len );
685
+		memset ( pad, 0, pad_len );
686
+	} else if ( word != end ) {
687
+		DBG ( "IPv6 underlength address \"%s\"\n", string );
688
+		return -EINVAL;
689
+	}
690
+
691
+	return 0;
692
+}
693
+
625 694
 /**
626 695
  * Convert IPv6 address to standard notation
627 696
  *
628
- * @v in	IPv6 address
629
- * @ret string	IPv6 address in standard notation
697
+ * @v in		IPv6 address
698
+ * @ret string		IPv6 address string in canonical format
630 699
  *
631 700
  * RFC5952 defines the canonical format for IPv6 textual representation.
632 701
  */
@@ -672,8 +741,8 @@ char * inet6_ntoa ( const struct in6_addr *in ) {
672 741
 /**
673 742
  * Transcribe IPv6 address
674 743
  *
675
- * @v net_addr	IPv6 address
676
- * @ret string	IPv6 address in standard notation
744
+ * @v net_addr		IPv6 address
745
+ * @ret string		IPv6 address in standard notation
677 746
  *
678 747
  */
679 748
 static const char * ipv6_ntoa ( const void *net_addr ) {

+ 66
- 0
src/tests/ipv6_test.c View File

@@ -60,6 +60,37 @@ FILE_LICENCE ( GPL2_OR_LATER );
60 60
 	ok ( strcmp ( actual, expected ) == 0 );			\
61 61
 	} while ( 0 )
62 62
 
63
+/**
64
+ * Report an inet6_aton() test result
65
+ *
66
+ * @v text		Textual representation
67
+ * @v addr		Expected IPv6 address
68
+ */
69
+#define inet6_aton_ok( text, addr ) do {				\
70
+	static const char string[] = text;				\
71
+	static const struct in6_addr expected = {			\
72
+		.s6_addr = addr,					\
73
+	};								\
74
+	struct in6_addr actual;						\
75
+									\
76
+	ok ( inet6_aton ( string, &actual ) == 0 );			\
77
+	DBG ( "inet6_aton ( \"%s\" ) = %s\n", string,			\
78
+	      inet6_ntoa ( &actual ) );					\
79
+	ok ( memcmp ( &actual, &expected, sizeof ( actual ) ) == 0 );	\
80
+	} while ( 0 )
81
+
82
+/**
83
+ * Report an inet6_aton() failure test result
84
+ *
85
+ * @v text		Textual representation
86
+ */
87
+#define inet6_aton_fail_ok( text ) do {					\
88
+	static const char string[] = text;				\
89
+	struct in6_addr dummy;						\
90
+									\
91
+	ok ( inet6_aton ( string, &dummy ) != 0 );			\
92
+	} while ( 0 )
93
+
63 94
 /**
64 95
  * Perform IPv6 self-tests
65 96
  *
@@ -106,6 +137,41 @@ static void ipv6_test_exec ( void ) {
106 137
 	inet6_ntoa_ok ( IPV6 ( 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
107 138
 			       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ),
108 139
 			"ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" );
140
+
141
+	/* inet6_aton() tests */
142
+	inet6_aton_ok ( "2001:ba8:0:1d4::6950:5845",
143
+			IPV6 ( 0x20, 0x01, 0x0b, 0xa8, 0x00, 0x00, 0x01, 0xd4,
144
+			       0x00, 0x00, 0x00, 0x00, 0x69, 0x50, 0x58, 0x45));
145
+	/* No zeros */
146
+	inet6_aton_ok ( "2001:db8:1:1:1:1:1:1",
147
+			IPV6 ( 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x01, 0x00, 0x01,
148
+			       0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01));
149
+	/* All intervening zeros */
150
+	inet6_aton_ok ( "fe80::1",
151
+			IPV6 ( 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
152
+			       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01));
153
+	/* Trailing run of zeros */
154
+	inet6_aton_ok ( "fe80::",
155
+			IPV6 ( 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
156
+			       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00));
157
+	/* Leading run of zeros */
158
+	inet6_aton_ok ( "::1",
159
+			IPV6 ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
160
+			       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01));
161
+	/* All zeros */
162
+	inet6_aton_ok ( "::",
163
+			IPV6 ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
164
+			       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00));
165
+
166
+	/* inet6_aton() failure tests */
167
+	inet6_aton_fail_ok ( "20012:ba8:0:1d4::6950:5845" );
168
+	inet6_aton_fail_ok ( "200z:ba8:0:1d4::6950:5845" );
169
+	inet6_aton_fail_ok ( "2001.ba8:0:1d4::6950:5845" );
170
+	inet6_aton_fail_ok ( "2001:db8:1:1:1:1:1" );
171
+	inet6_aton_fail_ok ( "2001:db8:1:1:1:1:1:1:2" );
172
+	inet6_aton_fail_ok ( "2001:db8::1::2" );
173
+	inet6_aton_fail_ok ( "2001:ba8:0:1d4:::6950:5845" );
174
+	inet6_aton_fail_ok ( ":::" );
109 175
 }
110 176
 
111 177
 /** IPv6 self-test */

Loading…
Cancel
Save