From fef30b6f809ea30d650ad369162b4799f2302187 Mon Sep 17 00:00:00 2001 From: hpa Date: Wed, 22 Dec 2004 12:49:04 +0000 Subject: [PATCH] Support alternate TFTP servers via filename syntax. --- NEWS | 6 +++ parseconfig.inc | 6 +++ pxelinux.asm | 153 +++++++++++++++++++++++++++++++++++++++++++++----------- pxelinux.doc | 20 ++++++++ ui.inc | 8 ++- 5 files changed, 161 insertions(+), 32 deletions(-) diff --git a/NEWS b/NEWS index 5802c45..1336ad3 100644 --- a/NEWS +++ b/NEWS @@ -26,6 +26,12 @@ Changes in 3.00: key to display the prompt" behaviour. * New simple menu system, as an alternative to the advanced menu system already present. See README.menu for details. + * PXELINUX: Filenames can now be prefixed with an IP address + plus :: (e.g. 192.0.2.1::filename), which downloads a file + from an alternate TFTP server, or just a :: + (e.g. ::filename), which suppresses the common pathname + prefix. See pxelinux.doc. + Changes in 2.13: * MEMDISK: Fix command-line parsing "brown paper bag" class diff --git a/parseconfig.inc b/parseconfig.inc index c72a569..1db13a1 100644 --- a/parseconfig.inc +++ b/parseconfig.inc @@ -90,7 +90,13 @@ pc_localboot: call getint xor ax,ax mov cx,FILENAME_MAX rep stosb ; Null kernel name +%if IS_PXELINUX + ; PXELINUX uses the first 4 bytes of vk_rname for the + ; mangled IP address + mov [VKernelBuf+vk_rname+5], bx ; Return type +%else mov [VKernelBuf+vk_rname+1], bx ; Return type +%endif .err: ret %endif diff --git a/pxelinux.asm b/pxelinux.asm index 4763670..a0328f4 100644 --- a/pxelinux.asm +++ b/pxelinux.asm @@ -189,7 +189,8 @@ RBFB_brainfuck resb 800h alignb FILENAME_MAX BootFile resb 256 ; Boot file from DHCP packet -ConfigName resb 256 ; Configuration file from DHCP option +ConfigServer resd 1 ; Null prefix for mangled config name +ConfigName resb 256-4 ; Configuration file from DHCP option PathPrefix resb 256 ; Path prefix derived from boot file DotQuadBuf resb 16 ; Buffer for dotted-quad IP address IPOption resb 80 ; ip= option buffer @@ -720,16 +721,21 @@ find_config: ; Begin looking for configuration file ; config_scan: + mov di,ConfigServer + xor eax,eax + stosd ; The config file is always from the server + test byte [DHCPMagic], 02h jz .no_option ; We got a DHCP option, try it first mov si,trying_msg call writestr - mov di,ConfigName + ; mov di,ConfigName ; - already the case mov si,di call writestr call crlf + mov di,ConfigServer call open jnz .success @@ -751,6 +757,7 @@ config_scan: mov si,di call writestr call crlf + mov di,ConfigServer call open pop di jnz .success @@ -790,6 +797,7 @@ config_scan: mov si,di call writestr call crlf + mov di,ConfigServer call open popa jnz .success @@ -1071,7 +1079,7 @@ memory_scan_for_pxenv_struct: ; Open a TFTP connection to the server ; ; On entry: -; DS:DI = filename +; DS:DI = mangled filename ; If successful: ; ZF clear ; SI = socket pointer @@ -1096,28 +1104,46 @@ searchdir: .sendreq: push ax ; [bp-2] - Retry counter push si ; [bp-4] - File name - push bx ; [bp-6] - TFTP block - mov bx,[bx] - push bx ; [bp-8] - TID (local port no) - mov eax,[ServerIP] ; Server IP - mov [pxe_udp_write_pkt.status],byte 0 - mov [pxe_udp_write_pkt.sip],eax - mov eax,[UseGW] - mov [pxe_udp_write_pkt.gip],eax - mov [pxe_udp_write_pkt.lport],bx - mov ax,[ServerPort] - mov [pxe_udp_write_pkt.rport],ax mov di,packet_buf mov [pxe_udp_write_pkt.buffer],di + mov ax,TFTP_RRQ ; TFTP opcode stosw + + lodsd ; EAX <- server override (if any) + and eax,eax + jnz .noprefix ; No prefix, and we have the server + push si ; Add common prefix mov si,PathPrefix call strcpy dec di pop si + + mov eax,[ServerIP] ; Get default server + +.noprefix: call strcpy ; Filename + + mov [bx+tftp_remoteip],eax + + push bx ; [bp-6] - TFTP block + mov bx,[bx] + push bx ; [bp-8] - TID (local port no) + + mov [pxe_udp_write_pkt.status],byte 0 + mov [pxe_udp_write_pkt.sip],eax + ; Now figure out the gateway + xor eax,[MyIP] + and eax,[Netmask] + jz .nogwneeded + mov eax,[Gateway] +.nogwneeded: + mov [pxe_udp_write_pkt.gip],eax + mov [pxe_udp_write_pkt.lport],bx + mov ax,[ServerPort] + mov [pxe_udp_write_pkt.rport],ax mov si,tftp_tail mov cx,tftp_tail_len rep movsb @@ -1170,10 +1196,9 @@ searchdir: mov si,[bp-6] ; TFTP pointer mov bx,[bp-8] ; TID - mov eax,[ServerIP] + mov eax,[si+tftp_remoteip] cmp [pxe_udp_read_pkt.sip],eax ; This is technically not to the TFTP spec? jne .no_packet - mov [si+tftp_remoteip],eax ; Got packet - reset timeout mov word [PktTimeout],PKT_TIMEOUT @@ -1382,6 +1407,50 @@ free_socket: ret ; +; parse_dotquad: +; Read a dot-quad pathname in DS:SI and output an IP +; address in EAX, with SI pointing to the first +; nonmatching character. +; +; Return CF=1 on error. +; +parse_dotquad: + push cx + mov cx,4 + xor eax,eax +.parseloop: + mov ch,ah + mov ah,al + lodsb + sub al,'0' + jb .notnumeric + cmp al,9 + ja .notnumeric + aad ; AL += 10 * AH; AH = 0; + xchg ah,ch + jmp .parseloop +.notnumeric: + cmp al,'.'-'0' + pushf + mov al,ah + mov ah,ch + xor ch,ch + ror eax,8 + popf + jne .error + loop .parseloop + jmp .done +.error: + loop .realerror ; If CX := 1 then we're done + clc + jmp .done +.realerror: + stc +.done: + dec si ; CF unchanged! + pop cx + ret +; ; mangle_name: Mangle a filename pointed to by DS:SI into a buffer pointed ; to by ES:DI; ends on encountering any whitespace. ; @@ -1389,8 +1458,32 @@ free_socket: ; and doesn't contain whitespace, and zero-pads the output buffer, ; so "repe cmpsb" can do a compare. ; +; The first four bytes of the manged name is the IP address of +; the download host. +; mangle_name: - mov cx,FILENAME_MAX-1 + push si + mov eax,[ServerIP] + cmp word [si],'::' ; Leading ::? + je .gotprefix + call parse_dotquad + jc .noip + cmp word [si],'::' + je .gotprefix +.noip: + pop si + xor eax,eax + jmp .prefix_done + +.gotprefix: + pop cx ; Adjust stack + inc si ; Skip double colon + inc si + +.prefix_done: + stosd ; Save IP address prefix + mov cx,FILENAME_MAX-5 + .mn_loop: lodsb cmp al,' ' ; If control or space, end @@ -1416,8 +1509,18 @@ mangle_name: ; On return, DI points to the first byte after the output name, ; which is set to a null byte. ; -unmangle_name: call strcpy +unmangle_name: + push eax + lodsd + and eax,eax + jz .noip + call gendotquad + mov ax,'::' + stosw +.noip: + call strcpy dec di ; Point to final null byte + pop eax ret ; @@ -1848,10 +1951,9 @@ reset_pxe: ; output a dotted quad string to ES:DI. ; DI points to terminal null at end of string on exit. ; -; CX is destroyed. -; gendotquad: push eax + push cx mov cx,4 .genchar: push eax @@ -1884,6 +1986,7 @@ gendotquad: loop .genchar dec di mov [es:di], byte 0 + pop cx pop eax ret @@ -1900,7 +2003,6 @@ gendotquad: ; ServerIP - boot server IP address ; Netmask - network mask ; Gateway - default gateway router IP -; UseGW - zero if ServerIP local, otherwise Gateway ; BootFile - boot file name ; ; This assumes the DHCP packet is in "trackbuf" and the length @@ -1952,14 +2054,6 @@ parse_dhcp: mov cx,64 call parse_dhcp_options .nosnameoverload: - ; Now adjust the gateway - mov eax,[MyIP] - xor eax,[ServerIP] - and eax,[Netmask] - jz .nogwneeded - mov eax,[Gateway] -.nogwneeded: - mov [UseGW],eax ret ; @@ -2402,7 +2496,6 @@ MyIP dd 0 ; My IP address ServerIP dd 0 ; IP address of boot server Netmask dd 0 ; Netmask of this subnet Gateway dd 0 ; Default router -UseGW dd 0 ; Router to use to get to ServerIP ServerPort dw TFTP_PORT ; TFTP server port ; diff --git a/pxelinux.doc b/pxelinux.doc index 2bc22c3..2fe2c2a 100644 --- a/pxelinux.doc +++ b/pxelinux.doc @@ -308,6 +308,26 @@ If you used this from a client whose Ethernet address was "/tftpboot/pxelinux.cfg/1:58:fa:84:cf:55:e". + ++++ ALTERNATE TFTP SERVERS ++++ + +PXELINUX supports the following special pathname conventions: + +::filename + + Suppresses the common filename prefix, i.e. passes the string + "filename" unmodified to the server. + +IP address::filename (e.g. 192.0.2.1::filename) + + Suppresses the common filename prefix, *and* sends a request + to an alternate TFTP server. + +:: was chosen because it is unlikely to conflict with operating system +usage. However, if you happen to have an environment for which the +special treatment of :: is a problem, please contact the SYSLINUX +mailing list. + + ++++ SOME NOTES ++++ If the boot fails, PXELINUX (unlike SYSLINUX) will not wait forever; diff --git a/ui.inc b/ui.inc index 2872ee5..33b69dd 100644 --- a/ui.inc +++ b/ui.inc @@ -278,7 +278,11 @@ vk_check: %if IS_PXELINUX || IS_ISOLINUX ; Is this a "localboot" pseudo-kernel? +%if IS_PXELINUX + cmp byte [VKernelBuf+vk_rname+4], 0 +%else cmp byte [VKernelBuf+vk_rname], 0 +%endif jne get_kernel ; No, it's real, go get it mov ax, [VKernelBuf+vk_rname+1] @@ -315,7 +319,7 @@ get_kernel: mov byte [KernelName+FILENAME_MAX],0 ; Zero-terminate filename/e mov eax,[KernelName+8] ; Save initial extension mov [exten_table_end],eax ; Last case == initial ext. %else - mov di,KernelName + mov di,KernelName+4*IS_PXELINUX xor al,al mov cx,FILENAME_MAX-5 ; Need 4 chars + null repne scasb ; Scan for final null @@ -429,7 +433,7 @@ kernel_good: %else push di push ax - mov di,KernelName + mov di,KernelName+4*IS_PXELINUX xor al,al mov cx,FILENAME_MAX repne scasb -- 2.7.4