|
@@ -133,6 +133,8 @@ enum {
|
133
|
133
|
TFTP_FL_RRQ_MULTICAST = 0x0004,
|
134
|
134
|
/** Perform MTFTP recovery on timeout */
|
135
|
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
|
140
|
/** Maximum number of MTFTP open requests before falling back to TFTP */
|
|
@@ -410,6 +412,42 @@ static int tftp_send_ack ( struct tftp_request *tftp ) {
|
410
|
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
|
452
|
* Transmit next relevant packet
|
415
|
453
|
*
|
|
@@ -732,6 +770,14 @@ static int tftp_rx_oack ( struct tftp_request *tftp, void *buf, size_t len ) {
|
732
|
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
|
781
|
/* Request next data block */
|
736
|
782
|
tftp_send_packet ( tftp );
|
737
|
783
|
|
|
@@ -759,6 +805,13 @@ static int tftp_rx_data ( struct tftp_request *tftp,
|
759
|
805
|
size_t data_len;
|
760
|
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
|
815
|
/* Sanity check */
|
763
|
816
|
if ( iob_len ( iobuf ) < sizeof ( *data ) ) {
|
764
|
817
|
DBGC ( tftp, "TFTP %p received underlength DATA packet "
|
|
@@ -1120,6 +1173,26 @@ struct uri_opener tftp_uri_opener __uri_opener = {
|
1120
|
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
|
1197
|
* Initiate TFTM download
|
1125
|
1198
|
*
|