PXELINUX: handle OACK packets with extra NULs, cleaner TFTP error
authorH. Peter Anvin <hpa@zytor.com>
Tue, 9 Jun 2009 05:19:41 +0000 (22:19 -0700)
committerH. Peter Anvin <hpa@zytor.com>
Tue, 9 Jun 2009 05:19:41 +0000 (22:19 -0700)
There are apparently TFTP servers in the field which will send OACK
packets with extra NUL bytes appended at the end.  If we find an OACK
packet where the only thing left at some point during processing is
NULs, then just consider the packet processed.

We have reported all TFTP protocol errors as "tsize required", which
is definitely not true anymore.  Change error code to 0 (undefined)
and the error string to "TFTP error".  When this code gets converted
to C we'll do better.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
NEWS
core/pxelinux.asm

diff --git a/NEWS b/NEWS
index bdc46cb..5a18525 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -8,6 +8,8 @@ Changes in 3.82:
          interrupts disabled.
        * Do not invoke the idle handler during large file loads.
        * Simple menu: make ONTIMEOUT work with MENU HIDDEN.
+       * PXELINUX: handle TFTP servers which have extra NULs at the
+         end of an OACK packet.
 
 Changes in 3.81:
        * Shuffler: fix bug in real-mode entry.  This affected a
index 9d9d5b4..de1b10c 100644 (file)
@@ -1106,6 +1106,15 @@ searchdir:
 .parse_oack:
                jcxz .done_pkt                  ; No options acked
 .get_opt_name:
+               ; Some TFTP servers have junk NUL bytes at the end of the packet.
+               ; If all that is left is NUL, then consider the packet processed.
+               mov di,si
+               push cx
+               xor ax,ax
+               repz scasb
+               pop cx
+               jz .done_pkt
+
                mov di,si
                mov bx,si
 .opt_name_loop:        lodsb
@@ -1115,10 +1124,10 @@ searchdir:
                stosb
                loop .opt_name_loop
                ; We ran out, and no final null
-               jmp .err_reply
+               jmp .done_pkt                   ; Ignore runt option
 .got_opt_name: ; si -> option value
                dec cx                          ; bytes left in pkt
-               jz .err_reply                   ; Option w/o value
+               jz .done_pkt                    ; Option w/o value, ignore
 
                ; Parse option pointed to by bx; guaranteed to be
                ; null-terminated.
@@ -1141,7 +1150,8 @@ searchdir:
 
                pop si
                pop cx
-               jmp .err_reply                  ; Non-negotiated option returned
+               ; Non-negotiated option returned, no idea what it means...
+               jmp .err_reply
 
 .get_value:    pop si                          ; si -> option value
                pop cx                          ; cx -> bytes left in pkt
@@ -1221,13 +1231,13 @@ searchdir:
                pop es
                jmp .done_pkt
 
-.err_reply:    ; Option negotiation error.  Send ERROR reply.
+.err_reply:    ; TFTP protocol error.  Send ERROR reply.
                ; ServerIP and gateway are already programmed in
                mov si,[bp-6]
                mov ax,[si+tftp_remoteport]
                mov word [pxe_udp_write_pkt.rport],ax
-               mov word [pxe_udp_write_pkt.buffer],tftp_opt_err
-               mov word [pxe_udp_write_pkt.buffersize],tftp_opt_err_len
+               mov word [pxe_udp_write_pkt.buffer],tftp_proto_err
+               mov word [pxe_udp_write_pkt.buffersize],tftp_proto_err_len
                mov di,pxe_udp_write_pkt
                mov bx,PXENV_UDP_WRITE
                call pxenv
@@ -2725,12 +2735,12 @@ tftp_opt_table:
 tftp_opts      equ ($-tftp_opt_table)/6
 
 ;
-; Error packet to return on options negotiation error
+; Error packet to return on TFTP protocol error
 ;
-tftp_opt_err   dw TFTP_ERROR                           ; ERROR packet
-               dw TFTP_EOPTNEG                         ; ERROR 8: bad options
-               db 'tsize option required', 0           ; Error message
-tftp_opt_err_len equ ($-tftp_opt_err)
+tftp_proto_err dw TFTP_ERROR                           ; ERROR packet
+               dw TFTP_EUNDEF                          ; ERROR 0: undefined
+               db 'TFTP protocol error', 0             ; Error message
+tftp_proto_err_len equ ($-tftp_proto_err)
 
                alignz 4
 ack_packet_buf:        dw TFTP_ACK, 0                          ; TFTP ACK packet