Kaynağa Gözat

[tftp] Make TFTP size requests abort transfer with an error

pxenv_tftp_get_fsize is an API call that PXE clients can call to
obtain the size of a remote file. It is implemented by starting a TFTP
transfer with pxe_tftp_open, waiting for the response and then
stopping the transfer with pxe_tftp_close(). This leaves the session
hanging on the TFTP server and it will try to resend the packet
repeatedly (verified with tftpd-hpa) until it times out.

This patch adds a method "tftpsize" that will abort the transfer after
the first packet is received from the server. This will terminate the
session on the server and is the same behaviour as Intel's PXE ROM
exhibits.

Together with a qemu patch to handle the ERROR packet (submitted to
qemu's mailing list), this resolves a specific issue where booting
pxegrub with qemu's TFTP server would be slow or hang.

I've tested this against qemu's tftp server and against my normal boot
infrastructure (tftpd-hpa). Booting pxegrub and loading extra files
now produces a trace similar to Intel's PXE client and there are no
spurious retransmits from tftpd any more.

Signed-off-by: Thomas Horsten <thomas@horsten.com>
Signed-off-by: Milan Plzik <milan.plzik@gmail.com>
Signed-off-by: Stefan Hajnoczi <stefanha@gmail.com>
Signed-off-by: Marty Connor <mdc@etherboot.org>
tags/v1.0.0-rc1
Thomas Horsten 14 yıl önce
ebeveyn
işleme
c124f6360d
2 değiştirilmiş dosya ile 81 ekleme ve 5 silme
  1. 8
    5
      src/arch/i386/interface/pxe/pxe_tftp.c
  2. 73
    0
      src/net/udp/tftp.c

+ 8
- 5
src/arch/i386/interface/pxe/pxe_tftp.c Dosyayı Görüntüle

165
  * @ret rc		Return status code
165
  * @ret rc		Return status code
166
  */
166
  */
167
 static int pxe_tftp_open ( uint32_t ipaddress, unsigned int port,
167
 static int pxe_tftp_open ( uint32_t ipaddress, unsigned int port,
168
-			   const unsigned char *filename, size_t blksize ) {
168
+			   const unsigned char *filename, size_t blksize,
169
+			   int sizeonly ) {
169
 	char uri_string[PXE_TFTP_URI_LEN];
170
 	char uri_string[PXE_TFTP_URI_LEN];
170
 	struct in_addr address;
171
 	struct in_addr address;
171
 	int rc;
172
 	int rc;
185
 	if ( blksize < TFTP_DEFAULT_BLKSIZE )
186
 	if ( blksize < TFTP_DEFAULT_BLKSIZE )
186
 		blksize = TFTP_DEFAULT_BLKSIZE;
187
 		blksize = TFTP_DEFAULT_BLKSIZE;
187
 	snprintf ( uri_string, sizeof ( uri_string ),
188
 	snprintf ( uri_string, sizeof ( uri_string ),
188
-		   "tftp://%s:%d%s%s?blksize=%zd",
189
+		   "tftp%s://%s:%d%s%s?blksize=%zd",
190
+		   sizeonly ? "size" : "",
189
 		   inet_ntoa ( address ), ntohs ( port ),
191
 		   inet_ntoa ( address ), ntohs ( port ),
190
 		   ( ( filename[0] == '/' ) ? "" : "/" ), filename, blksize );
192
 		   ( ( filename[0] == '/' ) ? "" : "/" ), filename, blksize );
191
 	DBG ( " %s", uri_string );
193
 	DBG ( " %s", uri_string );
254
 	if ( ( rc = pxe_tftp_open ( tftp_open->ServerIPAddress,
256
 	if ( ( rc = pxe_tftp_open ( tftp_open->ServerIPAddress,
255
 				    tftp_open->TFTPPort,
257
 				    tftp_open->TFTPPort,
256
 				    tftp_open->FileName,
258
 				    tftp_open->FileName,
257
-				    tftp_open->PacketSize ) ) != 0 ) {
259
+				    tftp_open->PacketSize,
260
+				    0) ) != 0 ) {
258
 		tftp_open->Status = PXENV_STATUS ( rc );
261
 		tftp_open->Status = PXENV_STATUS ( rc );
259
 		return PXENV_EXIT_FAILURE;
262
 		return PXENV_EXIT_FAILURE;
260
 	}
263
 	}
488
 
491
 
489
 	/* Open TFTP file */
492
 	/* Open TFTP file */
490
 	if ( ( rc = pxe_tftp_open ( tftp_read_file->ServerIPAddress, 0,
493
 	if ( ( rc = pxe_tftp_open ( tftp_read_file->ServerIPAddress, 0,
491
-				    tftp_read_file->FileName, 0 ) ) != 0 ) {
494
+				    tftp_read_file->FileName, 0, 0 ) ) != 0 ) {
492
 		tftp_read_file->Status = PXENV_STATUS ( rc );
495
 		tftp_read_file->Status = PXENV_STATUS ( rc );
493
 		return PXENV_EXIT_FAILURE;
496
 		return PXENV_EXIT_FAILURE;
494
 	}
497
 	}
558
 
561
 
559
 	/* Open TFTP file */
562
 	/* Open TFTP file */
560
 	if ( ( rc = pxe_tftp_open ( tftp_get_fsize->ServerIPAddress, 0,
563
 	if ( ( rc = pxe_tftp_open ( tftp_get_fsize->ServerIPAddress, 0,
561
-				    tftp_get_fsize->FileName, 0 ) ) != 0 ) {
564
+				    tftp_get_fsize->FileName, 0, 1 ) ) != 0 ) {
562
 		tftp_get_fsize->Status = PXENV_STATUS ( rc );
565
 		tftp_get_fsize->Status = PXENV_STATUS ( rc );
563
 		return PXENV_EXIT_FAILURE;
566
 		return PXENV_EXIT_FAILURE;
564
 	}
567
 	}

+ 73
- 0
src/net/udp/tftp.c Dosyayı Görüntüle

133
 	TFTP_FL_RRQ_MULTICAST = 0x0004,
133
 	TFTP_FL_RRQ_MULTICAST = 0x0004,
134
 	/** Perform MTFTP recovery on timeout */
134
 	/** Perform MTFTP recovery on timeout */
135
 	TFTP_FL_MTFTP_RECOVERY = 0x0008,
135
 	TFTP_FL_MTFTP_RECOVERY = 0x0008,
136
+	/** Only get filesize and then abort the transfer */
137
+	TFTP_FL_SIZEONLY = 0x0010,
136
 };
138
 };
137
 
139
 
138
 /** Maximum number of MTFTP open requests before falling back to TFTP */
140
 /** Maximum number of MTFTP open requests before falling back to TFTP */
410
 	return xfer_deliver_iob_meta ( &tftp->socket, iobuf, &meta );
412
 	return xfer_deliver_iob_meta ( &tftp->socket, iobuf, &meta );
411
 }
413
 }
412
 
414
 
415
+/**
416
+ * Transmit ERROR (Abort)
417
+ *
418
+ * @v tftp		TFTP connection
419
+ * @v errcode		TFTP error code
420
+ * @v errmsg		Error message string
421
+ * @ret rc		Return status code
422
+ */
423
+static int tftp_send_error ( struct tftp_request *tftp, int errcode,
424
+			     const char *errmsg ) {
425
+	struct tftp_error *err;
426
+	struct io_buffer *iobuf;
427
+	struct xfer_metadata meta = {
428
+		.dest = ( struct sockaddr * ) &tftp->peer,
429
+	};
430
+	size_t msglen;
431
+
432
+	DBGC2 ( tftp, "TFTP %p sending ERROR %d: %s\n", tftp, errcode,
433
+		errmsg );
434
+
435
+	/* Allocate buffer */
436
+	msglen = sizeof ( *err ) + strlen ( errmsg ) + 1 /* NUL */;
437
+	iobuf = xfer_alloc_iob ( &tftp->socket, msglen );
438
+	if ( ! iobuf )
439
+		return -ENOMEM;
440
+
441
+	/* Build ERROR */
442
+	err = iob_put ( iobuf, msglen );
443
+	err->opcode = htons ( TFTP_ERROR );
444
+	err->errcode = htons ( errcode );
445
+	strcpy ( err->errmsg, errmsg );
446
+
447
+	/* ERR always goes to the peer recorded from the RRQ response */
448
+	return xfer_deliver_iob_meta ( &tftp->socket, iobuf, &meta );
449
+}
450
+
413
 /**
451
 /**
414
  * Transmit next relevant packet
452
  * Transmit next relevant packet
415
  *
453
  *
732
 			goto done;
770
 			goto done;
733
 	}
771
 	}
734
 
772
 
773
+	/* Abort request if only trying to determine file size */
774
+	if ( tftp->flags & TFTP_FL_SIZEONLY ) {
775
+		rc = 0;
776
+		tftp_send_error ( tftp, TFTP_ERR_UNKNOWN_TID, "TFTP Aborted" );
777
+		tftp_done ( tftp, rc );
778
+		return rc;
779
+	}
780
+
735
 	/* Request next data block */
781
 	/* Request next data block */
736
 	tftp_send_packet ( tftp );
782
 	tftp_send_packet ( tftp );
737
 
783
 
759
 	size_t data_len;
805
 	size_t data_len;
760
 	int rc;
806
 	int rc;
761
 
807
 
808
+	if ( tftp->flags & TFTP_FL_SIZEONLY ) {
809
+		/* If we get here then server doesn't support SIZE option */
810
+		rc = -ENOTSUP;
811
+		tftp_send_error ( tftp, TFTP_ERR_UNKNOWN_TID, "TFTP Aborted" );
812
+		goto done;
813
+	}
814
+
762
 	/* Sanity check */
815
 	/* Sanity check */
763
 	if ( iob_len ( iobuf ) < sizeof ( *data ) ) {
816
 	if ( iob_len ( iobuf ) < sizeof ( *data ) ) {
764
 		DBGC ( tftp, "TFTP %p received underlength DATA packet "
817
 		DBGC ( tftp, "TFTP %p received underlength DATA packet "
1120
 	.open	= tftp_open,
1173
 	.open	= tftp_open,
1121
 };
1174
 };
1122
 
1175
 
1176
+/**
1177
+ * Initiate TFTP-size request
1178
+ *
1179
+ * @v xfer		Data transfer interface
1180
+ * @v uri		Uniform Resource Identifier
1181
+ * @ret rc		Return status code
1182
+ */
1183
+static int tftpsize_open ( struct xfer_interface *xfer, struct uri *uri ) {
1184
+	return tftp_core_open ( xfer, uri, TFTP_PORT, NULL,
1185
+				( TFTP_FL_RRQ_SIZES |
1186
+				  TFTP_FL_SIZEONLY ) );
1187
+
1188
+}
1189
+
1190
+/** TFTP URI opener */
1191
+struct uri_opener tftpsize_uri_opener __uri_opener = {
1192
+	.scheme	= "tftpsize",
1193
+	.open	= tftpsize_open,
1194
+};
1195
+
1123
 /**
1196
 /**
1124
  * Initiate TFTM download
1197
  * Initiate TFTM download
1125
  *
1198
  *

Loading…
İptal
Kaydet