From owner-freebsd-bugs@FreeBSD.ORG Fri Oct 22 13:30:27 2004 Return-Path: Delivered-To: freebsd-bugs@hub.freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 8DC3616A4CE for ; Fri, 22 Oct 2004 13:30:27 +0000 (GMT) Received: from freefall.freebsd.org (freefall.freebsd.org [216.136.204.21]) by mx1.FreeBSD.org (Postfix) with ESMTP id 5998C43D48 for ; Fri, 22 Oct 2004 13:30:27 +0000 (GMT) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (gnats@localhost [127.0.0.1]) by freefall.freebsd.org (8.12.11/8.12.11) with ESMTP id i9MDURjg039788 for ; Fri, 22 Oct 2004 13:30:27 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.12.11/8.12.11/Submit) id i9MDURi6039785; Fri, 22 Oct 2004 13:30:27 GMT (envelope-from gnats) Resent-Date: Fri, 22 Oct 2004 13:30:27 GMT Resent-Message-Id: <200410221330.i9MDURi6039785@freefall.freebsd.org> Resent-From: FreeBSD-gnats-submit@FreeBSD.org (GNATS Filer) Resent-To: freebsd-bugs@FreeBSD.org Resent-Reply-To: FreeBSD-gnats-submit@FreeBSD.org, Ralf Wenk Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 70B4B16A4CE for ; Fri, 22 Oct 2004 13:29:28 +0000 (GMT) Received: from rz06.fh-karlsruhe.de (rz06.FH-Karlsruhe.DE [193.196.64.6]) by mx1.FreeBSD.org (Postfix) with ESMTP id 3D62B43D4C for ; Fri, 22 Oct 2004 13:29:27 +0000 (GMT) (envelope-from root@fh-karlsruhe.de) Received: from rz-tp600e.fh-karlsruhe.de ([193.196.65.252] helo=localhost) by rz06.fh-karlsruhe.de with esmtp (Exim 4.42) id 1CKzTx-000Goc-Mj; Fri, 22 Oct 2004 15:29:25 +0200 Received: from root by localhost with local (Exim 4.42 (FreeBSD)) id 1CKzTx-0000hC-3t; Fri, 22 Oct 2004 15:29:25 +0200 Message-Id: Date: Fri, 22 Oct 2004 15:29:25 +0200 From: Ralf Wenk To: FreeBSD-gnats-submit@FreeBSD.org X-Send-Pr-Version: 3.113 cc: Ralf Wenk Subject: kern/73004: [patch] PXE loader malfunction in multiple PXE server environment X-BeenThere: freebsd-bugs@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list Reply-To: Ralf Wenk List-Id: Bug reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 22 Oct 2004 13:30:27 -0000 >Number: 73004 >Category: kern >Synopsis: [patch] PXE loader malfunction in multiple PXE server environment >Confidential: no >Severity: serious >Priority: low >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Fri Oct 22 13:30:26 GMT 2004 >Closed-Date: >Last-Modified: >Originator: Ralf Wenk >Release: FreeBSD 5.3-STABLE i386 >Organization: FH Karlsruhe, University of Applied Sciences >Environment: System: FreeBSD RZ-Wenk1 5.3-STABLE FreeBSD 5.3-STABLE #0: Fri Oct 22 11:14:32 CEST 2004 root@RZ-Wenk1:/usr/obj/usr/src/sys/fsc-t-diskless i386 >Description: The pxeboot still do not support an environment with multipe DHCP/PXE bootservers. This patch uses the PXEs decision of which bootserver to use as well as enables the kernel to return values for the dhcp.* kernel environment variables used in /etc/rc.d/hostname and /etc/rc.d/resolv. See also problem report 65523. >How-To-Repeat: Use a multipe DHCP/PXE environment an try not to use the nearest DHCP/PXE bootserver. >Fix: --- pxe.c.udiff begins here --- --- pxe.c.old Fri Oct 22 15:03:44 2004 +++ pxe.c Fri Oct 22 15:04:14 2004 @@ -42,6 +42,7 @@ #include #include +#define SUPPORT_DHCP /* PXE uses DHCP */ #include #include #include "btxv86.h" @@ -133,6 +134,102 @@ }; /* + * This is ugly: + * libstand/bootp.c contains a similar RFC 1048 parser function named + * vend_rfc1048(), but the function is local to bootp.c and also uses + * a variable local to bootp.c if compiled with SUPPORT_DHCP defined. + * While the first problem could easily be fixed the second one would + * need an additional function in bootp.c to set the local variable. + */ +static int +pxe_vend_rfc1048(void) +{ + char vm_rfc1048[4] = VM_RFC1048; + u_char buffer[256]; + u_char *cp, *ep; + int size; + u_char tag; + + if (bcmp(bootplayer.vendor.v.magic, vm_rfc1048, sizeof(vm_rfc1048)) == 0) + { + cp = (u_char *)bootplayer.vendor.d; + ep = cp + sizeof(bootplayer.vendor.d); + + /* Step over magic cookie */ + cp += sizeof(int); + + while (cp < ep) { + tag = *cp++; + size = *cp++; + if (tag == TAG_END) + break; + + if (tag == TAG_SUBNET_MASK) { + bcopy(cp, &netmask, sizeof(netmask)); +#ifdef PXE_DEBUG + printf("pxe_vend_rfc1048: SUBNET_MASK %s\n", intoa(netmask)); +#endif + } + if (tag == TAG_GATEWAY) { + bcopy(cp, &gateip.s_addr, sizeof(gateip.s_addr)); +#ifdef PXE_DEBUG + printf("pxe_vend_rfc1048: GATEWAY %s\n", intoa(gateip.s_addr)); +#endif + } + if (tag == TAG_SWAPSERVER) { + /* let it override bp_siaddr */ + bcopy(cp, &rootip.s_addr, sizeof(swapip.s_addr)); +#ifdef PXE_DEBUG + printf("pxe_vend_rfc1048: SWAPSERVER %s\n", intoa(rootip.s_addr)); +#endif + } + if (tag == TAG_ROOTPATH) { + strncpy(rootpath, (char *)cp, sizeof(rootpath)); + rootpath[size] = '\0'; +#ifdef PXE_DEBUG + printf("pxe_vend_rfc1048: ROOTPATH %s\n", rootpath); +#endif + } + if (tag == TAG_HOSTNAME) { + strncpy(hostname, (char *)cp, sizeof(hostname)); + hostname[size] = '\0'; +#ifdef PXE_DEBUG + printf("pxe_vend_rfc1048: HOSTNAME %s\n", hostname); +#endif + setenv("dhcp.host-name", hostname, 1); + } + if (tag == TAG_DOMAINNAME) { + strncpy(buffer, (char *)cp, sizeof(buffer)); + buffer[size] = '\0'; +#ifdef PXE_DEBUG + printf("pxe_vend_rfc1048: DOMAINNAME %s\n", buffer); +#endif + setenv("dhcp.domain-name", buffer, 1); + } + if (tag == TAG_DOMAIN_SERVER) { + int count = 0; /* DNS server(s) */ + + buffer[0] = '\0'; + while ( count < (size >> 2)) { + strcat(buffer, inet_ntoa(*((struct in_addr*)cp + count))); + strcat(buffer, ","); + count++; + } + buffer[strlen(buffer) - 1] = '\0'; +#ifdef PXE_DEBUG + printf("pxe_vend_rfc1048: DOMAINNAMESERVER %s\n", buffer); +#endif + setenv("dhcp.domain-name-server", buffer, 1); + } + cp += size; + } + return(0); + } + else + return(-1); +} + +/* * This function is called by the loader to enable PXE support if we * are booted by PXE. The passed in pointer is a pointer to the * PXENV+ structure. @@ -274,12 +371,52 @@ } if (rootip.s_addr == 0) { /* - * Do a bootp/dhcp request to find out where our - * NFS/TFTP server is. Even if we dont get back - * the proper information, fall back to the server - * which brought us to life and a default rootpath. + * PXE looks into the content of all answers to its request + * and uses a finite state machine to select one of them. + * It is even possible that there are several requests + * generated and the information collected is combined. + * E.g. in the case of several PXE servers it is possible + * that not the answer of the fastest one is selected. This + * breaks the simple way of just using the first answer. + * But fortunately PXE stores the selected information + * in the bootplayer structure for us to use. + */ +#ifdef PXE_DEBUG + printf("pxe_open: bootplayer.cip: %s\n", intoa( bootplayer.cip)); + printf("pxe_open: bootplayer.yip: %s\n", intoa( bootplayer.yip)); + printf("pxe_open: bootplayer.sip: %s\n", intoa( bootplayer.sip)); + printf("pxe_open: bootplayer.gip: %s\n", intoa( bootplayer.gip)); + sprintf(temp, "%6D", bootplayer.CAddr, ":"); + printf("pxe_open: bootplayer.CAddr: %s\n", temp); + printf("pxe_open: bootplayer.Sname: %s\n", bootplayer.Sname); + printf("pxe_open: bootplayer.bootfile: %s\n", bootplayer.bootfile); +#endif + /* + * Calling bootp() sets some global variables as a side effect + * which are used later in the (legacy) code. As we try to avoid + * calling boot(), we had to do the same thing. */ - bootp(pxe_sock, BOOTP_PXE); + myip.s_addr = bootplayer.yip; + if (IN_CLASSA(ntohl(myip.s_addr))) + netmask = htonl(IN_CLASSA_NET); + else if (IN_CLASSB(ntohl(myip.s_addr))) + netmask = htonl(IN_CLASSB_NET); + else + netmask = htonl(IN_CLASSC_NET); + if (pxe_vend_rfc1048() != 0) { + /* + * We are not happy with the information found in the + * bootplayer structure. As some last resort + * do a bootp/dhcp request to find out where our + * NFS/TFTP server is. Even if we dont get back + * the proper information, fall back to the server + * which brought us to life and a default rootpath. + */ + bootp(pxe_sock, BOOTP_PXE); + } +#ifdef PXE_DEBUG + printf("pxe_open: server addr: %s\n", inet_ntoa(rootip)); +#endif if (rootip.s_addr == 0) rootip.s_addr = bootplayer.sip; if (!rootpath[1]) @@ -299,7 +436,7 @@ printf("pxe_open: server path: %s\n", rootpath); printf("pxe_open: gateway ip: %s\n", inet_ntoa(gateip)); - setenv("boot.netif.ip", inet_ntoa(myip), 1); + setenv("boot.netif.ip", intoa(bootplayer.yip), 1); setenv("boot.netif.netmask", intoa(netmask), 1); setenv("boot.netif.gateway", inet_ntoa(gateip), 1); if (bootplayer.Hardware == ETHER_TYPE) { --- pxe.c.udiff ends here --- >Release-Note: >Audit-Trail: >Unformatted: