Просмотр исходного кода

Merge commit 'laptop/master'

tags/v0.9.3
Michael Brown 16 лет назад
Родитель
Сommit
105ebec4f3
2 измененных файлов: 297 добавлений и 112 удалений
  1. 2
    0
      src/include/gpxe/tftp.h
  2. 295
    112
      src/net/udp/tftp.c

+ 2
- 0
src/include/gpxe/tftp.h Просмотреть файл

@@ -29,6 +29,8 @@
29 29
 #define TFTP_ERR_UNKNOWN_USER	7 /**< No such user */
30 30
 #define TFTP_ERR_BAD_OPTS	8 /**< Option negotiation failed */
31 31
 
32
+#define MTFTP_PORT	     1759 /**< Default MTFTP server port */
33
+
32 34
 /** A TFTP read request (RRQ) packet */
33 35
 struct tftp_rrq {
34 36
 	uint16_t opcode;

+ 295
- 112
src/net/udp/tftp.c Просмотреть файл

@@ -74,24 +74,23 @@ struct tftp_request {
74 74
 	 * "tsize" option, this value will be zero.
75 75
 	 */
76 76
 	unsigned long tsize;
77
-	/** Multicast address
78
-	 *
79
-	 * This is the destination address for multicast data
80
-	 * transmissions.
81
-	 */
82
-	struct sockaddr_tcpip multicast;
83
-	/** Master client
77
+	
78
+	/** Server port
84 79
 	 *
85
-	 * True if this is the client responsible for sending ACKs.
80
+	 * This is the port to which RRQ packets are sent.
86 81
 	 */
87
-	int master;
88
-	
82
+	unsigned int port;
89 83
 	/** Peer address
90 84
 	 *
91 85
 	 * The peer address is determined by the first response
92 86
 	 * received to the TFTP RRQ.
93 87
 	 */
94 88
 	struct sockaddr_tcpip peer;
89
+	/** Request flags */
90
+	unsigned int flags;
91
+	/** MTFTP timeout count */
92
+	unsigned int mtftp_timeouts;
93
+
95 94
 	/** Block bitmap */
96 95
 	struct bitmap bitmap;
97 96
 	/** Maximum known length
@@ -110,6 +109,21 @@ struct tftp_request {
110 109
 	struct retry_timer timer;
111 110
 };
112 111
 
112
+/** TFTP request flags */
113
+enum {
114
+	/** Send ACK packets */
115
+	TFTP_FL_SEND_ACK = 0x0001,
116
+	/** Request blksize and tsize options */
117
+	TFTP_FL_RRQ_SIZES = 0x0002,
118
+	/** Request multicast option */
119
+	TFTP_FL_RRQ_MULTICAST = 0x0004,
120
+	/** Perform MTFTP recovery on timeout */
121
+	TFTP_FL_MTFTP_RECOVERY = 0x0008,
122
+};
123
+
124
+/** Maximum number of MTFTP open requests before falling back to TFTP */
125
+#define MTFTP_MAX_TIMEOUTS 3
126
+
113 127
 /**
114 128
  * Free TFTP request
115 129
  *
@@ -147,6 +161,67 @@ static void tftp_done ( struct tftp_request *tftp, int rc ) {
147 161
 	xfer_close ( &tftp->xfer, rc );
148 162
 }
149 163
 
164
+/**
165
+ * Reopen TFTP socket
166
+ *
167
+ * @v tftp		TFTP connection
168
+ * @ret rc		Return status code
169
+ */
170
+static int tftp_reopen ( struct tftp_request *tftp ) {
171
+	struct sockaddr_tcpip server;
172
+	int rc;
173
+
174
+	/* Close socket */
175
+	xfer_close ( &tftp->socket, 0 );
176
+
177
+	/* Disable ACK sending. */
178
+	tftp->flags &= ~TFTP_FL_SEND_ACK;
179
+
180
+	/* Reset peer address */
181
+	memset ( &tftp->peer, 0, sizeof ( tftp->peer ) );
182
+
183
+	/* Open socket */
184
+	memset ( &server, 0, sizeof ( server ) );
185
+	server.st_port = htons ( tftp->port );
186
+	if ( ( rc = xfer_open_named_socket ( &tftp->socket, SOCK_DGRAM,
187
+					     ( struct sockaddr * ) &server,
188
+					     tftp->uri->host, NULL ) ) != 0 ) {
189
+		DBGC ( tftp, "TFTP %p could not open socket: %s\n",
190
+		       tftp, strerror ( rc ) );
191
+		return rc;
192
+	}
193
+
194
+	return 0;
195
+}
196
+
197
+/**
198
+ * Reopen TFTP multicast socket
199
+ *
200
+ * @v tftp		TFTP connection
201
+ * @v local		Local socket address
202
+ * @ret rc		Return status code
203
+ */
204
+static int tftp_reopen_mc ( struct tftp_request *tftp,
205
+			    struct sockaddr *local ) {
206
+	int rc;
207
+
208
+	/* Close multicast socket */
209
+	xfer_close ( &tftp->mc_socket, 0 );
210
+
211
+	/* Open multicast socket.  We never send via this socket, so
212
+	 * use the local address as the peer address (since the peer
213
+	 * address cannot be NULL).
214
+	 */
215
+	if ( ( rc = xfer_open_socket ( &tftp->mc_socket, SOCK_DGRAM,
216
+				       local, local ) ) != 0 ) {
217
+		DBGC ( tftp, "TFTP %p could not open multicast "
218
+		       "socket: %s\n", tftp, strerror ( rc ) );
219
+		return rc;
220
+	}
221
+
222
+	return 0;
223
+}
224
+
150 225
 /**
151 226
  * Presize TFTP receive buffers and block bitmap
152 227
  *
@@ -201,6 +276,35 @@ void tftp_set_request_blksize ( unsigned int blksize ) {
201 276
 	tftp_request_blksize = blksize;
202 277
 }
203 278
 
279
+/**
280
+ * MTFTP multicast receive address
281
+ *
282
+ * This is treated as a global configuration parameter.
283
+ */
284
+static struct sockaddr_in tftp_mtftp_socket = {
285
+	.sin_family = AF_INET,
286
+	.sin_addr.s_addr = htonl ( 0xefff0101 ),
287
+	.sin_port = htons ( 3001 ),
288
+};
289
+
290
+/**
291
+ * Set MTFTP multicast address
292
+ *
293
+ * @v address		Multicast IPv4 address
294
+ */
295
+void tftp_set_mtftp_address ( struct in_addr address ) {
296
+	tftp_mtftp_socket.sin_addr = address;
297
+}
298
+
299
+/**
300
+ * Set MTFTP multicast port
301
+ *
302
+ * @v port		Multicast port
303
+ */
304
+void tftp_set_mtftp_port ( unsigned int port ) {
305
+	tftp_mtftp_socket.sin_port = htons ( port );
306
+}
307
+
204 308
 /**
205 309
  * Transmit RRQ
206 310
  *
@@ -227,11 +331,19 @@ static int tftp_send_rrq ( struct tftp_request *tftp ) {
227 331
 	/* Build request */
228 332
 	rrq = iob_put ( iobuf, sizeof ( *rrq ) );
229 333
 	rrq->opcode = htons ( TFTP_RRQ );
230
-	iob_put ( iobuf,
231
-		  snprintf ( rrq->data, iob_tailroom ( iobuf ),
232
-			     "%s%coctet%cblksize%c%d%ctsize%c0%cmulticast%c",
233
-			     path, 0, 0, 0, tftp_request_blksize, 0,
234
-			     0, 0, 0 ) + 1 );
334
+	iob_put ( iobuf, snprintf ( iobuf->tail, iob_tailroom ( iobuf ),
335
+				    "%s%coctet", path, 0 ) + 1 );
336
+	if ( tftp->flags & TFTP_FL_RRQ_SIZES ) {
337
+		iob_put ( iobuf, snprintf ( iobuf->tail,
338
+					    iob_tailroom ( iobuf ),
339
+					    "blksize%c%d%ctsize%c0", 0,
340
+					    tftp_request_blksize, 0, 0 ) + 1 );
341
+	}
342
+	if ( tftp->flags & TFTP_FL_RRQ_MULTICAST ) {
343
+		iob_put ( iobuf, snprintf ( iobuf->tail,
344
+					    iob_tailroom ( iobuf ),
345
+					    "multicast%c", 0 ) + 1 );
346
+	}
235 347
 
236 348
 	/* RRQ always goes to the address specified in the initial
237 349
 	 * xfer_open() call
@@ -283,16 +395,15 @@ static int tftp_send_packet ( struct tftp_request *tftp ) {
283 395
 	stop_timer ( &tftp->timer );
284 396
 	start_timer ( &tftp->timer );
285 397
 
286
-	/* If we are the master client, send RRQ or ACK as appropriate */
287
-	if ( tftp->master ) {
288
-		if ( ! tftp->peer.st_family ) {
289
-			return tftp_send_rrq ( tftp );
290
-		} else {
398
+	/* Send RRQ or ACK as appropriate */
399
+	if ( ! tftp->peer.st_family ) {
400
+		return tftp_send_rrq ( tftp );
401
+	} else {
402
+		if ( tftp->flags & TFTP_FL_SEND_ACK ) {
291 403
 			return tftp_send_ack ( tftp );
404
+		} else {
405
+			return 0;
292 406
 		}
293
-	} else {
294
-		/* Do nothing when not the master client */
295
-		return 0;
296 407
 	}
297 408
 }
298 409
 
@@ -305,12 +416,61 @@ static int tftp_send_packet ( struct tftp_request *tftp ) {
305 416
 static void tftp_timer_expired ( struct retry_timer *timer, int fail ) {
306 417
 	struct tftp_request *tftp =
307 418
 		container_of ( timer, struct tftp_request, timer );
419
+	int rc;
308 420
 
309
-	if ( fail ) {
310
-		tftp_done ( tftp, -ETIMEDOUT );
421
+	/* If we are doing MTFTP, attempt the various recovery strategies */
422
+	if ( tftp->flags & TFTP_FL_MTFTP_RECOVERY ) {
423
+		if ( tftp->peer.st_family ) {
424
+			/* If we have received any response from the server,
425
+			 * try resending the RRQ to restart the download.
426
+			 */
427
+			DBGC ( tftp, "TFTP %p attempting reopen\n", tftp );
428
+			if ( ( rc = tftp_reopen ( tftp ) ) != 0 )
429
+				goto err;
430
+		} else {
431
+			/* Fall back to plain TFTP after several attempts */
432
+			tftp->mtftp_timeouts++;
433
+			DBGC ( tftp, "TFTP %p timeout %d waiting for MTFTP "
434
+			       "open\n", tftp, tftp->mtftp_timeouts );
435
+
436
+			if ( tftp->mtftp_timeouts > MTFTP_MAX_TIMEOUTS ) {
437
+				DBGC ( tftp, "TFTP %p falling back to plain "
438
+				       "TFTP\n", tftp );
439
+				tftp->flags = TFTP_FL_RRQ_SIZES;
440
+
441
+				/* Close multicast socket */
442
+				xfer_close ( &tftp->mc_socket, 0 );
443
+
444
+				/* Reset retry timer */
445
+				start_timer_nodelay ( &tftp->timer );
446
+
447
+				/* The blocksize may change: discard
448
+				 * the block bitmap
449
+				 */
450
+				bitmap_free ( &tftp->bitmap );
451
+				memset ( &tftp->bitmap, 0,
452
+					 sizeof ( tftp->bitmap ) );
453
+
454
+				/* Reopen on standard TFTP port */
455
+				tftp->port = TFTP_PORT;
456
+				if ( ( rc = tftp_reopen ( tftp ) ) != 0 )
457
+					goto err;
458
+			}
459
+		}
311 460
 	} else {
312
-		tftp_send_packet ( tftp );
461
+		/* Not doing MTFTP (or have fallen back to plain
462
+		 * TFTP); fail as per normal.
463
+		 */
464
+		if ( fail ) {
465
+			rc = -ETIMEDOUT;
466
+			goto err;
467
+		}
313 468
 	}
469
+	tftp_send_packet ( tftp );
470
+	return;
471
+
472
+ err:
473
+	tftp_done ( tftp, rc );
314 474
 }
315 475
 
316 476
 /**
@@ -366,15 +526,16 @@ static int tftp_process_tsize ( struct tftp_request *tftp,
366 526
  */
367 527
 static int tftp_process_multicast ( struct tftp_request *tftp,
368 528
 				    const char *value ) {
369
-	struct sockaddr_in *sin = ( struct sockaddr_in * ) &tftp->multicast;
529
+	union {
530
+		struct sockaddr sa;
531
+		struct sockaddr_in sin;
532
+	} socket;
370 533
 	char buf[ strlen ( value ) + 1 ];
371 534
 	char *addr;
372 535
 	char *port;
373 536
 	char *port_end;
374 537
 	char *mc;
375 538
 	char *mc_end;
376
-	struct sockaddr *mc_peer;
377
-	struct sockaddr *mc_local;
378 539
 	int rc;
379 540
 
380 541
 	/* Split value into "addr,port,mc" fields */
@@ -394,45 +555,33 @@ static int tftp_process_multicast ( struct tftp_request *tftp,
394 555
 	*(mc++) = '\0';
395 556
 
396 557
 	/* Parse parameters */
397
-	if ( *addr ) {
398
-		if ( inet_aton ( addr, &sin->sin_addr ) == 0 ) {
558
+	if ( strtoul ( mc, &mc_end, 0 ) == 0 )
559
+		tftp->flags &= ~TFTP_FL_SEND_ACK;
560
+	if ( *mc_end ) {
561
+		DBGC ( tftp, "TFTP %p multicast invalid mc %s\n", tftp, mc );
562
+		return -EINVAL;
563
+	}
564
+	DBGC ( tftp, "TFTP %p is%s the master client\n",
565
+	       tftp, ( ( tftp->flags & TFTP_FL_SEND_ACK ) ? "" : " not" ) );
566
+	if ( *addr && *port ) {
567
+		socket.sin.sin_family = AF_INET;
568
+		if ( inet_aton ( addr, &socket.sin.sin_addr ) == 0 ) {
399 569
 			DBGC ( tftp, "TFTP %p multicast invalid IP address "
400 570
 			       "%s\n", tftp, addr );
401 571
 			return -EINVAL;
402 572
 		}
403 573
 		DBGC ( tftp, "TFTP %p multicast IP address %s\n",
404
-		       tftp, inet_ntoa ( sin->sin_addr ) );
405
-	}
406
-	if ( *port ) {
407
-		sin->sin_port = htons ( strtoul ( port, &port_end, 0 ) );
574
+		       tftp, inet_ntoa ( socket.sin.sin_addr ) );
575
+		socket.sin.sin_port = htons ( strtoul ( port, &port_end, 0 ) );
408 576
 		if ( *port_end ) {
409 577
 			DBGC ( tftp, "TFTP %p multicast invalid port %s\n",
410 578
 			       tftp, port );
411 579
 			return -EINVAL;
412 580
 		}
413 581
 		DBGC ( tftp, "TFTP %p multicast port %d\n",
414
-		       tftp, ntohs ( sin->sin_port ) );
415
-	}
416
-	tftp->master = strtoul ( mc, &mc_end, 0 );
417
-	if ( *mc_end ) {
418
-		DBGC ( tftp, "TFTP %p multicast invalid mc %s\n", tftp, mc );
419
-		return -EINVAL;
420
-	}
421
-	DBGC ( tftp, "TFTP %p is%s the master client\n",
422
-	       tftp, ( tftp->master ? "" : " not" ) );
423
-
424
-	/* Open multicast socket, if new address specified */
425
-	if ( *addr || *port ) {
426
-		xfer_close ( &tftp->mc_socket, 0 );
427
-		mc_peer = ( ( struct sockaddr * ) &tftp->peer );
428
-		mc_local = ( ( struct sockaddr * ) &tftp->multicast );
429
-		mc_local->sa_family = mc_peer->sa_family;
430
-		if ( ( rc = xfer_open_socket ( &tftp->mc_socket, SOCK_DGRAM,
431
-					       mc_peer, mc_local ) ) != 0 ) {
432
-			DBGC ( tftp, "TFTP %p could not open multicast "
433
-			       "socket: %s\n", tftp, strerror ( rc ) );
582
+		       tftp, ntohs ( socket.sin.sin_port ) );
583
+		if ( ( rc = tftp_reopen_mc ( tftp, &socket.sa ) ) != 0 )
434 584
 			return rc;
435
-		}
436 585
 	}
437 586
 
438 587
 	return 0;
@@ -614,10 +763,10 @@ static int tftp_rx_data ( struct tftp_request *tftp,
614 763
 }
615 764
 
616 765
 /** Translation between TFTP errors and internal error numbers */
617
-static const uint8_t tftp_errors[] = {
618
-	[TFTP_ERR_FILE_NOT_FOUND]	= PXENV_STATUS_TFTP_FILE_NOT_FOUND,
619
-	[TFTP_ERR_ACCESS_DENIED]	= PXENV_STATUS_TFTP_ACCESS_VIOLATION,
620
-	[TFTP_ERR_ILLEGAL_OP]		= PXENV_STATUS_TFTP_UNKNOWN_OPCODE,
766
+static const int tftp_errors[] = {
767
+	[TFTP_ERR_FILE_NOT_FOUND]	= ENOENT,
768
+	[TFTP_ERR_ACCESS_DENIED]	= EACCES,
769
+	[TFTP_ERR_ILLEGAL_OP]		= ENOTSUP,
621 770
 };
622 771
 
623 772
 /**
@@ -648,7 +797,7 @@ static int tftp_rx_error ( struct tftp_request *tftp, void *buf, size_t len ) {
648 797
 	if ( err < ( sizeof ( tftp_errors ) / sizeof ( tftp_errors[0] ) ) )
649 798
 		rc = -tftp_errors[err];
650 799
 	if ( ! rc )
651
-		rc = -PXENV_STATUS_TFTP_CANNOT_OPEN_CONNECTION;
800
+		rc = -ENOTSUP;
652 801
 
653 802
 	/* Close TFTP request */
654 803
 	tftp_done ( tftp, rc );
@@ -739,32 +888,29 @@ static int tftp_socket_deliver_iob ( struct xfer_interface *socket,
739 888
 	struct tftp_request *tftp =
740 889
 		container_of ( socket, struct tftp_request, socket );
741 890
 
742
-	return tftp_rx ( tftp, iobuf, meta );
743
-}
744
-
745
-/**
746
- * TFTP connection closed by network stack
747
- *
748
- * @v socket		Transport layer interface
749
- * @v rc		Reason for close
750
- */
751
-static void tftp_socket_close ( struct xfer_interface *socket, int rc ) {
752
-	struct tftp_request *tftp =
753
-		container_of ( socket, struct tftp_request, socket );
754
-
755
-	DBGC ( tftp, "TFTP %p socket closed: %s\n",
756
-	       tftp, strerror ( rc ) );
757
-
758
-	/* Any close counts as an error */
759
-	if ( ! rc )
760
-		rc = -ECONNRESET;
891
+	/* Enable sending ACKs when we receive a unicast packet.  This
892
+	 * covers three cases:
893
+	 *
894
+	 * 1. Standard TFTP; we should always send ACKs, and will
895
+	 *    always receive a unicast packet before we need to send the
896
+	 *    first ACK.
897
+	 *
898
+	 * 2. RFC2090 multicast TFTP; the only unicast packets we will
899
+         *    receive are the OACKs; enable sending ACKs here (before
900
+         *    processing the OACK) and disable it when processing the
901
+         *    multicast option if we are not the master client.
902
+	 *
903
+	 * 3. MTFTP; receiving a unicast datagram indicates that we
904
+	 *    are the "master client" and should send ACKs.
905
+	 */
906
+	tftp->flags |= TFTP_FL_SEND_ACK;
761 907
 
762
-	tftp_done ( tftp, rc );
908
+	return tftp_rx ( tftp, iobuf, meta );
763 909
 }
764 910
 
765 911
 /** TFTP socket operations */
766 912
 static struct xfer_interface_operations tftp_socket_operations = {
767
-	.close		= tftp_socket_close,
913
+	.close		= ignore_xfer_close,
768 914
 	.vredirect	= xfer_vopen,
769 915
 	.window		= unlimited_xfer_window,
770 916
 	.alloc_iob	= default_xfer_alloc_iob,
@@ -789,29 +935,9 @@ static int tftp_mc_socket_deliver_iob ( struct xfer_interface *mc_socket,
789 935
 	return tftp_rx ( tftp, iobuf, meta );
790 936
 }
791 937
 
792
-/**
793
- * TFTP multicast connection closed by network stack
794
- *
795
- * @v socket		Multicast transport layer interface
796
- * @v rc		Reason for close
797
- */
798
-static void tftp_mc_socket_close ( struct xfer_interface *mc_socket,
799
-				   int rc ) {
800
-	struct tftp_request *tftp =
801
-		container_of ( mc_socket, struct tftp_request, mc_socket );
802
-
803
-	DBGC ( tftp, "TFTP %p multicast socket closed: %s\n",
804
-	       tftp, strerror ( rc ) );
805
-
806
-	/* The multicast socket may be closed when we receive a new
807
-	 * OACK and open/reopen the socket; we should not call
808
-	 * tftp_done() at this point.
809
-	 */
810
-}
811
- 
812 938
 /** TFTP multicast socket operations */
813 939
 static struct xfer_interface_operations tftp_mc_socket_operations = {
814
-	.close		= tftp_mc_socket_close,
940
+	.close		= ignore_xfer_close,
815 941
 	.vredirect	= xfer_vopen,
816 942
 	.window		= unlimited_xfer_window,
817 943
 	.alloc_iob	= default_xfer_alloc_iob,
@@ -846,15 +972,17 @@ static struct xfer_interface_operations tftp_xfer_operations = {
846 972
 };
847 973
 
848 974
 /**
849
- * Initiate TFTP download
975
+ * Initiate TFTP/TFTM/MTFTP download
850 976
  *
851 977
  * @v xfer		Data transfer interface
852 978
  * @v uri		Uniform Resource Identifier
853 979
  * @ret rc		Return status code
854 980
  */
855
-int tftp_open ( struct xfer_interface *xfer, struct uri *uri ) {
981
+static int tftp_core_open ( struct xfer_interface *xfer, struct uri *uri,
982
+			    unsigned int default_port,
983
+			    struct sockaddr *multicast,
984
+			    unsigned int flags ) {
856 985
 	struct tftp_request *tftp;
857
-	struct sockaddr_tcpip server;
858 986
 	int rc;
859 987
 
860 988
 	/* Sanity checks */
@@ -874,17 +1002,20 @@ int tftp_open ( struct xfer_interface *xfer, struct uri *uri ) {
874 1002
 	xfer_init ( &tftp->mc_socket, &tftp_mc_socket_operations,
875 1003
 		    &tftp->refcnt );
876 1004
 	tftp->blksize = TFTP_DEFAULT_BLKSIZE;
877
-	tftp->master = 1;
1005
+	tftp->flags = flags;
878 1006
 	tftp->timer.expired = tftp_timer_expired;
879 1007
 
880 1008
 	/* Open socket */
881
-	memset ( &server, 0, sizeof ( server ) );
882
-	server.st_port = htons ( uri_port ( tftp->uri, TFTP_PORT ) );
883
-	if ( ( rc = xfer_open_named_socket ( &tftp->socket, SOCK_DGRAM,
884
-					     ( struct sockaddr * ) &server,
885
-					     uri->host, NULL ) ) != 0 )
1009
+	tftp->port = uri_port ( tftp->uri, default_port );
1010
+	if ( ( rc = tftp_reopen ( tftp ) ) != 0 )
886 1011
 		goto err;
887 1012
 
1013
+	/* Open multicast socket */
1014
+	if ( multicast ) {
1015
+		if ( ( rc = tftp_reopen_mc ( tftp, multicast ) ) != 0 )
1016
+			goto err;
1017
+	}
1018
+
888 1019
 	/* Start timer to initiate RRQ */
889 1020
 	start_timer_nodelay ( &tftp->timer );
890 1021
 
@@ -901,8 +1032,60 @@ int tftp_open ( struct xfer_interface *xfer, struct uri *uri ) {
901 1032
 	return rc;
902 1033
 }
903 1034
 
1035
+/**
1036
+ * Initiate TFTP download
1037
+ *
1038
+ * @v xfer		Data transfer interface
1039
+ * @v uri		Uniform Resource Identifier
1040
+ * @ret rc		Return status code
1041
+ */
1042
+static int tftp_open ( struct xfer_interface *xfer, struct uri *uri ) {
1043
+	return tftp_core_open ( xfer, uri, TFTP_PORT, NULL,
1044
+				TFTP_FL_RRQ_SIZES );
1045
+
1046
+}
1047
+
904 1048
 /** TFTP URI opener */
905 1049
 struct uri_opener tftp_uri_opener __uri_opener = {
906 1050
 	.scheme	= "tftp",
907 1051
 	.open	= tftp_open,
908 1052
 };
1053
+
1054
+/**
1055
+ * Initiate TFTM download
1056
+ *
1057
+ * @v xfer		Data transfer interface
1058
+ * @v uri		Uniform Resource Identifier
1059
+ * @ret rc		Return status code
1060
+ */
1061
+static int tftm_open ( struct xfer_interface *xfer, struct uri *uri ) {
1062
+	return tftp_core_open ( xfer, uri, TFTP_PORT, NULL,
1063
+				( TFTP_FL_RRQ_SIZES |
1064
+				  TFTP_FL_RRQ_MULTICAST ) );
1065
+
1066
+}
1067
+
1068
+/** TFTM URI opener */
1069
+struct uri_opener tftm_uri_opener __uri_opener = {
1070
+	.scheme	= "tftm",
1071
+	.open	= tftm_open,
1072
+};
1073
+
1074
+/**
1075
+ * Initiate MTFTP download
1076
+ *
1077
+ * @v xfer		Data transfer interface
1078
+ * @v uri		Uniform Resource Identifier
1079
+ * @ret rc		Return status code
1080
+ */
1081
+static int mtftp_open ( struct xfer_interface *xfer, struct uri *uri ) {
1082
+	return tftp_core_open ( xfer, uri, MTFTP_PORT,
1083
+				( struct sockaddr * ) &tftp_mtftp_socket,
1084
+				TFTP_FL_MTFTP_RECOVERY );
1085
+}
1086
+
1087
+/** MTFTP URI opener */
1088
+struct uri_opener mtftp_uri_opener __uri_opener = {
1089
+	.scheme	= "mtftp",
1090
+	.open	= mtftp_open,
1091
+};

Загрузка…
Отмена
Сохранить