Browse Source

[uri] Generalise tftp_uri() to pxe_uri()

Merge the functionality of parse_next_server_and_filename() and
tftp_uri() into a single pxe_uri(), which takes a server address
(IPv4/IPv6/none) and a filename, and produces a URI using the rule:

 - if the filename is a hierarchical absolute URI (i.e. includes a
   scheme such as "http://" or "tftp://") then use that URI and ignore
   the server address,

 - otherwise, if the server address is recognised (according to
   sa_family) then construct a TFTP URI based on the server address,
   port, and filename

 - otherwise fail.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 8 years ago
parent
commit
53d2d9e3c3
5 changed files with 159 additions and 117 deletions
  1. 11
    13
      src/arch/i386/interface/pxe/pxe_tftp.c
  2. 37
    16
      src/core/uri.c
  3. 2
    2
      src/include/ipxe/uri.h
  4. 77
    29
      src/tests/uri_test.c
  5. 32
    57
      src/usr/autoboot.c

+ 11
- 13
src/arch/i386/interface/pxe/pxe_tftp.c View File

@@ -159,26 +159,21 @@ static struct pxe_tftp_connection pxe_tftp = {
159 159
 	.xfer = INTF_INIT ( pxe_tftp_xfer_desc ),
160 160
 };
161 161
 
162
-/**
163
- * Maximum length of a PXE TFTP URI
164
- *
165
- * The PXE TFTP API provides 128 characters for the filename; the
166
- * extra 128 bytes allow for the remainder of the URI.
167
- */
168
-#define PXE_TFTP_URI_LEN 256
169
-
170 162
 /**
171 163
  * Open PXE TFTP connection
172 164
  *
173 165
  * @v ipaddress		IP address
174
- * @v port		TFTP server port
166
+ * @v port		TFTP server port (in network byte order)
175 167
  * @v filename		File name
176 168
  * @v blksize		Requested block size
177 169
  * @ret rc		Return status code
178 170
  */
179 171
 static int pxe_tftp_open ( IP4_t ipaddress, UDP_PORT_t port,
180 172
 			   UINT8_t *filename, UINT16_t blksize ) {
181
-	struct in_addr address;
173
+	union {
174
+		struct sockaddr sa;
175
+		struct sockaddr_in sin;
176
+	} server;
182 177
 	struct uri *uri;
183 178
 	int rc;
184 179
 
@@ -191,12 +186,15 @@ static int pxe_tftp_open ( IP4_t ipaddress, UDP_PORT_t port,
191 186
 	pxe_tftp.rc = -EINPROGRESS;
192 187
 
193 188
 	/* Construct URI */
194
-	address.s_addr = ipaddress;
195
-	DBG ( " %s", inet_ntoa ( address ) );
189
+	memset ( &server, 0, sizeof ( server ) );
190
+	server.sin.sin_family = AF_INET;
191
+	server.sin.sin_addr.s_addr = ipaddress;
192
+	server.sin.sin_port = port;
193
+	DBG ( " %s", sock_ntoa ( &server.sa ) );
196 194
 	if ( port )
197 195
 		DBG ( ":%d", ntohs ( port ) );
198 196
 	DBG ( ":%s", filename );
199
-	uri = tftp_uri ( address, ntohs ( port ), ( ( char * ) filename ) );
197
+	uri = pxe_uri ( &server.sa, ( ( char * ) filename ) );
200 198
 	if ( ! uri ) {
201 199
 		DBG ( " could not create URI\n" );
202 200
 		return -ENOMEM;

+ 37
- 16
src/core/uri.c View File

@@ -36,6 +36,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
36 36
 #include <ctype.h>
37 37
 #include <ipxe/vsprintf.h>
38 38
 #include <ipxe/params.h>
39
+#include <ipxe/tcpip.h>
39 40
 #include <ipxe/uri.h>
40 41
 
41 42
 /**
@@ -711,30 +712,50 @@ struct uri * resolve_uri ( const struct uri *base_uri,
711 712
 }
712 713
 
713 714
 /**
714
- * Construct TFTP URI from next-server and filename
715
+ * Construct URI from server address and filename
715 716
  *
716
- * @v next_server	Next-server address
717
- * @v port		Port number, or zero to use the default port
717
+ * @v sa_server		Server address
718 718
  * @v filename		Filename
719 719
  * @ret uri		URI, or NULL on failure
720 720
  *
721
- * TFTP filenames specified via the DHCP next-server field often
721
+ * PXE TFTP filenames specified via the DHCP next-server field often
722 722
  * contain characters such as ':' or '#' which would confuse the
723 723
  * generic URI parser.  We provide a mechanism for directly
724 724
  * constructing a TFTP URI from the next-server and filename.
725 725
  */
726
-struct uri * tftp_uri ( struct in_addr next_server, unsigned int port,
727
-			const char *filename ) {
726
+struct uri * pxe_uri ( struct sockaddr *sa_server, const char *filename ) {
728 727
 	char buf[ 6 /* "65535" + NUL */ ];
729
-	struct uri uri;
730
-
731
-	memset ( &uri, 0, sizeof ( uri ) );
732
-	uri.scheme = "tftp";
733
-	uri.host = inet_ntoa ( next_server );
734
-	if ( port ) {
735
-		snprintf ( buf, sizeof ( buf ), "%d", port );
736
-		uri.port = buf;
728
+	struct sockaddr_tcpip *st_server =
729
+		( ( struct sockaddr_tcpip * ) sa_server );
730
+	struct uri tmp;
731
+	struct uri *uri;
732
+
733
+	/* Fail if filename is empty */
734
+	if ( ! ( filename && filename[0] ) )
735
+		return NULL;
736
+
737
+	/* If filename is a hierarchical absolute URI, then use that
738
+	 * URI.  (We accept only hierarchical absolute URIs, since PXE
739
+	 * filenames sometimes start with DOS drive letters such as
740
+	 * "C:\", which get misinterpreted as opaque absolute URIs.)
741
+	 */
742
+	uri = parse_uri ( filename );
743
+	if ( uri && uri_is_absolute ( uri ) && ( ! uri->opaque ) )
744
+		return uri;
745
+	uri_put ( uri );
746
+
747
+	/* Otherwise, construct a TFTP URI directly */
748
+	memset ( &tmp, 0, sizeof ( tmp ) );
749
+	tmp.scheme = "tftp";
750
+	tmp.host = sock_ntoa ( sa_server );
751
+	if ( ! tmp.host )
752
+		return NULL;
753
+	if ( st_server->st_port ) {
754
+		snprintf ( buf, sizeof ( buf ), "%d",
755
+			   ntohs ( st_server->st_port ) );
756
+		tmp.port = buf;
737 757
 	}
738
-	uri.path = filename;
739
-	return uri_dup ( &uri );
758
+	tmp.path = filename;
759
+	uri = uri_dup ( &tmp );
760
+	return uri;
740 761
 }

+ 2
- 2
src/include/ipxe/uri.h View File

@@ -206,8 +206,8 @@ extern char * resolve_path ( const char *base_path,
206 206
 			     const char *relative_path );
207 207
 extern struct uri * resolve_uri ( const struct uri *base_uri,
208 208
 				  struct uri *relative_uri );
209
-extern struct uri * tftp_uri ( struct in_addr next_server, unsigned int port,
210
-			       const char *filename );
209
+extern struct uri * pxe_uri ( struct sockaddr *sa_server,
210
+			      const char *filename );
211 211
 extern void churi ( struct uri *uri );
212 212
 
213 213
 #endif /* _IPXE_URI_H */

+ 77
- 29
src/tests/uri_test.c View File

@@ -35,6 +35,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
35 35
 #include <string.h>
36 36
 #include <byteswap.h>
37 37
 #include <ipxe/uri.h>
38
+#include <ipxe/tcpip.h>
38 39
 #include <ipxe/params.h>
39 40
 #include <ipxe/test.h>
40 41
 
@@ -66,12 +67,15 @@ struct uri_resolve_test {
66 67
 	const char *resolved;
67 68
 };
68 69
 
69
-/** A TFTP URI test */
70
-struct uri_tftp_test {
71
-	/** Next-server address */
72
-	struct in_addr next_server;
73
-	/** Port number */
74
-	unsigned int port;
70
+/** A PXE URI test */
71
+struct uri_pxe_test {
72
+	/** Server address */
73
+	union {
74
+		struct sockaddr sa;
75
+		struct sockaddr_in sin;
76
+		struct sockaddr_in6 sin6;
77
+		struct sockaddr_tcpip st;
78
+	} server;
75 79
 	/** Filename */
76 80
 	const char *filename;
77 81
 	/** URI */
@@ -323,20 +327,20 @@ static void uri_resolve_path_okx ( struct uri_resolve_test *test,
323 327
 	uri_resolve_path_okx ( test, __FILE__, __LINE__ )
324 328
 
325 329
 /**
326
- * Report URI TFTP test result
330
+ * Report URI PXE test result
327 331
  *
328
- * @v test		URI TFTP test
332
+ * @v test		URI PXE test
329 333
  * @v file		Test code file
330 334
  * @v line		Test code line
331 335
  */
332
-static void uri_tftp_okx ( struct uri_tftp_test *test, const char *file,
333
-			   unsigned int line ) {
336
+static void uri_pxe_okx ( struct uri_pxe_test *test, const char *file,
337
+			  unsigned int line ) {
334 338
 	char buf[ strlen ( test->string ) + 1 /* NUL */ ];
335 339
 	struct uri *uri;
336 340
 	size_t len;
337 341
 
338 342
 	/* Construct URI */
339
-	uri = tftp_uri ( test->next_server, test->port, test->filename );
343
+	uri = pxe_uri ( &test->server.sa, test->filename );
340 344
 	okx ( uri != NULL, file, line );
341 345
 	if ( uri ) {
342 346
 		uri_okx ( uri, &test->uri, file, line );
@@ -346,7 +350,7 @@ static void uri_tftp_okx ( struct uri_tftp_test *test, const char *file,
346 350
 	}
347 351
 	uri_put ( uri );
348 352
 }
349
-#define uri_tftp_ok( test ) uri_tftp_okx ( test, __FILE__, __LINE__ )
353
+#define uri_pxe_ok( test ) uri_pxe_okx ( test, __FILE__, __LINE__ )
350 354
 
351 355
 /**
352 356
  * Report current working URI test result
@@ -678,9 +682,33 @@ static struct uri_resolve_test uri_fragment = {
678 682
 	"http://192.168.0.254/test#bar",
679 683
 };
680 684
 
681
-/** TFTP URI with absolute path */
682
-static struct uri_tftp_test uri_tftp_absolute = {
683
-	{ .s_addr = htonl ( 0xc0a80002 ) /* 192.168.0.2 */ }, 0,
685
+/** PXE URI with absolute URI */
686
+static struct uri_pxe_test uri_pxe_absolute = {
687
+	{
688
+		/* 192.168.0.3 */
689
+		.sin = {
690
+			.sin_family = AF_INET,
691
+			.sin_addr = { .s_addr = htonl ( 0xc0a80003 ) },
692
+		},
693
+	},
694
+	"http://not.a.tftp/uri",
695
+	{
696
+		.scheme = "http",
697
+		.host = "not.a.tftp",
698
+		.path = "/uri",
699
+	},
700
+	"http://not.a.tftp/uri",
701
+};
702
+
703
+/** PXE URI with absolute path */
704
+static struct uri_pxe_test uri_pxe_absolute_path = {
705
+	{
706
+		/* 192.168.0.2 */
707
+		.sin = {
708
+			.sin_family = AF_INET,
709
+			.sin_addr = { .s_addr = htonl ( 0xc0a80002 ) },
710
+		},
711
+	},
684 712
 	"/absolute/path",
685 713
 	{
686 714
 		.scheme = "tftp",
@@ -690,9 +718,15 @@ static struct uri_tftp_test uri_tftp_absolute = {
690 718
 	"tftp://192.168.0.2/absolute/path",
691 719
 };
692 720
 
693
-/** TFTP URI with relative path */
694
-static struct uri_tftp_test uri_tftp_relative = {
695
-	{ .s_addr = htonl ( 0xc0a80003 ) /* 192.168.0.3 */ }, 0,
721
+/** PXE URI with relative path */
722
+static struct uri_pxe_test uri_pxe_relative_path = {
723
+	{
724
+		/* 192.168.0.3 */
725
+		.sin = {
726
+			.sin_family = AF_INET,
727
+			.sin_addr = { .s_addr = htonl ( 0xc0a80003 ) },
728
+		},
729
+	},
696 730
 	"relative/path",
697 731
 	{
698 732
 		.scheme = "tftp",
@@ -702,9 +736,15 @@ static struct uri_tftp_test uri_tftp_relative = {
702 736
 	"tftp://192.168.0.3/relative/path",
703 737
 };
704 738
 
705
-/** TFTP URI with path containing special characters */
706
-static struct uri_tftp_test uri_tftp_icky = {
707
-	{ .s_addr = htonl ( 0x0a000006 ) /* 10.0.0.6 */ }, 0,
739
+/** PXE URI with path containing special characters */
740
+static struct uri_pxe_test uri_pxe_icky = {
741
+	{
742
+		/* 10.0.0.6 */
743
+		.sin = {
744
+			.sin_family = AF_INET,
745
+			.sin_addr = { .s_addr = htonl ( 0x0a000006 ) },
746
+		},
747
+	},
708 748
 	"C:\\tftpboot\\icky#path",
709 749
 	{
710 750
 		.scheme = "tftp",
@@ -714,9 +754,16 @@ static struct uri_tftp_test uri_tftp_icky = {
714 754
 	"tftp://10.0.0.6/C%3A\\tftpboot\\icky%23path",
715 755
 };
716 756
 
717
-/** TFTP URI with custom port */
718
-static struct uri_tftp_test uri_tftp_port = {
719
-	{ .s_addr = htonl ( 0xc0a80001 ) /* 192.168.0.1 */ }, 4069,
757
+/** PXE URI with custom port */
758
+static struct uri_pxe_test uri_pxe_port = {
759
+	{
760
+		/* 192.168.0.1:4069 */
761
+		.sin = {
762
+			.sin_family = AF_INET,
763
+			.sin_addr = { .s_addr = htonl ( 0xc0a80001 ) },
764
+			.sin_port = htons ( 4069 ),
765
+		},
766
+	},
720 767
 	"/another/path",
721 768
 	{
722 769
 		.scheme = "tftp",
@@ -857,11 +904,12 @@ static void uri_test_exec ( void ) {
857 904
 	uri_resolve_ok ( &uri_query );
858 905
 	uri_resolve_ok ( &uri_fragment );
859 906
 
860
-	/* TFTP URI construction tests */
861
-	uri_tftp_ok ( &uri_tftp_absolute );
862
-	uri_tftp_ok ( &uri_tftp_relative );
863
-	uri_tftp_ok ( &uri_tftp_icky );
864
-	uri_tftp_ok ( &uri_tftp_port );
907
+	/* PXE URI construction tests */
908
+	uri_pxe_ok ( &uri_pxe_absolute );
909
+	uri_pxe_ok ( &uri_pxe_absolute_path );
910
+	uri_pxe_ok ( &uri_pxe_relative_path );
911
+	uri_pxe_ok ( &uri_pxe_icky );
912
+	uri_pxe_ok ( &uri_pxe_port );
865 913
 
866 914
 	/* Current working URI tests */
867 915
 	uri_churi_ok ( uri_churi );

+ 32
- 57
src/usr/autoboot.c View File

@@ -87,33 +87,6 @@ __weak int pxe_menu_boot ( struct net_device *netdev __unused ) {
87 87
 	return -ENOTSUP;
88 88
 }
89 89
 
90
-/**
91
- * Parse next-server and filename into a URI
92
- *
93
- * @v next_server	Next-server address
94
- * @v filename		Filename
95
- * @ret uri		URI, or NULL on failure
96
- */
97
-static struct uri * parse_next_server_and_filename ( struct in_addr next_server,
98
-						     const char *filename ) {
99
-	struct uri *uri;
100
-
101
-	/* Parse filename */
102
-	uri = parse_uri ( filename );
103
-	if ( ! uri )
104
-		return NULL;
105
-
106
-	/* Construct a TFTP URI for the filename, if applicable */
107
-	if ( next_server.s_addr && filename[0] && ! uri_is_absolute ( uri ) ) {
108
-		uri_put ( uri );
109
-		uri = tftp_uri ( next_server, 0, filename );
110
-		if ( ! uri )
111
-			return NULL;
112
-	}
113
-
114
-	return uri;
115
-}
116
-
117 90
 /** The "keep-san" setting */
118 91
 const struct setting keep_san_setting __setting ( SETTING_SANBOOT_EXTRA,
119 92
 						  keep-san ) = {
@@ -250,11 +223,17 @@ static void close_all_netdevs ( void ) {
250 223
  * @ret uri		URI, or NULL on failure
251 224
  */
252 225
 struct uri * fetch_next_server_and_filename ( struct settings *settings ) {
253
-	struct in_addr next_server = { 0 };
226
+	union {
227
+		struct sockaddr sa;
228
+		struct sockaddr_in sin;
229
+	} next_server;
254 230
 	char *raw_filename = NULL;
255 231
 	struct uri *uri = NULL;
256 232
 	char *filename;
257 233
 
234
+	/* Initialise server address */
235
+	memset ( &next_server, 0, sizeof ( next_server ) );
236
+
258 237
 	/* If we have a filename, fetch it along with the next-server
259 238
 	 * setting from the same settings block.
260 239
 	 */
@@ -263,20 +242,27 @@ struct uri * fetch_next_server_and_filename ( struct settings *settings ) {
263 242
 		fetch_string_setting_copy ( settings, &filename_setting,
264 243
 					    &raw_filename );
265 244
 		fetch_ipv4_setting ( settings, &next_server_setting,
266
-				     &next_server );
245
+				     &next_server.sin.sin_addr );
246
+	}
247
+	if ( ! raw_filename )
248
+		goto err_fetch;
249
+
250
+	/* Populate server address */
251
+	if ( next_server.sin.sin_addr.s_addr ) {
252
+		next_server.sin.sin_family = AF_INET;
253
+		printf ( "Next server: %s\n",
254
+			 inet_ntoa ( next_server.sin.sin_addr ) );
267 255
 	}
268 256
 
269 257
 	/* Expand filename setting */
270
-	filename = expand_settings ( raw_filename ? raw_filename : "" );
258
+	filename = expand_settings ( raw_filename );
271 259
 	if ( ! filename )
272 260
 		goto err_expand;
273
-
274
-	/* Parse next server and filename */
275
-	if ( next_server.s_addr )
276
-		printf ( "Next server: %s\n", inet_ntoa ( next_server ) );
277 261
 	if ( filename[0] )
278 262
 		printf ( "Filename: %s\n", filename );
279
-	uri = parse_next_server_and_filename ( next_server, filename );
263
+
264
+	/* Construct URI */
265
+	uri = pxe_uri ( &next_server.sa, filename );
280 266
 	if ( ! uri )
281 267
 		goto err_parse;
282 268
 
@@ -284,6 +270,7 @@ struct uri * fetch_next_server_and_filename ( struct settings *settings ) {
284 270
 	free ( filename );
285 271
  err_expand:
286 272
 	free ( raw_filename );
273
+ err_fetch:
287 274
 	return uri;
288 275
 }
289 276
 
@@ -301,9 +288,11 @@ static struct uri * fetch_root_path ( struct settings *settings ) {
301 288
 	/* Fetch root-path setting */
302 289
 	fetch_string_setting_copy ( settings, &root_path_setting,
303 290
 				    &raw_root_path );
291
+	if ( ! raw_root_path )
292
+		goto err_fetch;
304 293
 
305 294
 	/* Expand filename setting */
306
-	root_path = expand_settings ( raw_root_path ? raw_root_path : "" );
295
+	root_path = expand_settings ( raw_root_path );
307 296
 	if ( ! root_path )
308 297
 		goto err_expand;
309 298
 
@@ -318,6 +307,7 @@ static struct uri * fetch_root_path ( struct settings *settings ) {
318 307
 	free ( root_path );
319 308
  err_expand:
320 309
 	free ( raw_root_path );
310
+ err_fetch:
321 311
 	return uri;
322 312
 }
323 313
 
@@ -378,32 +368,19 @@ int netboot ( struct net_device *netdev ) {
378 368
 		goto err_pxe_menu_boot;
379 369
 	}
380 370
 
381
-	/* Fetch next server and filename */
371
+	/* Fetch next server and filename (if any) */
382 372
 	filename = fetch_next_server_and_filename ( NULL );
383
-	if ( ! filename )
384
-		goto err_filename;
385
-	if ( ! uri_has_path ( filename ) ) {
386
-		/* Ignore empty filename */
387
-		uri_put ( filename );
388
-		filename = NULL;
389
-	}
390 373
 
391
-	/* Fetch root path */
374
+	/* Fetch root path (if any) */
392 375
 	root_path = fetch_root_path ( NULL );
393
-	if ( ! root_path )
394
-		goto err_root_path;
395
-	if ( ! uri_is_absolute ( root_path ) ) {
396
-		/* Ignore empty root path */
397
-		uri_put ( root_path );
398
-		root_path = NULL;
399
-	}
400 376
 
401 377
 	/* If we have both a filename and a root path, ignore an
402
-	 * unsupported URI scheme in the root path, since it may
403
-	 * represent an NFS root.
378
+	 * unsupported or missing URI scheme in the root path, since
379
+	 * it may represent an NFS root.
404 380
 	 */
405 381
 	if ( filename && root_path &&
406
-	     ( xfer_uri_opener ( root_path->scheme ) == NULL ) ) {
382
+	     ( ! ( uri_is_absolute ( root_path ) ||
383
+		   ( xfer_uri_opener ( root_path->scheme ) == NULL ) ) ) ) {
407 384
 		printf ( "Ignoring unsupported root path\n" );
408 385
 		uri_put ( root_path );
409 386
 		root_path = NULL;
@@ -424,9 +401,7 @@ int netboot ( struct net_device *netdev ) {
424 401
  err_uriboot:
425 402
  err_no_boot:
426 403
 	uri_put ( root_path );
427
- err_root_path:
428 404
 	uri_put ( filename );
429
- err_filename:
430 405
  err_pxe_menu_boot:
431 406
  err_dhcp:
432 407
  err_ifopen:

Loading…
Cancel
Save