Index: head/lib/libstand/arp.c =================================================================== --- head/lib/libstand/arp.c (revision 317886) +++ head/lib/libstand/arp.c (revision 317887) @@ -1,309 +1,305 @@ /* $NetBSD: arp.c,v 1.18 1997/07/07 15:52:49 drochner Exp $ */ /* * Copyright (c) 1992 Regents of the University of California. * All rights reserved. * * This software was developed by the Computer Systems Engineering group * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and * contributed to Berkeley. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#) Header: arp.c,v 1.5 93/07/15 05:52:26 leres Exp (LBL) */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include "stand.h" #include "net.h" /* Cache stuff */ #define ARP_NUM 8 /* need at most 3 arp entries */ struct arp_list { struct in_addr addr; u_char ea[6]; } arp_list[ARP_NUM] = { /* XXX - net order `INADDR_BROADCAST' must be a constant */ { {0xffffffff}, BA } }; int arp_num = 1; /* Local forwards */ static ssize_t arpsend(struct iodesc *, void *, size_t); -static ssize_t arprecv(struct iodesc *, void *, size_t, time_t); +static ssize_t arprecv(struct iodesc *, void **, void **, time_t); /* Broadcast an ARP packet, asking who has addr on interface d */ u_char * -arpwhohas(d, addr) - struct iodesc *d; - struct in_addr addr; +arpwhohas(struct iodesc *d, struct in_addr addr) { int i; struct ether_arp *ah; struct arp_list *al; + void *pkt; struct { struct ether_header eh; struct { struct ether_arp arp; u_char pad[18]; /* 60 - sizeof(...) */ } data; } wbuf; - struct { - struct ether_header eh; - struct { - struct ether_arp arp; - u_char pad[24]; /* extra space */ - } data; - } rbuf; /* Try for cached answer first */ for (i = 0, al = arp_list; i < arp_num; ++i, ++al) if (addr.s_addr == al->addr.s_addr) return (al->ea); /* Don't overflow cache */ if (arp_num > ARP_NUM - 1) { arp_num = 1; /* recycle */ printf("arpwhohas: overflowed arp_list!\n"); } #ifdef ARP_DEBUG if (debug) printf("arpwhohas: send request for %s\n", inet_ntoa(addr)); #endif bzero((char*)&wbuf.data, sizeof(wbuf.data)); ah = &wbuf.data.arp; ah->arp_hrd = htons(ARPHRD_ETHER); ah->arp_pro = htons(ETHERTYPE_IP); ah->arp_hln = sizeof(ah->arp_sha); /* hardware address length */ ah->arp_pln = sizeof(ah->arp_spa); /* protocol address length */ ah->arp_op = htons(ARPOP_REQUEST); MACPY(d->myea, ah->arp_sha); bcopy(&d->myip, ah->arp_spa, sizeof(ah->arp_spa)); /* Leave zeros in arp_tha */ bcopy(&addr, ah->arp_tpa, sizeof(ah->arp_tpa)); /* Store ip address in cache (incomplete entry). */ al->addr = addr; + pkt = NULL; + ah = NULL; i = sendrecv(d, arpsend, &wbuf.data, sizeof(wbuf.data), - arprecv, &rbuf.data, sizeof(rbuf.data)); + arprecv, &pkt, (void **)&ah); if (i == -1) { panic("arp: no response for %s\n", inet_ntoa(addr)); } /* Store ethernet address in cache */ - ah = &rbuf.data.arp; #ifdef ARP_DEBUG if (debug) { + struct ether_header *eh; + + eh = (struct ether_header *)((uintptr_t)pkt + ETHER_ALIGN); printf("arp: response from %s\n", - ether_sprintf(rbuf.eh.ether_shost)); + ether_sprintf(eh->ether_shost)); printf("arp: cacheing %s --> %s\n", inet_ntoa(addr), ether_sprintf(ah->arp_sha)); } #endif MACPY(ah->arp_sha, al->ea); ++arp_num; + free(pkt); return (al->ea); } static ssize_t -arpsend(d, pkt, len) - struct iodesc *d; - void *pkt; - size_t len; +arpsend(struct iodesc *d, void *pkt, size_t len) { #ifdef ARP_DEBUG if (debug) printf("arpsend: called\n"); #endif return (sendether(d, pkt, len, bcea, ETHERTYPE_ARP)); } /* * Returns 0 if this is the packet we're waiting for * else -1 (and errno == 0) */ static ssize_t -arprecv(d, pkt, len, tleft) - struct iodesc *d; - void *pkt; - size_t len; - time_t tleft; +arprecv(struct iodesc *d, void **pkt, void **payload, time_t tleft) { ssize_t n; struct ether_arp *ah; u_int16_t etype; /* host order */ + void *ptr; #ifdef ARP_DEBUG if (debug) printf("arprecv: "); #endif - n = readether(d, pkt, len, tleft, &etype); + ptr = NULL; + n = readether(d, &ptr, (void **)&ah, tleft, &etype); errno = 0; /* XXX */ if (n == -1 || n < sizeof(struct ether_arp)) { #ifdef ARP_DEBUG if (debug) printf("bad len=%d\n", n); #endif + free(ptr); return (-1); } if (etype != ETHERTYPE_ARP) { #ifdef ARP_DEBUG if (debug) printf("not arp type=%d\n", etype); #endif + free(ptr); return (-1); } /* Ethernet address now checked in readether() */ - - ah = (struct ether_arp *)pkt; if (ah->arp_hrd != htons(ARPHRD_ETHER) || ah->arp_pro != htons(ETHERTYPE_IP) || ah->arp_hln != sizeof(ah->arp_sha) || ah->arp_pln != sizeof(ah->arp_spa) ) { #ifdef ARP_DEBUG if (debug) printf("bad hrd/pro/hln/pln\n"); #endif + free(ptr); return (-1); } if (ah->arp_op == htons(ARPOP_REQUEST)) { #ifdef ARP_DEBUG if (debug) printf("is request\n"); #endif arp_reply(d, ah); + free(ptr); return (-1); } if (ah->arp_op != htons(ARPOP_REPLY)) { #ifdef ARP_DEBUG if (debug) printf("not ARP reply\n"); #endif + free(ptr); return (-1); } /* Is the reply from the source we want? */ if (bcmp(&arp_list[arp_num].addr, ah->arp_spa, sizeof(ah->arp_spa))) { #ifdef ARP_DEBUG if (debug) printf("unwanted address\n"); #endif + free(ptr); return (-1); } /* We don't care who the reply was sent to. */ /* We have our answer. */ #ifdef ARP_DEBUG if (debug) printf("got it\n"); #endif + *pkt = ptr; + *payload = ah; return (n); } /* * Convert an ARP request into a reply and send it. * Notes: Re-uses buffer. Pad to length = 46. */ void -arp_reply(d, pkt) - struct iodesc *d; - void *pkt; /* the request */ +arp_reply(struct iodesc *d, void *pkt) { struct ether_arp *arp = pkt; if (arp->arp_hrd != htons(ARPHRD_ETHER) || arp->arp_pro != htons(ETHERTYPE_IP) || arp->arp_hln != sizeof(arp->arp_sha) || arp->arp_pln != sizeof(arp->arp_spa) ) { #ifdef ARP_DEBUG if (debug) printf("arp_reply: bad hrd/pro/hln/pln\n"); #endif return; } if (arp->arp_op != htons(ARPOP_REQUEST)) { #ifdef ARP_DEBUG if (debug) printf("arp_reply: not request!\n"); #endif return; } /* If we are not the target, ignore the request. */ if (bcmp(arp->arp_tpa, &d->myip, sizeof(arp->arp_tpa))) return; #ifdef ARP_DEBUG if (debug) { printf("arp_reply: to %s\n", ether_sprintf(arp->arp_sha)); } #endif arp->arp_op = htons(ARPOP_REPLY); /* source becomes target */ bcopy(arp->arp_sha, arp->arp_tha, sizeof(arp->arp_tha)); bcopy(arp->arp_spa, arp->arp_tpa, sizeof(arp->arp_tpa)); /* here becomes source */ bcopy(d->myea, arp->arp_sha, sizeof(arp->arp_sha)); bcopy(&d->myip, arp->arp_spa, sizeof(arp->arp_spa)); /* * No need to get fancy here. If the send fails, the * requestor will just ask again. */ (void) sendether(d, pkt, sizeof(*arp) + 18, arp->arp_tha, ETHERTYPE_ARP); } Index: head/lib/libstand/bootp.c =================================================================== --- head/lib/libstand/bootp.c (revision 317886) +++ head/lib/libstand/bootp.c (revision 317887) @@ -1,783 +1,788 @@ /* $NetBSD: bootp.c,v 1.14 1998/02/16 11:10:54 drochner Exp $ */ /* * Copyright (c) 1992 Regents of the University of California. * All rights reserved. * * This software was developed by the Computer Systems Engineering group * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and * contributed to Berkeley. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#) Header: bootp.c,v 1.4 93/09/11 03:13:51 leres Exp (LBL) */ #include __FBSDID("$FreeBSD$"); +#include #include #include #include #include #include #include #define BOOTP_DEBUGxx #define SUPPORT_DHCP #define DHCP_ENV_NOVENDOR 1 /* do not parse vendor options */ #define DHCP_ENV_PXE 10 /* assume pxe vendor options */ #define DHCP_ENV_FREEBSD 11 /* assume freebsd vendor options */ /* set DHCP_ENV to one of the values above to export dhcp options to kenv */ #define DHCP_ENV DHCP_ENV_NO_VENDOR #include "stand.h" #include "net.h" #include "netif.h" #include "bootp.h" struct in_addr servip; static time_t bot; static char vm_rfc1048[4] = VM_RFC1048; #ifdef BOOTP_VEND_CMU static char vm_cmu[4] = VM_CMU; #endif /* Local forwards */ static ssize_t bootpsend(struct iodesc *, void *, size_t); -static ssize_t bootprecv(struct iodesc *, void *, size_t, time_t); +static ssize_t bootprecv(struct iodesc *, void **, void **, time_t); static int vend_rfc1048(u_char *, u_int); #ifdef BOOTP_VEND_CMU static void vend_cmu(u_char *); #endif #ifdef DHCP_ENV /* export the dhcp response to kenv */ struct dhcp_opt; static void setenv_(u_char *cp, u_char *ep, struct dhcp_opt *opts); #else #define setenv_(a, b, c) #endif #ifdef SUPPORT_DHCP static char expected_dhcpmsgtype = -1, dhcp_ok; struct in_addr dhcp_serverip; #endif +struct bootp *bootp_response; +size_t bootp_response_size; /* Fetch required bootp infomation */ void -bootp(sock, flag) - int sock; - int flag; +bootp(int sock, int flag) { + void *pkt; struct iodesc *d; struct bootp *bp; struct { u_char header[HEADER_SIZE]; struct bootp wbootp; } wbuf; - struct { - u_char header[HEADER_SIZE]; - struct bootp rbootp; - } rbuf; + struct bootp *rbootp; #ifdef BOOTP_DEBUG if (debug) printf("bootp: socket=%d\n", sock); #endif if (!bot) bot = getsecs(); if (!(d = socktodesc(sock))) { printf("bootp: bad socket. %d\n", sock); return; } #ifdef BOOTP_DEBUG if (debug) printf("bootp: d=%lx\n", (long)d); #endif bp = &wbuf.wbootp; bzero(bp, sizeof(*bp)); bp->bp_op = BOOTREQUEST; bp->bp_htype = 1; /* 10Mb Ethernet (48 bits) */ bp->bp_hlen = 6; bp->bp_xid = htonl(d->xid); MACPY(d->myea, bp->bp_chaddr); strncpy(bp->bp_file, bootfile, sizeof(bp->bp_file)); bcopy(vm_rfc1048, bp->bp_vend, sizeof(vm_rfc1048)); #ifdef SUPPORT_DHCP bp->bp_vend[4] = TAG_DHCP_MSGTYPE; bp->bp_vend[5] = 1; bp->bp_vend[6] = DHCPDISCOVER; /* * If we are booting from PXE, we want to send the string * 'PXEClient' to the DHCP server so you have the option of * only responding to PXE aware dhcp requests. */ if (flag & BOOTP_PXE) { bp->bp_vend[7] = TAG_CLASSID; bp->bp_vend[8] = 9; bcopy("PXEClient", &bp->bp_vend[9], 9); bp->bp_vend[18] = TAG_PARAM_REQ; bp->bp_vend[19] = 7; bp->bp_vend[20] = TAG_ROOTPATH; bp->bp_vend[21] = TAG_HOSTNAME; bp->bp_vend[22] = TAG_SWAPSERVER; bp->bp_vend[23] = TAG_GATEWAY; bp->bp_vend[24] = TAG_SUBNET_MASK; bp->bp_vend[25] = TAG_INTF_MTU; bp->bp_vend[26] = TAG_SERVERID; bp->bp_vend[27] = TAG_END; } else bp->bp_vend[7] = TAG_END; #else bp->bp_vend[4] = TAG_END; #endif d->myip.s_addr = INADDR_ANY; d->myport = htons(IPPORT_BOOTPC); d->destip.s_addr = INADDR_BROADCAST; d->destport = htons(IPPORT_BOOTPS); #ifdef SUPPORT_DHCP expected_dhcpmsgtype = DHCPOFFER; dhcp_ok = 0; #endif if(sendrecv(d, bootpsend, bp, sizeof(*bp), - bootprecv, &rbuf.rbootp, sizeof(rbuf.rbootp)) - == -1) { + bootprecv, &pkt, (void **)&rbootp) == -1) { printf("bootp: no reply\n"); return; } #ifdef SUPPORT_DHCP if(dhcp_ok) { u_int32_t leasetime; bp->bp_vend[6] = DHCPREQUEST; bp->bp_vend[7] = TAG_REQ_ADDR; bp->bp_vend[8] = 4; - bcopy(&rbuf.rbootp.bp_yiaddr, &bp->bp_vend[9], 4); + bcopy(&rbootp->bp_yiaddr, &bp->bp_vend[9], 4); bp->bp_vend[13] = TAG_SERVERID; bp->bp_vend[14] = 4; bcopy(&dhcp_serverip.s_addr, &bp->bp_vend[15], 4); bp->bp_vend[19] = TAG_LEASETIME; bp->bp_vend[20] = 4; leasetime = htonl(300); bcopy(&leasetime, &bp->bp_vend[21], 4); if (flag & BOOTP_PXE) { bp->bp_vend[25] = TAG_CLASSID; bp->bp_vend[26] = 9; bcopy("PXEClient", &bp->bp_vend[27], 9); bp->bp_vend[36] = TAG_END; } else bp->bp_vend[25] = TAG_END; expected_dhcpmsgtype = DHCPACK; + free(pkt); if(sendrecv(d, bootpsend, bp, sizeof(*bp), - bootprecv, &rbuf.rbootp, sizeof(rbuf.rbootp)) - == -1) { + bootprecv, &pkt, (void **)&rbootp) == -1) { printf("DHCPREQUEST failed\n"); return; } } #endif - myip = d->myip = rbuf.rbootp.bp_yiaddr; - servip = rbuf.rbootp.bp_siaddr; - if(rootip.s_addr == INADDR_ANY) rootip = servip; - bcopy(rbuf.rbootp.bp_file, bootfile, sizeof(bootfile)); + myip = d->myip = rbootp->bp_yiaddr; + servip = rbootp->bp_siaddr; + if (rootip.s_addr == INADDR_ANY) + rootip = servip; + bcopy(rbootp->bp_file, bootfile, sizeof(bootfile)); bootfile[sizeof(bootfile) - 1] = '\0'; if (!netmask) { 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); #ifdef BOOTP_DEBUG if (debug) printf("'native netmask' is %s\n", intoa(netmask)); #endif } #ifdef BOOTP_DEBUG if (debug) printf("mask: %s\n", intoa(netmask)); #endif /* We need a gateway if root is on a different net */ if (!SAMENET(myip, rootip, netmask)) { #ifdef BOOTP_DEBUG if (debug) printf("need gateway for root ip\n"); #endif } /* Toss gateway if on a different net */ if (!SAMENET(myip, gateip, netmask)) { #ifdef BOOTP_DEBUG if (debug) printf("gateway ip (%s) bad\n", inet_ntoa(gateip)); #endif gateip.s_addr = 0; } /* Bump xid so next request will be unique. */ ++d->xid; + free(pkt); } /* Transmit a bootp request */ static ssize_t -bootpsend(d, pkt, len) - struct iodesc *d; - void *pkt; - size_t len; +bootpsend(struct iodesc *d, void *pkt, size_t len) { struct bootp *bp; #ifdef BOOTP_DEBUG if (debug) printf("bootpsend: d=%lx called.\n", (long)d); #endif bp = pkt; bp->bp_secs = htons((u_short)(getsecs() - bot)); #ifdef BOOTP_DEBUG if (debug) printf("bootpsend: calling sendudp\n"); #endif return (sendudp(d, pkt, len)); } static ssize_t -bootprecv(d, pkt, len, tleft) -struct iodesc *d; -void *pkt; -size_t len; -time_t tleft; +bootprecv(struct iodesc *d, void **pkt, void **payload, time_t tleft) { ssize_t n; struct bootp *bp; + void *ptr; -#ifdef BOOTP_DEBUGx +#ifdef BOOTP_DEBUG if (debug) printf("bootp_recvoffer: called\n"); #endif - n = readudp(d, pkt, len, tleft); + ptr = NULL; + n = readudp(d, &ptr, (void **)&bp, tleft); if (n == -1 || n < sizeof(struct bootp) - BOOTP_VENDSIZE) goto bad; - bp = (struct bootp *)pkt; - #ifdef BOOTP_DEBUG if (debug) - printf("bootprecv: checked. bp = 0x%lx, n = %d\n", - (long)bp, (int)n); + printf("bootprecv: checked. bp = %p, n = %zd\n", bp, n); #endif if (bp->bp_xid != htonl(d->xid)) { #ifdef BOOTP_DEBUG if (debug) { printf("bootprecv: expected xid 0x%lx, got 0x%x\n", d->xid, ntohl(bp->bp_xid)); } #endif goto bad; } #ifdef BOOTP_DEBUG if (debug) printf("bootprecv: got one!\n"); #endif /* Suck out vendor info */ if (bcmp(vm_rfc1048, bp->bp_vend, sizeof(vm_rfc1048)) == 0) { - if(vend_rfc1048(bp->bp_vend, sizeof(bp->bp_vend)) != 0) + int vsize = n - offsetof(struct bootp, bp_vend); + if (vend_rfc1048(bp->bp_vend, vsize) != 0) goto bad; + + /* Save copy of bootp reply or DHCP ACK message */ + if (bp->bp_op == BOOTREPLY && + ((dhcp_ok == 1 && expected_dhcpmsgtype == DHCPACK) || + dhcp_ok == 0)) { + free(bootp_response); + bootp_response = malloc(n); + if (bootp_response != NULL) { + bootp_response_size = n; + bcopy(bp, bootp_response, bootp_response_size); + } + } } #ifdef BOOTP_VEND_CMU else if (bcmp(vm_cmu, bp->bp_vend, sizeof(vm_cmu)) == 0) vend_cmu(bp->bp_vend); #endif else printf("bootprecv: unknown vendor 0x%lx\n", (long)bp->bp_vend); - return(n); + *pkt = ptr; + *payload = bp; + return (n); bad: + free(ptr); errno = 0; return (-1); } int dhcp_try_rfc1048(u_char *cp, u_int len) { expected_dhcpmsgtype = DHCPACK; if (bcmp(vm_rfc1048, cp, sizeof(vm_rfc1048)) == 0) { return (vend_rfc1048(cp, len)); } return (-1); } static int -vend_rfc1048(cp, len) - u_char *cp; - u_int len; +vend_rfc1048(u_char *cp, u_int len) { u_char *ep; int size; u_char tag; const char *val; #ifdef BOOTP_DEBUG if (debug) printf("vend_rfc1048 bootp info. len=%d\n", len); #endif ep = cp + len; /* Step over magic cookie */ cp += sizeof(int); setenv_(cp, ep, NULL); while (cp < ep) { tag = *cp++; size = *cp++; if (tag == TAG_END) break; if (tag == TAG_SUBNET_MASK) { bcopy(cp, &netmask, sizeof(netmask)); } if (tag == TAG_GATEWAY) { bcopy(cp, &gateip.s_addr, sizeof(gateip.s_addr)); } if (tag == TAG_SWAPSERVER) { /* let it override bp_siaddr */ bcopy(cp, &rootip.s_addr, sizeof(rootip.s_addr)); } if (tag == TAG_ROOTPATH) { if ((val = getenv("dhcp.root-path")) == NULL) val = (const char *)cp; strlcpy(rootpath, val, sizeof(rootpath)); } if (tag == TAG_HOSTNAME) { if ((val = getenv("dhcp.host-name")) == NULL) val = (const char *)cp; strlcpy(hostname, val, sizeof(hostname)); } if (tag == TAG_INTF_MTU) { intf_mtu = 0; if ((val = getenv("dhcp.interface-mtu")) != NULL) { unsigned long tmp; char *end; errno = 0; /* * Do not allow MTU to exceed max IPv4 packet * size, max value of 16-bit word. */ tmp = strtoul(val, &end, 0); if (errno != 0 || *val == '\0' || *end != '\0' || tmp > USHRT_MAX) { printf("%s: bad value: \"%s\", " "ignoring\n", "dhcp.interface-mtu", val); } else { intf_mtu = (u_int)tmp; } } if (intf_mtu <= 0) intf_mtu = be16dec(cp); } #ifdef SUPPORT_DHCP if (tag == TAG_DHCP_MSGTYPE) { if(*cp != expected_dhcpmsgtype) return(-1); dhcp_ok = 1; } if (tag == TAG_SERVERID) { bcopy(cp, &dhcp_serverip.s_addr, sizeof(dhcp_serverip.s_addr)); } #endif cp += size; } return(0); } #ifdef BOOTP_VEND_CMU static void -vend_cmu(cp) - u_char *cp; +vend_cmu(u_char *cp) { struct cmu_vend *vp; #ifdef BOOTP_DEBUG if (debug) printf("vend_cmu bootp info.\n"); #endif vp = (struct cmu_vend *)cp; if (vp->v_smask.s_addr != 0) { netmask = vp->v_smask.s_addr; } if (vp->v_dgate.s_addr != 0) { gateip = vp->v_dgate; } } #endif #ifdef DHCP_ENV /* * Parse DHCP options and store them into kenv variables. * Original code from Danny Braniss, modifications by Luigi Rizzo. * * The parser is driven by tables which specify the type and name of * each dhcp option and how it appears in kenv. * The first entry in the list contains the prefix used to set the kenv * name (including the . if needed), the last entry must have a 0 tag. * Entries do not need to be sorted though it helps for readability. * * Certain vendor-specific tables can be enabled according to DHCP_ENV. * Set it to 0 if you don't want any. */ enum opt_fmt { __NONE = 0, __8 = 1, __16 = 2, __32 = 4, /* Unsigned fields, value=size */ __IP, /* IPv4 address */ __TXT, /* C string */ __BYTES, /* byte sequence, printed %02x */ __INDIR, /* name=value */ __ILIST, /* name=value;name=value ... */ __VE, /* vendor specific, recurse */ }; struct dhcp_opt { uint8_t tag; uint8_t fmt; const char *desc; }; static struct dhcp_opt vndr_opt[] = { /* Vendor Specific Options */ #if DHCP_ENV == DHCP_ENV_FREEBSD /* FreeBSD table in the original code */ {0, 0, "FreeBSD"}, /* prefix */ {1, __TXT, "kernel"}, {2, __TXT, "kernelname"}, {3, __TXT, "kernel_options"}, {4, __IP, "usr-ip"}, {5, __TXT, "conf-path"}, {6, __TXT, "rc.conf0"}, {7, __TXT, "rc.conf1"}, {8, __TXT, "rc.conf2"}, {9, __TXT, "rc.conf3"}, {10, __TXT, "rc.conf4"}, {11, __TXT, "rc.conf5"}, {12, __TXT, "rc.conf6"}, {13, __TXT, "rc.conf7"}, {14, __TXT, "rc.conf8"}, {15, __TXT, "rc.conf9"}, {20, __TXT, "boot.nfsroot.options"}, {245, __INDIR, ""}, {246, __INDIR, ""}, {247, __INDIR, ""}, {248, __INDIR, ""}, {249, __INDIR, ""}, {250, __INDIR, ""}, {251, __INDIR, ""}, {252, __INDIR, ""}, {253, __INDIR, ""}, {254, __INDIR, ""}, #elif DHCP_ENV == DHCP_ENV_PXE /* some pxe options, RFC4578 */ {0, 0, "pxe"}, /* prefix */ {93, __16, "system-architecture"}, {94, __BYTES, "network-interface"}, {97, __BYTES, "machine-identifier"}, #else /* default (empty) table */ {0, 0, "dhcp.vendor."}, /* prefix */ #endif {0, __TXT, "%soption-%d"} }; static struct dhcp_opt dhcp_opt[] = { /* DHCP Option names, formats and codes, from RFC2132. */ {0, 0, "dhcp."}, // prefix {1, __IP, "subnet-mask"}, {2, __32, "time-offset"}, /* this is signed */ {3, __IP, "routers"}, {4, __IP, "time-servers"}, {5, __IP, "ien116-name-servers"}, {6, __IP, "domain-name-servers"}, {7, __IP, "log-servers"}, {8, __IP, "cookie-servers"}, {9, __IP, "lpr-servers"}, {10, __IP, "impress-servers"}, {11, __IP, "resource-location-servers"}, {12, __TXT, "host-name"}, {13, __16, "boot-size"}, {14, __TXT, "merit-dump"}, {15, __TXT, "domain-name"}, {16, __IP, "swap-server"}, {17, __TXT, "root-path"}, {18, __TXT, "extensions-path"}, {19, __8, "ip-forwarding"}, {20, __8, "non-local-source-routing"}, {21, __IP, "policy-filter"}, {22, __16, "max-dgram-reassembly"}, {23, __8, "default-ip-ttl"}, {24, __32, "path-mtu-aging-timeout"}, {25, __16, "path-mtu-plateau-table"}, {26, __16, "interface-mtu"}, {27, __8, "all-subnets-local"}, {28, __IP, "broadcast-address"}, {29, __8, "perform-mask-discovery"}, {30, __8, "mask-supplier"}, {31, __8, "perform-router-discovery"}, {32, __IP, "router-solicitation-address"}, {33, __IP, "static-routes"}, {34, __8, "trailer-encapsulation"}, {35, __32, "arp-cache-timeout"}, {36, __8, "ieee802-3-encapsulation"}, {37, __8, "default-tcp-ttl"}, {38, __32, "tcp-keepalive-interval"}, {39, __8, "tcp-keepalive-garbage"}, {40, __TXT, "nis-domain"}, {41, __IP, "nis-servers"}, {42, __IP, "ntp-servers"}, {43, __VE, "vendor-encapsulated-options"}, {44, __IP, "netbios-name-servers"}, {45, __IP, "netbios-dd-server"}, {46, __8, "netbios-node-type"}, {47, __TXT, "netbios-scope"}, {48, __IP, "x-font-servers"}, {49, __IP, "x-display-managers"}, {50, __IP, "dhcp-requested-address"}, {51, __32, "dhcp-lease-time"}, {52, __8, "dhcp-option-overload"}, {53, __8, "dhcp-message-type"}, {54, __IP, "dhcp-server-identifier"}, {55, __8, "dhcp-parameter-request-list"}, {56, __TXT, "dhcp-message"}, {57, __16, "dhcp-max-message-size"}, {58, __32, "dhcp-renewal-time"}, {59, __32, "dhcp-rebinding-time"}, {60, __TXT, "vendor-class-identifier"}, {61, __TXT, "dhcp-client-identifier"}, {64, __TXT, "nisplus-domain"}, {65, __IP, "nisplus-servers"}, {66, __TXT, "tftp-server-name"}, {67, __TXT, "bootfile-name"}, {68, __IP, "mobile-ip-home-agent"}, {69, __IP, "smtp-server"}, {70, __IP, "pop-server"}, {71, __IP, "nntp-server"}, {72, __IP, "www-server"}, {73, __IP, "finger-server"}, {74, __IP, "irc-server"}, {75, __IP, "streettalk-server"}, {76, __IP, "streettalk-directory-assistance-server"}, {77, __TXT, "user-class"}, {85, __IP, "nds-servers"}, {86, __TXT, "nds-tree-name"}, {87, __TXT, "nds-context"}, {210, __TXT, "authenticate"}, /* use the following entries for arbitrary variables */ {246, __ILIST, ""}, {247, __ILIST, ""}, {248, __ILIST, ""}, {249, __ILIST, ""}, {250, __INDIR, ""}, {251, __INDIR, ""}, {252, __INDIR, ""}, {253, __INDIR, ""}, {254, __INDIR, ""}, {0, __TXT, "%soption-%d"} }; /* * parse a dhcp response, set environment variables translating options * names and values according to the tables above. Also set dhcp.tags * to the list of selected tags. */ static void setenv_(u_char *cp, u_char *ep, struct dhcp_opt *opts) { u_char *ncp; u_char tag; char tags[512], *tp; /* the list of tags */ #define FLD_SEP ',' /* separator in list of elements */ ncp = cp; tp = tags; if (opts == NULL) opts = dhcp_opt; while (ncp < ep) { unsigned int size; /* option size */ char *vp, *endv, buf[256]; /* the value buffer */ struct dhcp_opt *op; tag = *ncp++; /* extract tag and size */ size = *ncp++; cp = ncp; /* current payload */ ncp += size; /* point to the next option */ if (tag == TAG_END) break; if (tag == 0) continue; for (op = opts+1; op->tag && op->tag != tag; op++) ; /* if not found we end up on the default entry */ /* * Copy data into the buffer. libstand does not have snprintf so we * need to be careful with sprintf(). With strings, the source is * always <256 char so shorter than the buffer so we are safe; with * other arguments, the longest string is inet_ntoa which is 16 bytes * so we make sure to have always enough room in the string before * trying an sprint. */ vp = buf; *vp = '\0'; endv = buf + sizeof(buf) - 1 - 16; /* last valid write position */ switch(op->fmt) { case __NONE: break; /* should not happen */ case __VE: /* recurse, vendor specific */ setenv_(cp, cp+size, vndr_opt); break; case __IP: /* ip address */ for (; size > 0 && vp < endv; size -= 4, cp += 4) { struct in_addr in_ip; /* ip addresses */ if (vp != buf) *vp++ = FLD_SEP; bcopy(cp, &in_ip.s_addr, sizeof(in_ip.s_addr)); sprintf(vp, "%s", inet_ntoa(in_ip)); vp += strlen(vp); } break; case __BYTES: /* opaque byte string */ for (; size > 0 && vp < endv; size -= 1, cp += 1) { sprintf(vp, "%02x", *cp); vp += strlen(vp); } break; case __TXT: bcopy(cp, buf, size); /* cannot overflow */ buf[size] = 0; break; case __32: case __16: case __8: /* op->fmt is also the length of each field */ for (; size > 0 && vp < endv; size -= op->fmt, cp += op->fmt) { uint32_t v; if (op->fmt == __32) v = (cp[0]<<24) + (cp[1]<<16) + (cp[2]<<8) + cp[3]; else if (op->fmt == __16) v = (cp[0]<<8) + cp[1]; else v = cp[0]; if (vp != buf) *vp++ = FLD_SEP; sprintf(vp, "%u", v); vp += strlen(vp); } break; case __INDIR: /* name=value */ case __ILIST: /* name=value;name=value... */ bcopy(cp, buf, size); /* cannot overflow */ buf[size] = '\0'; for (endv = buf; endv; endv = vp) { u_char *s = NULL; /* semicolon ? */ /* skip leading whitespace */ while (*endv && strchr(" \t\n\r", *endv)) endv++; vp = strchr(endv, '='); /* find name=value separator */ if (!vp) break; *vp++ = 0; if (op->fmt == __ILIST && (s = strchr(vp, ';'))) *s++ = '\0'; setenv(endv, vp, 1); vp = s; /* prepare for next round */ } buf[0] = '\0'; /* option already done */ } if (tp - tags < sizeof(tags) - 5) { /* add tag to the list */ if (tp != tags) *tp++ = FLD_SEP; sprintf(tp, "%d", tag); tp += strlen(tp); } if (buf[0]) { char env[128]; /* the string name */ if (op->tag == 0) sprintf(env, op->desc, opts[0].desc, tag); else sprintf(env, "%s%s", opts[0].desc, op->desc); /* * Do not replace existing values in the environment, so that * locally-obtained values can override server-provided values. */ setenv(env, buf, 0); } } if (tp != tags) { char env[128]; /* the string name */ sprintf(env, "%stags", opts[0].desc); setenv(env, tags, 1); } } #endif /* additional dhcp */ Index: head/lib/libstand/bootp.h =================================================================== --- head/lib/libstand/bootp.h (revision 317886) +++ head/lib/libstand/bootp.h (revision 317887) @@ -1,152 +1,156 @@ /* $NetBSD: bootp.h,v 1.4 1997/09/06 13:55:57 drochner Exp $ */ /* * Bootstrap Protocol (BOOTP). RFC951 and RFC1048. * * This file specifies the "implementation-independent" BOOTP protocol * information which is common to both client and server. * * Copyright 1988 by Carnegie Mellon. * * Permission to use, copy, modify, and distribute this program for any * purpose and without fee is hereby granted, provided that this copyright * and permission notice appear on all copies and supporting documentation, * the name of Carnegie Mellon not be used in advertising or publicity * pertaining to distribution of the program without specific prior * permission, and notice be given in supporting documentation that copying * and distribution is by permission of Carnegie Mellon and Stanford * University. Carnegie Mellon makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * $FreeBSD$ */ #ifndef _BOOTP_H_ #define _BOOTP_H_ struct bootp { unsigned char bp_op; /* packet opcode type */ unsigned char bp_htype; /* hardware addr type */ unsigned char bp_hlen; /* hardware addr length */ unsigned char bp_hops; /* gateway hops */ unsigned int bp_xid; /* transaction ID */ unsigned short bp_secs; /* seconds since boot began */ unsigned short bp_flags; struct in_addr bp_ciaddr; /* client IP address */ struct in_addr bp_yiaddr; /* 'your' IP address */ struct in_addr bp_siaddr; /* server IP address */ struct in_addr bp_giaddr; /* gateway IP address */ unsigned char bp_chaddr[16]; /* client hardware address */ unsigned char bp_sname[64]; /* server host name */ unsigned char bp_file[128]; /* boot file name */ #ifdef SUPPORT_DHCP #define BOOTP_VENDSIZE 312 #else #define BOOTP_VENDSIZE 64 #endif unsigned char bp_vend[BOOTP_VENDSIZE]; /* vendor-specific area */ }; /* * UDP port numbers, server and client. */ #define IPPORT_BOOTPS 67 #define IPPORT_BOOTPC 68 #define BOOTREPLY 2 #define BOOTREQUEST 1 /* * Vendor magic cookie (v_magic) for CMU */ #define VM_CMU "CMU" /* * Vendor magic cookie (v_magic) for RFC1048 */ #define VM_RFC1048 { 99, 130, 83, 99 } /* * RFC1048 tag values used to specify what information is being supplied in * the vendor field of the packet. */ #define TAG_PAD ((unsigned char) 0) #define TAG_SUBNET_MASK ((unsigned char) 1) #define TAG_TIME_OFFSET ((unsigned char) 2) #define TAG_GATEWAY ((unsigned char) 3) #define TAG_TIME_SERVER ((unsigned char) 4) #define TAG_NAME_SERVER ((unsigned char) 5) #define TAG_DOMAIN_SERVER ((unsigned char) 6) #define TAG_LOG_SERVER ((unsigned char) 7) #define TAG_COOKIE_SERVER ((unsigned char) 8) #define TAG_LPR_SERVER ((unsigned char) 9) #define TAG_IMPRESS_SERVER ((unsigned char) 10) #define TAG_RLP_SERVER ((unsigned char) 11) #define TAG_HOSTNAME ((unsigned char) 12) #define TAG_BOOTSIZE ((unsigned char) 13) #define TAG_DUMPFILE ((unsigned char) 14) #define TAG_DOMAINNAME ((unsigned char) 15) #define TAG_SWAPSERVER ((unsigned char) 16) #define TAG_ROOTPATH ((unsigned char) 17) #define TAG_INTF_MTU ((unsigned char) 26) #ifdef SUPPORT_DHCP #define TAG_REQ_ADDR ((unsigned char) 50) #define TAG_LEASETIME ((unsigned char) 51) #define TAG_OVERLOAD ((unsigned char) 52) #define TAG_DHCP_MSGTYPE ((unsigned char) 53) #define TAG_SERVERID ((unsigned char) 54) #define TAG_PARAM_REQ ((unsigned char) 55) #define TAG_MSG ((unsigned char) 56) #define TAG_MAXSIZE ((unsigned char) 57) #define TAG_T1 ((unsigned char) 58) #define TAG_T2 ((unsigned char) 59) #define TAG_CLASSID ((unsigned char) 60) #define TAG_CLIENTID ((unsigned char) 61) #endif #define TAG_END ((unsigned char) 255) #ifdef SUPPORT_DHCP #define DHCPDISCOVER 1 #define DHCPOFFER 2 #define DHCPREQUEST 3 #define DHCPDECLINE 4 #define DHCPACK 5 #define DHCPNAK 6 #define DHCPRELEASE 7 #endif /* * bootp flags */ #define BOOTP_NONE 0x0000 /* No flags */ #define BOOTP_PXE 0x0001 /* Booting from PXE. */ /* * "vendor" data permitted for CMU bootp clients. */ struct cmu_vend { unsigned char v_magic[4]; /* magic number */ unsigned int v_flags; /* flags/opcodes, etc. */ struct in_addr v_smask; /* Subnet mask */ struct in_addr v_dgate; /* Default gateway */ struct in_addr v_dns1, v_dns2; /* Domain name servers */ struct in_addr v_ins1, v_ins2; /* IEN-116 name servers */ struct in_addr v_ts1, v_ts2; /* Time servers */ unsigned char v_unused[25]; /* currently unused */ }; /* v_flags values */ #define VF_SMASK 1 /* Subnet mask field contains valid data */ +/* cached bootp response/dhcp ack */ +extern struct bootp *bootp_response; +extern size_t bootp_response_size; + int dhcp_try_rfc1048(u_char *cp, u_int len); #endif /* _BOOTP_H_ */ Index: head/lib/libstand/bootparam.c =================================================================== --- head/lib/libstand/bootparam.c (revision 317886) +++ head/lib/libstand/bootparam.c (revision 317887) @@ -1,452 +1,435 @@ /* $NetBSD: bootparam.c,v 1.11 1997/06/26 19:11:32 drochner Exp $ */ /* * Copyright (c) 1995 Gordon W. Ross * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * 4. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Gordon W. Ross * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /* * RPC/bootparams */ #include #include #include #include #include #include #include "rpcv2.h" #include "stand.h" #include "net.h" #include "netif.h" #include "rpc.h" #include "bootparam.h" #ifdef DEBUG_RPC #define RPC_PRINTF(a) printf a #else #define RPC_PRINTF(a) #endif struct in_addr bp_server_addr; /* net order */ n_short bp_server_port; /* net order */ /* * RPC definitions for bootparamd */ #define BOOTPARAM_PROG 100026 #define BOOTPARAM_VERS 1 #define BOOTPARAM_WHOAMI 1 #define BOOTPARAM_GETFILE 2 /* * Inet address in RPC messages * (Note, really four ints, NOT chars. Blech.) */ struct xdr_inaddr { u_int32_t atype; int32_t addr[4]; }; int xdr_inaddr_encode(char **p, struct in_addr ia); int xdr_inaddr_decode(char **p, struct in_addr *ia); int xdr_string_encode(char **p, char *str, int len); int xdr_string_decode(char **p, char *str, int *len_p); /* * RPC: bootparam/whoami * Given client IP address, get: * client name (hostname) * domain name (domainname) * gateway address * * The hostname and domainname are set here for convenience. * * Note - bpsin is initialized to the broadcast address, * and will be replaced with the bootparam server address * after this call is complete. Have to use PMAP_PROC_CALL * to make sure we get responses only from a servers that * know about us (don't want to broadcast a getport call). */ int -bp_whoami(sockfd) - int sockfd; +bp_whoami(int sockfd) { /* RPC structures for PMAPPROC_CALLIT */ struct args { u_int32_t prog; u_int32_t vers; u_int32_t proc; u_int32_t arglen; struct xdr_inaddr xina; } *args; struct repl { u_int16_t _pad; u_int16_t port; u_int32_t encap_len; /* encapsulated data here */ n_long capsule[64]; } *repl; struct { n_long h[RPC_HEADER_WORDS]; struct args d; } sdata; - struct { - n_long h[RPC_HEADER_WORDS]; - struct repl d; - } rdata; char *send_tail, *recv_head; struct iodesc *d; - int len, x; + void *pkt; + int len, x, rc; RPC_PRINTF(("bp_whoami: myip=%s\n", inet_ntoa(myip))); + rc = -1; if (!(d = socktodesc(sockfd))) { RPC_PRINTF(("bp_whoami: bad socket. %d\n", sockfd)); - return (-1); + return (rc); } args = &sdata.d; - repl = &rdata.d; /* * Build request args for PMAPPROC_CALLIT. */ args->prog = htonl(BOOTPARAM_PROG); args->vers = htonl(BOOTPARAM_VERS); args->proc = htonl(BOOTPARAM_WHOAMI); args->arglen = htonl(sizeof(struct xdr_inaddr)); send_tail = (char*) &args->xina; /* * append encapsulated data (client IP address) */ if (xdr_inaddr_encode(&send_tail, myip)) - return (-1); + return (rc); /* RPC: portmap/callit */ d->myport = htons(--rpc_port); d->destip.s_addr = INADDR_BROADCAST; /* XXX: subnet bcast? */ /* rpc_call will set d->destport */ + pkt = NULL; len = rpc_call(d, PMAPPROG, PMAPVERS, PMAPPROC_CALLIT, - args, send_tail - (char*)args, - repl, sizeof(*repl)); + args, send_tail - (char*)args, (void **)&repl, &pkt); if (len < 8) { printf("bootparamd: 'whoami' call failed\n"); - return (-1); + goto done; } /* Save bootparam server address (from IP header). */ rpc_fromaddr(repl, &bp_server_addr, &bp_server_port); /* * Note that bp_server_port is now 111 due to the * indirect call (using PMAPPROC_CALLIT), so get the * actual port number from the reply data. */ bp_server_port = repl->port; RPC_PRINTF(("bp_whoami: server at %s:%d\n", inet_ntoa(bp_server_addr), ntohs(bp_server_port))); /* We have just done a portmap call, so cache the portnum. */ rpc_pmap_putcache(bp_server_addr, BOOTPARAM_PROG, BOOTPARAM_VERS, (int)ntohs(bp_server_port)); /* * Parse the encapsulated results from bootparam/whoami */ x = ntohl(repl->encap_len); if (len < x) { printf("bp_whoami: short reply, %d < %d\n", len, x); - return (-1); + goto done; } recv_head = (char*) repl->capsule; /* client name */ hostnamelen = MAXHOSTNAMELEN-1; if (xdr_string_decode(&recv_head, hostname, &hostnamelen)) { RPC_PRINTF(("bp_whoami: bad hostname\n")); - return (-1); + goto done; } /* domain name */ domainnamelen = MAXHOSTNAMELEN-1; if (xdr_string_decode(&recv_head, domainname, &domainnamelen)) { RPC_PRINTF(("bp_whoami: bad domainname\n")); - return (-1); + goto done; } /* gateway address */ if (xdr_inaddr_decode(&recv_head, &gateip)) { RPC_PRINTF(("bp_whoami: bad gateway\n")); - return (-1); + goto done; } /* success */ - return(0); + rc = 0; +done: + free(pkt); + return (rc); } /* * RPC: bootparam/getfile * Given client name and file "key", get: * server name * server IP address * server pathname */ int -bp_getfile(sockfd, key, serv_addr, pathname) - int sockfd; - char *key; - char *pathname; - struct in_addr *serv_addr; +bp_getfile(int sockfd, char *key, struct in_addr *serv_addr, char *pathname) { struct { n_long h[RPC_HEADER_WORDS]; n_long d[64]; } sdata; - struct { - n_long h[RPC_HEADER_WORDS]; - n_long d[128]; - } rdata; + void *pkt; char serv_name[FNAME_SIZE]; - char *send_tail, *recv_head; + char *rdata, *send_tail; /* misc... */ struct iodesc *d; - int sn_len, path_len, rlen; + int rc = -1, sn_len, path_len, rlen; if (!(d = socktodesc(sockfd))) { RPC_PRINTF(("bp_getfile: bad socket. %d\n", sockfd)); return (-1); } send_tail = (char*) sdata.d; - recv_head = (char*) rdata.d; /* * Build request message. */ /* client name (hostname) */ if (xdr_string_encode(&send_tail, hostname, hostnamelen)) { RPC_PRINTF(("bp_getfile: bad client\n")); return (-1); } /* key name (root or swap) */ if (xdr_string_encode(&send_tail, key, strlen(key))) { RPC_PRINTF(("bp_getfile: bad key\n")); return (-1); } /* RPC: bootparam/getfile */ d->myport = htons(--rpc_port); d->destip = bp_server_addr; /* rpc_call will set d->destport */ - + pkt = NULL; rlen = rpc_call(d, BOOTPARAM_PROG, BOOTPARAM_VERS, BOOTPARAM_GETFILE, sdata.d, send_tail - (char*)sdata.d, - rdata.d, sizeof(rdata.d)); + (void **)&rdata, &pkt); if (rlen < 4) { RPC_PRINTF(("bp_getfile: short reply\n")); errno = EBADRPC; - return (-1); + goto done; } - recv_head = (char*) rdata.d; /* * Parse result message. */ /* server name */ sn_len = FNAME_SIZE-1; - if (xdr_string_decode(&recv_head, serv_name, &sn_len)) { + if (xdr_string_decode(&rdata, serv_name, &sn_len)) { RPC_PRINTF(("bp_getfile: bad server name\n")); - return (-1); + goto done; } /* server IP address (mountd/NFS) */ - if (xdr_inaddr_decode(&recv_head, serv_addr)) { + if (xdr_inaddr_decode(&rdata, serv_addr)) { RPC_PRINTF(("bp_getfile: bad server addr\n")); - return (-1); + goto done; } /* server pathname */ path_len = MAXPATHLEN-1; - if (xdr_string_decode(&recv_head, pathname, &path_len)) { + if (xdr_string_decode(&rdata, pathname, &path_len)) { RPC_PRINTF(("bp_getfile: bad server path\n")); - return (-1); + goto done; } /* success */ - return(0); + rc = 0; +done: + free(pkt); + return (rc); } /* * eXternal Data Representation routines. * (but with non-standard args...) */ int -xdr_string_encode(pkt, str, len) - char **pkt; - char *str; - int len; +xdr_string_encode(char **pkt, char *str, int len) { - u_int32_t *lenp; + uint32_t *lenp; char *datap; int padlen = (len + 3) & ~3; /* padded length */ /* The data will be int aligned. */ - lenp = (u_int32_t*) *pkt; + lenp = (uint32_t *) *pkt; *pkt += sizeof(*lenp); *lenp = htonl(len); datap = *pkt; *pkt += padlen; bcopy(str, datap, len); return (0); } int -xdr_string_decode(pkt, str, len_p) - char **pkt; - char *str; - int *len_p; /* bufsize - 1 */ +xdr_string_decode(char **pkt, char *str, int *len_p) { - u_int32_t *lenp; + uint32_t *lenp; char *datap; int slen; /* string length */ int plen; /* padded length */ /* The data will be int aligned. */ - lenp = (u_int32_t*) *pkt; + lenp = (uint32_t *) *pkt; *pkt += sizeof(*lenp); slen = ntohl(*lenp); plen = (slen + 3) & ~3; if (slen > *len_p) slen = *len_p; datap = *pkt; *pkt += plen; bcopy(datap, str, slen); str[slen] = '\0'; *len_p = slen; return (0); } int -xdr_inaddr_encode(pkt, ia) - char **pkt; - struct in_addr ia; /* network order */ +xdr_inaddr_encode(char **pkt, struct in_addr ia) { struct xdr_inaddr *xi; u_char *cp; int32_t *ip; union { n_long l; /* network order */ u_char c[4]; } uia; /* The data will be int aligned. */ xi = (struct xdr_inaddr *) *pkt; *pkt += sizeof(*xi); xi->atype = htonl(1); uia.l = ia.s_addr; cp = uia.c; ip = xi->addr; /* * Note: the htonl() calls below DO NOT * imply that uia.l is in host order. * In fact this needs it in net order. */ *ip++ = htonl((unsigned int)*cp++); *ip++ = htonl((unsigned int)*cp++); *ip++ = htonl((unsigned int)*cp++); *ip++ = htonl((unsigned int)*cp++); return (0); } int -xdr_inaddr_decode(pkt, ia) - char **pkt; - struct in_addr *ia; /* network order */ +xdr_inaddr_decode(char **pkt, struct in_addr *ia) { struct xdr_inaddr *xi; u_char *cp; int32_t *ip; union { n_long l; /* network order */ u_char c[4]; } uia; /* The data will be int aligned. */ xi = (struct xdr_inaddr *) *pkt; *pkt += sizeof(*xi); if (xi->atype != htonl(1)) { RPC_PRINTF(("xdr_inaddr_decode: bad addrtype=%d\n", ntohl(xi->atype))); return(-1); } cp = uia.c; ip = xi->addr; /* * Note: the ntohl() calls below DO NOT * imply that uia.l is in host order. * In fact this needs it in net order. */ *cp++ = ntohl(*ip++); *cp++ = ntohl(*ip++); *cp++ = ntohl(*ip++); *cp++ = ntohl(*ip++); ia->s_addr = uia.l; return (0); } Index: head/lib/libstand/ether.c =================================================================== --- head/lib/libstand/ether.c (revision 317886) +++ head/lib/libstand/ether.c (revision 317887) @@ -1,150 +1,147 @@ /* $NetBSD: ether.c,v 1.11 1997/07/07 15:52:50 drochner Exp $ */ /* * Copyright (c) 1992 Regents of the University of California. * All rights reserved. * * This software was developed by the Computer Systems Engineering group * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and * contributed to Berkeley. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#) Header: net.c,v 1.9 93/08/06 19:32:15 leres Exp (LBL) */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include "stand.h" #include "net.h" #include "netif.h" /* Caller must leave room for ethernet header in front!! */ ssize_t -sendether(d, pkt, len, dea, etype) - struct iodesc *d; - void *pkt; - size_t len; - u_char *dea; - int etype; +sendether(struct iodesc *d, void *pkt, size_t len, uint8_t *dea, int etype) { ssize_t n; struct ether_header *eh; #ifdef ETHER_DEBUG if (debug) printf("sendether: called\n"); #endif eh = (struct ether_header *)pkt - 1; len += sizeof(*eh); MACPY(d->myea, eh->ether_shost); /* by byte */ MACPY(dea, eh->ether_dhost); /* by byte */ eh->ether_type = htons(etype); n = netif_put(d, eh, len); if (n == -1 || n < sizeof(*eh)) return (-1); n -= sizeof(*eh); return (n); } /* * Get a packet of any Ethernet type, with our address or - * the broadcast address. Save the Ether type in arg 5. - * NOTE: Caller must leave room for the Ether header. + * the broadcast address. Save the Ether type in etype. + * Unless there is an error, we pass the whole packet and the unencapsulated + * data. */ ssize_t -readether(d, pkt, len, tleft, etype) - struct iodesc *d; - void *pkt; - size_t len; - time_t tleft; - u_int16_t *etype; +readether(struct iodesc *d, void **pkt, void **payload, time_t tleft, + uint16_t *etype) { ssize_t n; struct ether_header *eh; + void *ptr; #ifdef ETHER_DEBUG if (debug) printf("readether: called\n"); #endif - eh = (struct ether_header *)pkt - 1; - len += sizeof(*eh); - - n = netif_get(d, eh, len, tleft); - if (n == -1 || n < sizeof(*eh)) + ptr = NULL; + n = netif_get(d, &ptr, tleft); + if (n == -1 || n < sizeof(*eh)) { + free(ptr); return (-1); + } + eh = (struct ether_header *)((uintptr_t)ptr + ETHER_ALIGN); /* Validate Ethernet address. */ if (bcmp(d->myea, eh->ether_dhost, 6) != 0 && bcmp(bcea, eh->ether_dhost, 6) != 0) { #ifdef ETHER_DEBUG if (debug) printf("readether: not ours (ea=%s)\n", ether_sprintf(eh->ether_dhost)); #endif + free(ptr); return (-1); } + + *pkt = ptr; + *payload = (void *)((uintptr_t)eh + sizeof(*eh)); *etype = ntohs(eh->ether_type); n -= sizeof(*eh); return (n); } /* * Convert Ethernet address to printable (loggable) representation. */ static char digits[] = "0123456789abcdef"; char * -ether_sprintf(ap) - u_char *ap; +ether_sprintf(u_char *ap) { int i; static char etherbuf[18]; char *cp = etherbuf; for (i = 0; i < 6; i++) { *cp++ = digits[*ap >> 4]; *cp++ = digits[*ap++ & 0xf]; *cp++ = ':'; } *--cp = 0; return (etherbuf); } Index: head/lib/libstand/net.c =================================================================== --- head/lib/libstand/net.c (revision 317886) +++ head/lib/libstand/net.c (revision 317887) @@ -1,283 +1,283 @@ /* $NetBSD: net.c,v 1.20 1997/12/26 22:41:30 scottr Exp $ */ /* * Copyright (c) 1992 Regents of the University of California. * All rights reserved. * * This software was developed by the Computer Systems Engineering group * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and * contributed to Berkeley. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#) Header: net.c,v 1.9 93/08/06 19:32:15 leres Exp (LBL) */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include "stand.h" #include "net.h" /* * Send a packet and wait for a reply, with exponential backoff. * * The send routine must return the actual number of bytes written, * or -1 on error. * * The receive routine can indicate success by returning the number of * bytes read; it can return 0 to indicate EOF; it can return -1 with a * non-zero errno to indicate failure; finally, it can return -1 with a * zero errno to indicate it isn't done yet. */ ssize_t sendrecv(struct iodesc *d, - ssize_t (*sproc)(struct iodesc *, void *, size_t), - void *sbuf, size_t ssize, - ssize_t (*rproc)(struct iodesc *, void *, size_t, time_t), - void *rbuf, size_t rsize) + ssize_t (*sproc)(struct iodesc *, void *, size_t), + void *sbuf, size_t ssize, + ssize_t (*rproc)(struct iodesc *, void **, void **, time_t), + void **pkt, void **payload) { ssize_t cc; time_t t, tmo, tlast; long tleft; #ifdef NET_DEBUG if (debug) printf("sendrecv: called\n"); #endif tmo = MINTMO; tlast = 0; tleft = 0; t = getsecs(); for (;;) { if (tleft <= 0) { if (tmo >= MAXTMO) { errno = ETIMEDOUT; return -1; } cc = (*sproc)(d, sbuf, ssize); if (cc != -1 && cc < ssize) panic("sendrecv: short write! (%zd < %zd)", cc, ssize); tleft = tmo; tmo += MINTMO; if (tmo > MAXTMO) tmo = MAXTMO; if (cc == -1) { /* Error on transmit; wait before retrying */ while ((getsecs() - t) < tmo) ; tleft = 0; continue; } tlast = t; } /* Try to get a packet and process it. */ - cc = (*rproc)(d, rbuf, rsize, tleft); + cc = (*rproc)(d, pkt, payload, tleft); /* Return on data, EOF or real error. */ if (cc != -1 || errno != 0) return (cc); /* Timed out or didn't get the packet we're waiting for */ t = getsecs(); tleft -= t - tlast; tlast = t; } } /* * Like inet_addr() in the C library, but we only accept base-10. * Return values are in network order. */ n_long inet_addr(char *cp) { u_long val; int n; char c; u_int parts[4]; u_int *pp = parts; for (;;) { /* * Collect number up to ``.''. * Values are specified as for C: * 0x=hex, 0=octal, other=decimal. */ val = 0; while ((c = *cp) != '\0') { if (c >= '0' && c <= '9') { val = (val * 10) + (c - '0'); cp++; continue; } break; } if (*cp == '.') { /* * Internet format: * a.b.c.d * a.b.c (with c treated as 16-bits) * a.b (with b treated as 24 bits) */ if (pp >= parts + 3 || val > 0xff) goto bad; *pp++ = val, cp++; } else break; } /* * Check for trailing characters. */ if (*cp != '\0') goto bad; /* * Concoct the address according to * the number of parts specified. */ n = pp - parts + 1; switch (n) { case 1: /* a -- 32 bits */ break; case 2: /* a.b -- 8.24 bits */ if (val > 0xffffff) goto bad; val |= parts[0] << 24; break; case 3: /* a.b.c -- 8.8.16 bits */ if (val > 0xffff) goto bad; val |= (parts[0] << 24) | (parts[1] << 16); break; case 4: /* a.b.c.d -- 8.8.8.8 bits */ if (val > 0xff) goto bad; val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); break; } return (htonl(val)); bad: return (htonl(INADDR_NONE)); } char * inet_ntoa(struct in_addr ia) { return (intoa(ia.s_addr)); } /* Similar to inet_ntoa() */ char * intoa(n_long addr) { char *cp; u_int byte; int n; static char buf[17]; /* strlen(".255.255.255.255") + 1 */ addr = ntohl(addr); cp = &buf[sizeof buf]; *--cp = '\0'; n = 4; do { byte = addr & 0xff; *--cp = byte % 10 + '0'; byte /= 10; if (byte > 0) { *--cp = byte % 10 + '0'; byte /= 10; if (byte > 0) *--cp = byte + '0'; } *--cp = '.'; addr >>= 8; } while (--n > 0); return (cp+1); } static char * number(char *s, int *n) { for (*n = 0; isdigit(*s); s++) *n = (*n * 10) + *s - '0'; return s; } n_long ip_convertaddr(char *p) { #define IP_ANYADDR 0 n_long addr = 0, n; if (p == (char *)0 || *p == '\0') return IP_ANYADDR; p = number(p, &n); addr |= (n << 24) & 0xff000000; if (*p == '\0' || *p++ != '.') return IP_ANYADDR; p = number(p, &n); addr |= (n << 16) & 0xff0000; if (*p == '\0' || *p++ != '.') return IP_ANYADDR; p = number(p, &n); addr |= (n << 8) & 0xff00; if (*p == '\0' || *p++ != '.') return IP_ANYADDR; p = number(p, &n); addr |= n & 0xff; if (*p != '\0') return IP_ANYADDR; return htonl(addr); } Index: head/lib/libstand/net.h =================================================================== --- head/lib/libstand/net.h (revision 317886) +++ head/lib/libstand/net.h (revision 317887) @@ -1,132 +1,131 @@ /* $NetBSD: net.h,v 1.10 1995/10/20 00:46:30 cgd Exp $ */ /* * Copyright (c) 1993 Adam Glass * Copyright (c) 1992 Regents of the University of California. * All rights reserved. * * This software was developed by the Computer Systems Engineering group * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and * contributed to Berkeley. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _STAND_NET_H #define _STAND_NET_H #ifndef _KERNEL /* XXX - see */ #undef __IPADDR #define __IPADDR(x) htonl((u_int32_t)(x)) #endif #include "iodesc.h" #define BA { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } enum net_proto { NET_NONE, NET_NFS, NET_TFTP }; /* Returns true if n_long's on the same net */ #define SAMENET(a1, a2, m) ((a1.s_addr & m) == (a2.s_addr & m)) #define MACPY(s, d) bcopy((char *)s, (char *)d, 6) #define MAXTMO 120 /* seconds */ #define MINTMO 2 /* seconds */ #define FNAME_SIZE 128 #define IFNAME_SIZE 16 #define RECV_SIZE 1536 /* XXX delete this */ /* * How much room to leave for headers: * 14: struct ether_header * 20: struct ip * 8: struct udphdr * That's 42 but let's pad it out to 48 bytes. */ #define ETHER_SIZE 14 #define HEADER_SIZE 48 extern u_char bcea[6]; extern char rootpath[FNAME_SIZE]; extern char bootfile[FNAME_SIZE]; extern char hostname[FNAME_SIZE]; extern int hostnamelen; extern char domainname[FNAME_SIZE]; extern int domainnamelen; extern int netproto; extern char ifname[IFNAME_SIZE]; /* All of these are in network order. */ extern struct in_addr myip; extern struct in_addr rootip; extern struct in_addr swapip; extern struct in_addr gateip; extern struct in_addr nameip; extern n_long netmask; extern u_int intf_mtu; extern int debug; /* defined in the machdep sources */ extern struct iodesc sockets[SOPEN_MAX]; /* ARP/RevARP functions: */ u_char *arpwhohas(struct iodesc *, struct in_addr); void arp_reply(struct iodesc *, void *); int rarp_getipaddress(int); /* Link functions: */ ssize_t sendether(struct iodesc *d, void *pkt, size_t len, u_char *dea, int etype); -ssize_t readether(struct iodesc *d, void *pkt, size_t len, - time_t tleft, u_int16_t *etype); +ssize_t readether(struct iodesc *, void **, void **, time_t, uint16_t *); ssize_t sendudp(struct iodesc *, void *, size_t); -ssize_t readudp(struct iodesc *, void *, size_t, time_t); +ssize_t readudp(struct iodesc *, void **, void **, time_t); ssize_t sendrecv(struct iodesc *, - ssize_t (*)(struct iodesc *, void *, size_t), + ssize_t (*)(struct iodesc *, void *, size_t), void *, size_t, - ssize_t (*)(struct iodesc *, void *, size_t, time_t), - void *, size_t); + ssize_t (*)(struct iodesc *, void **, void **, time_t), + void **, void **); /* bootp/DHCP */ void bootp(int, int); /* Utilities: */ char *ether_sprintf(u_char *); int in_cksum(void *, int); char *inet_ntoa(struct in_addr); char *intoa(n_long); /* similar to inet_ntoa */ n_long inet_addr(char *); /* Machine-dependent functions: */ time_t getsecs(void); #endif /* ! _STAND_NET_H */ Index: head/lib/libstand/netif.c =================================================================== --- head/lib/libstand/netif.c (revision 317886) +++ head/lib/libstand/netif.c (revision 317887) @@ -1,335 +1,316 @@ /* $NetBSD: netif.c,v 1.10 1997/09/06 13:57:14 drochner Exp $ */ /* * Copyright (c) 1993 Adam Glass * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Adam Glass. * 4. The name of the Author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY Adam Glass ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include "stand.h" #include "net.h" #include "netif.h" struct iodesc sockets[SOPEN_MAX]; #ifdef NETIF_DEBUG int netif_debug = 0; #endif /* * netif_init: * * initialize the generic network interface layer */ void -netif_init() +netif_init(void) { struct netif_driver *drv; int d, i; #ifdef NETIF_DEBUG if (netif_debug) printf("netif_init: called\n"); #endif for (d = 0; netif_drivers[d]; d++) { drv = netif_drivers[d]; for (i = 0; i < drv->netif_nifs; i++) drv->netif_ifs[i].dif_used = 0; } } int -netif_match(nif, machdep_hint) - struct netif *nif; - void *machdep_hint; +netif_match(struct netif *nif, void *machdep_hint) { struct netif_driver *drv = nif->nif_driver; -#if 0 +#if NETIF_DEBUG if (netif_debug) printf("%s%d: netif_match (%d)\n", drv->netif_bname, nif->nif_unit, nif->nif_sel); #endif return drv->netif_match(nif, machdep_hint); } struct netif * -netif_select(machdep_hint) - void *machdep_hint; +netif_select(void *machdep_hint) { int d, u, unit_done, s; struct netif_driver *drv; struct netif cur_if; static struct netif best_if; int best_val; int val; best_val = 0; best_if.nif_driver = NULL; for (d = 0; netif_drivers[d] != NULL; d++) { cur_if.nif_driver = netif_drivers[d]; drv = cur_if.nif_driver; for (u = 0; u < drv->netif_nifs; u++) { cur_if.nif_unit = u; unit_done = 0; #ifdef NETIF_DEBUG if (netif_debug) printf("\t%s%d:", drv->netif_bname, cur_if.nif_unit); #endif for (s = 0; s < drv->netif_ifs[u].dif_nsel; s++) { cur_if.nif_sel = s; if (drv->netif_ifs[u].dif_used & (1 << s)) { #ifdef NETIF_DEBUG if (netif_debug) printf(" [%d used]", s); #endif continue; } val = netif_match(&cur_if, machdep_hint); #ifdef NETIF_DEBUG if (netif_debug) printf(" [%d -> %d]", s, val); #endif if (val > best_val) { best_val = val; best_if = cur_if; } } #ifdef NETIF_DEBUG if (netif_debug) printf("\n"); #endif } } if (best_if.nif_driver == NULL) return NULL; best_if.nif_driver-> netif_ifs[best_if.nif_unit].dif_used |= (1 << best_if.nif_sel); #ifdef NETIF_DEBUG if (netif_debug) printf("netif_select: %s%d(%d) wins\n", best_if.nif_driver->netif_bname, best_if.nif_unit, best_if.nif_sel); #endif return &best_if; } int -netif_probe(nif, machdep_hint) - struct netif *nif; - void *machdep_hint; +netif_probe(struct netif *nif, void *machdep_hint) { struct netif_driver *drv = nif->nif_driver; #ifdef NETIF_DEBUG if (netif_debug) printf("%s%d: netif_probe\n", drv->netif_bname, nif->nif_unit); #endif return drv->netif_probe(nif, machdep_hint); } void -netif_attach(nif, desc, machdep_hint) - struct netif *nif; - struct iodesc *desc; - void *machdep_hint; +netif_attach(struct netif *nif, struct iodesc *desc, void *machdep_hint) { struct netif_driver *drv = nif->nif_driver; #ifdef NETIF_DEBUG if (netif_debug) printf("%s%d: netif_attach\n", drv->netif_bname, nif->nif_unit); #endif desc->io_netif = nif; #ifdef PARANOID if (drv->netif_init == NULL) panic("%s%d: no netif_init support\n", drv->netif_bname, nif->nif_unit); #endif drv->netif_init(desc, machdep_hint); bzero(drv->netif_ifs[nif->nif_unit].dif_stats, sizeof(struct netif_stats)); } void -netif_detach(nif) - struct netif *nif; +netif_detach(struct netif *nif) { struct netif_driver *drv = nif->nif_driver; #ifdef NETIF_DEBUG if (netif_debug) printf("%s%d: netif_detach\n", drv->netif_bname, nif->nif_unit); #endif #ifdef PARANOID if (drv->netif_end == NULL) panic("%s%d: no netif_end support\n", drv->netif_bname, nif->nif_unit); #endif drv->netif_end(nif); } ssize_t -netif_get(desc, pkt, len, timo) - struct iodesc *desc; - void *pkt; - size_t len; - time_t timo; +netif_get(struct iodesc *desc, void **pkt, time_t timo) { #ifdef NETIF_DEBUG struct netif *nif = desc->io_netif; #endif struct netif_driver *drv = desc->io_netif->nif_driver; ssize_t rv; #ifdef NETIF_DEBUG if (netif_debug) printf("%s%d: netif_get\n", drv->netif_bname, nif->nif_unit); #endif #ifdef PARANOID if (drv->netif_get == NULL) panic("%s%d: no netif_get support\n", drv->netif_bname, nif->nif_unit); #endif - rv = drv->netif_get(desc, pkt, len, timo); + rv = drv->netif_get(desc, pkt, timo); #ifdef NETIF_DEBUG if (netif_debug) printf("%s%d: netif_get returning %d\n", drv->netif_bname, nif->nif_unit, (int)rv); #endif - return rv; + return (rv); } ssize_t -netif_put(desc, pkt, len) - struct iodesc *desc; - void *pkt; - size_t len; +netif_put(struct iodesc *desc, void *pkt, size_t len) { #ifdef NETIF_DEBUG struct netif *nif = desc->io_netif; #endif struct netif_driver *drv = desc->io_netif->nif_driver; ssize_t rv; #ifdef NETIF_DEBUG if (netif_debug) printf("%s%d: netif_put\n", drv->netif_bname, nif->nif_unit); #endif #ifdef PARANOID if (drv->netif_put == NULL) panic("%s%d: no netif_put support\n", drv->netif_bname, nif->nif_unit); #endif rv = drv->netif_put(desc, pkt, len); #ifdef NETIF_DEBUG if (netif_debug) printf("%s%d: netif_put returning %d\n", drv->netif_bname, nif->nif_unit, (int)rv); #endif - return rv; + return (rv); } struct iodesc * -socktodesc(sock) - int sock; +socktodesc(int sock) { if (sock >= SOPEN_MAX) { errno = EBADF; return (NULL); } return (&sockets[sock]); } int -netif_open(machdep_hint) - void *machdep_hint; +netif_open(void *machdep_hint) { int fd; struct iodesc *s; struct netif *nif; /* find a free socket */ for (fd = 0, s = sockets; fd < SOPEN_MAX; fd++, s++) if (s->io_netif == (struct netif *)0) goto fnd; errno = EMFILE; return (-1); fnd: bzero(s, sizeof(*s)); netif_init(); nif = netif_select(machdep_hint); if (!nif) panic("netboot: no interfaces left untried"); if (netif_probe(nif, machdep_hint)) { printf("netboot: couldn't probe %s%d\n", nif->nif_driver->netif_bname, nif->nif_unit); errno = EINVAL; - return(-1); + return (-1); } netif_attach(nif, s, machdep_hint); - return(fd); + return (fd); } int -netif_close(sock) - int sock; +netif_close(int sock) { if (sock >= SOPEN_MAX) { errno = EBADF; - return(-1); + return (-1); } netif_detach(sockets[sock].io_netif); sockets[sock].io_netif = (struct netif *)0; - return(0); + return (0); } Index: head/lib/libstand/netif.h =================================================================== --- head/lib/libstand/netif.h (revision 317886) +++ head/lib/libstand/netif.h (revision 317887) @@ -1,67 +1,65 @@ /* $NetBSD: netif.h,v 1.4 1995/09/14 23:45:30 pk Exp $ */ /* $FreeBSD$ */ #ifndef __SYS_LIBNETBOOT_NETIF_H #define __SYS_LIBNETBOOT_NETIF_H #include "iodesc.h" -#define NENTS(x) sizeof(x)/sizeof(x[0]) - struct netif_driver { const char *netif_bname; int (*netif_match)(struct netif *, void *); int (*netif_probe)(struct netif *, void *); void (*netif_init)(struct iodesc *, void *); - int (*netif_get)(struct iodesc *, void *, size_t, time_t); - int (*netif_put)(struct iodesc *, void *, size_t); + ssize_t (*netif_get)(struct iodesc *, void **, time_t); + ssize_t (*netif_put)(struct iodesc *, void *, size_t); void (*netif_end)(struct netif *); struct netif_dif *netif_ifs; int netif_nifs; }; struct netif_dif { int dif_unit; int dif_nsel; struct netif_stats *dif_stats; void *dif_private; /* the following fields are used internally by the netif layer */ u_long dif_used; }; struct netif_stats { int collisions; int collision_error; int missed; int sent; int received; int deferred; int overflow; }; struct netif { struct netif_driver *nif_driver; int nif_unit; int nif_sel; void *nif_devdata; }; extern struct netif_driver *netif_drivers[]; /* machdep */ extern int n_netif_drivers; extern int netif_debug; void netif_init(void); struct netif *netif_select(void *); int netif_probe(struct netif *, void *); void netif_attach(struct netif *, struct iodesc *, void *); void netif_detach(struct netif *); -ssize_t netif_get(struct iodesc *, void *, size_t, time_t); +ssize_t netif_get(struct iodesc *, void **, time_t); ssize_t netif_put(struct iodesc *, void *, size_t); int netif_open(void *); int netif_close(int); struct iodesc *socktodesc(int); #endif /* __SYS_LIBNETBOOT_NETIF_H */ Index: head/lib/libstand/nfs.c =================================================================== --- head/lib/libstand/nfs.c (revision 317886) +++ head/lib/libstand/nfs.c (revision 317887) @@ -1,845 +1,860 @@ /* $NetBSD: nfs.c,v 1.2 1998/01/24 12:43:09 drochner Exp $ */ /*- * Copyright (c) 1993 John Brezak * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include "rpcv2.h" #include "nfsv2.h" #include "stand.h" #include "net.h" #include "netif.h" #include "rpc.h" #define NFS_DEBUGxx #define NFSREAD_MIN_SIZE 1024 #define NFSREAD_MAX_SIZE 4096 /* NFSv3 definitions */ #define NFS_V3MAXFHSIZE 64 #define NFS_VER3 3 #define RPCMNT_VER3 3 #define NFSPROCV3_LOOKUP 3 #define NFSPROCV3_READLINK 5 #define NFSPROCV3_READ 6 #define NFSPROCV3_READDIR 16 typedef struct { uint32_t val[2]; } n_quad; struct nfsv3_time { uint32_t nfs_sec; uint32_t nfs_nsec; }; struct nfsv3_fattrs { uint32_t fa_type; uint32_t fa_mode; uint32_t fa_nlink; uint32_t fa_uid; uint32_t fa_gid; n_quad fa_size; n_quad fa_used; n_quad fa_rdev; n_quad fa_fsid; n_quad fa_fileid; struct nfsv3_time fa_atime; struct nfsv3_time fa_mtime; struct nfsv3_time fa_ctime; }; /* * For NFSv3, the file handle is variable in size, so most fixed sized * structures for arguments won't work. For most cases, a structure * that starts with any fixed size section is followed by an array * that covers the maximum size required. */ struct nfsv3_readdir_repl { uint32_t errno; uint32_t ok; struct nfsv3_fattrs fa; uint32_t cookiev0; uint32_t cookiev1; }; struct nfsv3_readdir_entry { uint32_t follows; uint32_t fid0; uint32_t fid1; uint32_t len; uint32_t nameplus[0]; }; struct nfs_iodesc { struct iodesc *iodesc; off_t off; uint32_t fhsize; u_char fh[NFS_V3MAXFHSIZE]; struct nfsv3_fattrs fa; /* all in network order */ uint64_t cookie; }; /* * XXX interactions with tftp? See nfswrapper.c for a confusing * issue. */ int nfs_open(const char *path, struct open_file *f); static int nfs_close(struct open_file *f); static int nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid); static int nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid); static off_t nfs_seek(struct open_file *f, off_t offset, int where); static int nfs_stat(struct open_file *f, struct stat *sb); static int nfs_readdir(struct open_file *f, struct dirent *d); struct nfs_iodesc nfs_root_node; struct fs_ops nfs_fsops = { "nfs", nfs_open, nfs_close, nfs_read, nfs_write, nfs_seek, nfs_stat, nfs_readdir }; static int nfs_read_size = NFSREAD_MIN_SIZE; /* * Improve boot performance over NFS */ static void set_nfs_read_size(void) { char *env, *end; char buf[10]; if ((env = getenv("nfs.read_size")) != NULL) { errno = 0; nfs_read_size = (int)strtol(env, &end, 0); if (errno != 0 || *env == '\0' || *end != '\0') { printf("%s: bad value: \"%s\", defaulting to %d\n", "nfs.read_size", env, NFSREAD_MIN_SIZE); nfs_read_size = NFSREAD_MIN_SIZE; } } if (nfs_read_size < NFSREAD_MIN_SIZE) { printf("%s: bad value: \"%d\", defaulting to %d\n", "nfs.read_size", nfs_read_size, NFSREAD_MIN_SIZE); nfs_read_size = NFSREAD_MIN_SIZE; } if (nfs_read_size > NFSREAD_MAX_SIZE) { printf("%s: bad value: \"%d\", defaulting to %d\n", "nfs.read_size", nfs_read_size, NFSREAD_MIN_SIZE); nfs_read_size = NFSREAD_MAX_SIZE; } snprintf(buf, sizeof (buf), "%d", nfs_read_size); setenv("nfs.read_size", buf, 1); } /* * Fetch the root file handle (call mount daemon) * Return zero or error number. */ int nfs_getrootfh(struct iodesc *d, char *path, uint32_t *fhlenp, u_char *fhp) { + void *pkt = NULL; int len; struct args { uint32_t len; char path[FNAME_SIZE]; } *args; struct repl { uint32_t errno; uint32_t fhsize; u_char fh[NFS_V3MAXFHSIZE]; uint32_t authcnt; uint32_t auth[7]; } *repl; struct { uint32_t h[RPC_HEADER_WORDS]; struct args d; } sdata; - struct { - uint32_t h[RPC_HEADER_WORDS]; - struct repl d; - } rdata; size_t cc; #ifdef NFS_DEBUG if (debug) printf("nfs_getrootfh: %s\n", path); #endif args = &sdata.d; - repl = &rdata.d; bzero(args, sizeof(*args)); len = strlen(path); if (len > sizeof(args->path)) len = sizeof(args->path); args->len = htonl(len); bcopy(path, args->path, len); len = sizeof(uint32_t) + roundup(len, sizeof(uint32_t)); cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER3, RPCMNT_MOUNT, - args, len, repl, sizeof(*repl)); - if (cc == -1) + args, len, (void **)&repl, &pkt); + if (cc == -1) { + free(pkt); /* errno was set by rpc_call */ return (errno); - if (cc < 2 * sizeof (uint32_t)) + } + if (cc < 2 * sizeof (uint32_t)) { + free(pkt); return (EBADRPC); - if (repl->errno != 0) + } + if (repl->errno != 0) { + free(pkt); return (ntohl(repl->errno)); + } *fhlenp = ntohl(repl->fhsize); bcopy(repl->fh, fhp, *fhlenp); set_nfs_read_size(); + free(pkt); return (0); } /* * Lookup a file. Store handle and attributes. * Return zero or error number. */ int nfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd) { + void *pkt = NULL; int len, rlen, pos; struct args { uint32_t fhsize; uint32_t fhplusname[1 + (NFS_V3MAXFHSIZE + FNAME_SIZE) / sizeof(uint32_t)]; } *args; struct repl { uint32_t errno; uint32_t fhsize; uint32_t fhplusattr[(NFS_V3MAXFHSIZE + 2 * (sizeof(uint32_t) + sizeof(struct nfsv3_fattrs))) / sizeof(uint32_t)]; } *repl; struct { uint32_t h[RPC_HEADER_WORDS]; struct args d; } sdata; - struct { - uint32_t h[RPC_HEADER_WORDS]; - struct repl d; - } rdata; ssize_t cc; #ifdef NFS_DEBUG if (debug) printf("lookupfh: called\n"); #endif args = &sdata.d; - repl = &rdata.d; bzero(args, sizeof(*args)); args->fhsize = htonl(d->fhsize); bcopy(d->fh, args->fhplusname, d->fhsize); len = strlen(name); if (len > FNAME_SIZE) len = FNAME_SIZE; pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); args->fhplusname[pos++] = htonl(len); bcopy(name, &args->fhplusname[pos], len); len = sizeof(uint32_t) + pos * sizeof(uint32_t) + roundup(len, sizeof(uint32_t)); - rlen = sizeof(*repl); - cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_LOOKUP, - args, len, repl, rlen); - if (cc == -1) + args, len, (void **)&repl, &pkt); + if (cc == -1) { + free(pkt); return (errno); /* XXX - from rpc_call */ - if (cc < 2 * sizeof(uint32_t)) + } + if (cc < 2 * sizeof(uint32_t)) { + free(pkt); return (EIO); - if (repl->errno != 0) + } + if (repl->errno != 0) { + free(pkt); /* saerrno.h now matches NFS error numbers. */ return (ntohl(repl->errno)); + } newfd->fhsize = ntohl(repl->fhsize); bcopy(repl->fhplusattr, &newfd->fh, newfd->fhsize); pos = roundup(newfd->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); - if (repl->fhplusattr[pos++] == 0) + if (repl->fhplusattr[pos++] == 0) { + free(pkt); return (EIO); + } bcopy(&repl->fhplusattr[pos], &newfd->fa, sizeof(newfd->fa)); + free(pkt); return (0); } #ifndef NFS_NOSYMLINK /* * Get the destination of a symbolic link. */ int nfs_readlink(struct nfs_iodesc *d, char *buf) { + void *pkt = NULL; struct args { uint32_t fhsize; u_char fh[NFS_V3MAXFHSIZE]; } *args; struct repl { uint32_t errno; uint32_t ok; struct nfsv3_fattrs fa; uint32_t len; u_char path[NFS_MAXPATHLEN]; } *repl; struct { uint32_t h[RPC_HEADER_WORDS]; struct args d; } sdata; - struct { - uint32_t h[RPC_HEADER_WORDS]; - struct repl d; - } rdata; ssize_t cc; + int rc = 0; #ifdef NFS_DEBUG if (debug) printf("readlink: called\n"); #endif args = &sdata.d; - repl = &rdata.d; bzero(args, sizeof(*args)); args->fhsize = htonl(d->fhsize); bcopy(d->fh, args->fh, d->fhsize); cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READLINK, args, sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)), - repl, sizeof(*repl)); + (void **)&repl, &pkt); if (cc == -1) return (errno); - if (cc < 2 * sizeof(uint32_t)) - return (EIO); + if (cc < 2 * sizeof(uint32_t)) { + rc = EIO; + goto done; + } - if (repl->errno != 0) - return (ntohl(repl->errno)); + if (repl->errno != 0) { + rc = ntohl(repl->errno); + goto done; + } - if (repl->ok == 0) - return (EIO); + if (repl->ok == 0) { + rc = EIO; + goto done; + } repl->len = ntohl(repl->len); - if (repl->len > NFS_MAXPATHLEN) - return (ENAMETOOLONG); + if (repl->len > NFS_MAXPATHLEN) { + rc = ENAMETOOLONG; + goto done; + } bcopy(repl->path, buf, repl->len); buf[repl->len] = 0; +done: + free(pkt); return (0); } #endif /* * Read data from a file. * Return transfer count or -1 (and set errno) */ ssize_t nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len) { + void *pkt = NULL; struct args { uint32_t fhsize; uint32_t fhoffcnt[NFS_V3MAXFHSIZE / sizeof(uint32_t) + 3]; } *args; struct repl { uint32_t errno; uint32_t ok; struct nfsv3_fattrs fa; uint32_t count; uint32_t eof; uint32_t len; u_char data[NFSREAD_MAX_SIZE]; } *repl; struct { uint32_t h[RPC_HEADER_WORDS]; struct args d; } sdata; - struct { - uint32_t h[RPC_HEADER_WORDS]; - struct repl d; - } rdata; size_t cc; long x; int hlen, rlen, pos; args = &sdata.d; - repl = &rdata.d; bzero(args, sizeof(*args)); args->fhsize = htonl(d->fhsize); bcopy(d->fh, args->fhoffcnt, d->fhsize); pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); args->fhoffcnt[pos++] = 0; args->fhoffcnt[pos++] = htonl((uint32_t)off); if (len > nfs_read_size) len = nfs_read_size; args->fhoffcnt[pos] = htonl((uint32_t)len); hlen = offsetof(struct repl, data[0]); cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READ, args, 4 * sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)), - repl, sizeof(*repl)); - if (cc == -1) + (void **)&repl, &pkt); + if (cc == -1) { /* errno was already set by rpc_call */ return (-1); + } if (cc < hlen) { errno = EBADRPC; + free(pkt); return (-1); } if (repl->errno != 0) { errno = ntohl(repl->errno); + free(pkt); return (-1); } rlen = cc - hlen; x = ntohl(repl->count); if (rlen < x) { printf("nfsread: short packet, %d < %ld\n", rlen, x); errno = EBADRPC; + free(pkt); return (-1); } bcopy(repl->data, addr, x); + free(pkt); return (x); } /* * Open a file. * return zero or error number */ int nfs_open(const char *upath, struct open_file *f) { struct iodesc *desc; struct nfs_iodesc *currfd; char buf[2 * NFS_V3MAXFHSIZE + 3]; u_char *fh; char *cp; int i; #ifndef NFS_NOSYMLINK struct nfs_iodesc *newfd; struct nfsv3_fattrs *fa; char *ncp; int c; char namebuf[NFS_MAXPATHLEN + 1]; char linkbuf[NFS_MAXPATHLEN + 1]; int nlinks = 0; #endif int error; char *path; if (netproto != NET_NFS) return (EINVAL); #ifdef NFS_DEBUG if (debug) printf("nfs_open: %s (rootpath=%s)\n", upath, rootpath); #endif if (!rootpath[0]) { printf("no rootpath, no nfs\n"); return (ENXIO); } - /* - * This is silly - we should look at dv_type but that value is - * arch dependant and we can't use it here. - */ -#ifndef __i386__ - if (strcmp(f->f_dev->dv_name, "net") != 0) + if (f->f_dev->dv_type != DEVT_NET) return (EINVAL); -#else - if (strcmp(f->f_dev->dv_name, "pxe") != 0) - return (EINVAL); -#endif if (!(desc = socktodesc(*(int *)(f->f_devdata)))) return (EINVAL); /* Bind to a reserved port. */ desc->myport = htons(--rpc_port); desc->destip = rootip; if ((error = nfs_getrootfh(desc, rootpath, &nfs_root_node.fhsize, nfs_root_node.fh))) return (error); nfs_root_node.fa.fa_type = htonl(NFDIR); nfs_root_node.fa.fa_mode = htonl(0755); nfs_root_node.fa.fa_nlink = htonl(2); nfs_root_node.iodesc = desc; fh = &nfs_root_node.fh[0]; buf[0] = 'X'; cp = &buf[1]; for (i = 0; i < nfs_root_node.fhsize; i++, cp += 2) sprintf(cp, "%02x", fh[i]); sprintf(cp, "X"); setenv("boot.nfsroot.server", inet_ntoa(rootip), 1); setenv("boot.nfsroot.path", rootpath, 1); setenv("boot.nfsroot.nfshandle", buf, 1); sprintf(buf, "%d", nfs_root_node.fhsize); setenv("boot.nfsroot.nfshandlelen", buf, 1); /* Allocate file system specific data structure */ currfd = malloc(sizeof(*newfd)); if (currfd == NULL) { error = ENOMEM; goto out; } #ifndef NFS_NOSYMLINK bcopy(&nfs_root_node, currfd, sizeof(*currfd)); newfd = NULL; cp = path = strdup(upath); if (path == NULL) { error = ENOMEM; goto out; } while (*cp) { /* * Remove extra separators */ while (*cp == '/') cp++; if (*cp == '\0') break; /* * Check that current node is a directory. */ if (currfd->fa.fa_type != htonl(NFDIR)) { error = ENOTDIR; goto out; } /* allocate file system specific data structure */ newfd = malloc(sizeof(*newfd)); if (newfd == NULL) { error = ENOMEM; goto out; } newfd->iodesc = currfd->iodesc; /* * Get next component of path name. */ { int len = 0; ncp = cp; while ((c = *cp) != '\0' && c != '/') { if (++len > NFS_MAXNAMLEN) { error = ENOENT; goto out; } cp++; } *cp = '\0'; } /* lookup a file handle */ error = nfs_lookupfh(currfd, ncp, newfd); *cp = c; if (error) goto out; /* * Check for symbolic link */ if (newfd->fa.fa_type == htonl(NFLNK)) { int link_len, len; error = nfs_readlink(newfd, linkbuf); if (error) goto out; link_len = strlen(linkbuf); len = strlen(cp); if (link_len + len > MAXPATHLEN || ++nlinks > MAXSYMLINKS) { error = ENOENT; goto out; } bcopy(cp, &namebuf[link_len], len + 1); bcopy(linkbuf, namebuf, link_len); /* * If absolute pathname, restart at root. * If relative pathname, restart at parent directory. */ cp = namebuf; if (*cp == '/') bcopy(&nfs_root_node, currfd, sizeof(*currfd)); free(newfd); newfd = NULL; continue; } free(currfd); currfd = newfd; newfd = NULL; } error = 0; out: free(newfd); free(path); #else currfd->iodesc = desc; error = nfs_lookupfh(&nfs_root_node, upath, currfd); #endif if (!error) { currfd->off = 0; currfd->cookie = 0; f->f_fsdata = (void *)currfd; return (0); } #ifdef NFS_DEBUG if (debug) printf("nfs_open: %s lookupfh failed: %s\n", path, strerror(error)); #endif free(currfd); return (error); } int nfs_close(struct open_file *f) { struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; #ifdef NFS_DEBUG if (debug) printf("nfs_close: fp=0x%lx\n", (u_long)fp); #endif - if (fp) - free(fp); - f->f_fsdata = (void *)0; + free(fp); + f->f_fsdata = NULL; return (0); } /* * read a portion of a file */ int nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid) { struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; ssize_t cc; char *addr = buf; #ifdef NFS_DEBUG if (debug) printf("nfs_read: size=%lu off=%d\n", (u_long)size, (int)fp->off); #endif while ((int)size > 0) { twiddle(16); cc = nfs_readdata(fp, fp->off, (void *)addr, size); /* XXX maybe should retry on certain errors */ if (cc == -1) { #ifdef NFS_DEBUG if (debug) printf("nfs_read: read: %s", strerror(errno)); #endif return (errno); /* XXX - from nfs_readdata */ } if (cc == 0) { #ifdef NFS_DEBUG if (debug) printf("nfs_read: hit EOF unexpectantly"); #endif goto ret; } fp->off += cc; addr += cc; size -= cc; } ret: if (resid) *resid = size; return (0); } /* * Not implemented. */ int nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid) { return (EROFS); } off_t nfs_seek(struct open_file *f, off_t offset, int where) { struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata; uint32_t size = ntohl(d->fa.fa_size.val[1]); switch (where) { case SEEK_SET: d->off = offset; break; case SEEK_CUR: d->off += offset; break; case SEEK_END: d->off = size - offset; break; default: errno = EINVAL; return (-1); } return (d->off); } /* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5, NFSOCK=6, NFFIFO=7 */ int nfs_stat_types[9] = { 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFSOCK, S_IFIFO, 0 }; int nfs_stat(struct open_file *f, struct stat *sb) { struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; uint32_t ftype, mode; ftype = ntohl(fp->fa.fa_type); mode = ntohl(fp->fa.fa_mode); mode |= nfs_stat_types[ftype & 7]; sb->st_mode = mode; sb->st_nlink = ntohl(fp->fa.fa_nlink); sb->st_uid = ntohl(fp->fa.fa_uid); sb->st_gid = ntohl(fp->fa.fa_gid); sb->st_size = ntohl(fp->fa.fa_size.val[1]); return (0); } static int nfs_readdir(struct open_file *f, struct dirent *d) { struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; struct nfsv3_readdir_repl *repl; struct nfsv3_readdir_entry *rent; + static void *pkt = NULL; static char *buf; static struct nfs_iodesc *pfp = NULL; static uint64_t cookie = 0; size_t cc; - int pos; + int pos, rc; struct args { uint32_t fhsize; uint32_t fhpluscookie[5 + NFS_V3MAXFHSIZE]; } *args; struct { uint32_t h[RPC_HEADER_WORDS]; struct args d; } sdata; - static struct { - uint32_t h[RPC_HEADER_WORDS]; - u_char d[NFS_READDIRSIZE]; - } rdata; if (fp != pfp || fp->off != cookie) { pfp = NULL; refill: + free(pkt); + pkt = NULL; args = &sdata.d; bzero(args, sizeof(*args)); args->fhsize = htonl(fp->fhsize); bcopy(fp->fh, args->fhpluscookie, fp->fhsize); pos = roundup(fp->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); args->fhpluscookie[pos++] = htonl(fp->off >> 32); args->fhpluscookie[pos++] = htonl(fp->off); args->fhpluscookie[pos++] = htonl(fp->cookie >> 32); args->fhpluscookie[pos++] = htonl(fp->cookie); args->fhpluscookie[pos] = htonl(NFS_READDIRSIZE); cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READDIR, args, 6 * sizeof(uint32_t) + roundup(fp->fhsize, sizeof(uint32_t)), - rdata.d, sizeof(rdata.d)); - buf = rdata.d; + (void **)&buf, &pkt); + if (cc == -1) { + rc = errno; + goto err; + } repl = (struct nfsv3_readdir_repl *)buf; - if (repl->errno != 0) - return (ntohl(repl->errno)); + if (repl->errno != 0) { + rc = ntohl(repl->errno); + goto err; + } pfp = fp; cookie = fp->off; fp->cookie = ((uint64_t)ntohl(repl->cookiev0) << 32) | ntohl(repl->cookiev1); buf += sizeof (struct nfsv3_readdir_repl); } rent = (struct nfsv3_readdir_entry *)buf; if (rent->follows == 0) { /* fid0 is actually eof */ if (rent->fid0 != 0) { - cookie = 0; - return (ENOENT); + rc = ENOENT; + goto err; } goto refill; } d->d_namlen = ntohl(rent->len); bcopy(rent->nameplus, d->d_name, d->d_namlen); d->d_name[d->d_namlen] = '\0'; pos = roundup(d->d_namlen, sizeof(uint32_t)) / sizeof(uint32_t); fp->off = cookie = ((uint64_t)ntohl(rent->nameplus[pos]) << 32) | ntohl(rent->nameplus[pos + 1]); pos += 2; buf = (u_char *)&rent->nameplus[pos]; return (0); + +err: + free(pkt); + pkt = NULL; + pfp = NULL; + cookie = 0; + return (rc); } Index: head/lib/libstand/rarp.c =================================================================== --- head/lib/libstand/rarp.c (revision 317886) +++ head/lib/libstand/rarp.c (revision 317887) @@ -1,225 +1,218 @@ /* $NetBSD: rarp.c,v 1.16 1997/07/07 15:52:52 drochner Exp $ */ /* * Copyright (c) 1992 Regents of the University of California. * All rights reserved. * * This software was developed by the Computer Systems Engineering group * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and * contributed to Berkeley. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#) Header: arp.c,v 1.5 93/07/15 05:52:26 leres Exp (LBL) */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include "stand.h" #include "net.h" #include "netif.h" static ssize_t rarpsend(struct iodesc *, void *, size_t); -static ssize_t rarprecv(struct iodesc *, void *, size_t, time_t); +static ssize_t rarprecv(struct iodesc *, void **, void **, time_t); /* * Ethernet (Reverse) Address Resolution Protocol (see RFC 903, and 826). */ int -rarp_getipaddress(sock) - int sock; +rarp_getipaddress(int sock) { struct iodesc *d; struct ether_arp *ap; + void *pkt; struct { u_char header[ETHER_SIZE]; struct { struct ether_arp arp; u_char pad[18]; /* 60 - sizeof(arp) */ } data; } wbuf; - struct { - u_char header[ETHER_SIZE]; - struct { - struct ether_arp arp; - u_char pad[24]; /* extra space */ - } data; - } rbuf; #ifdef RARP_DEBUG if (debug) printf("rarp: socket=%d\n", sock); #endif if (!(d = socktodesc(sock))) { printf("rarp: bad socket. %d\n", sock); return (-1); } #ifdef RARP_DEBUG if (debug) printf("rarp: d=%x\n", (u_int)d); #endif bzero((char*)&wbuf.data, sizeof(wbuf.data)); ap = &wbuf.data.arp; ap->arp_hrd = htons(ARPHRD_ETHER); ap->arp_pro = htons(ETHERTYPE_IP); ap->arp_hln = sizeof(ap->arp_sha); /* hardware address length */ ap->arp_pln = sizeof(ap->arp_spa); /* protocol address length */ ap->arp_op = htons(ARPOP_REVREQUEST); bcopy(d->myea, ap->arp_sha, 6); bcopy(d->myea, ap->arp_tha, 6); + pkt = NULL; if (sendrecv(d, rarpsend, &wbuf.data, sizeof(wbuf.data), - rarprecv, &rbuf.data, sizeof(rbuf.data)) < 0) - { + rarprecv, &pkt, (void *)&ap) < 0) { printf("No response for RARP request\n"); return (-1); } - ap = &rbuf.data.arp; bcopy(ap->arp_tpa, (char *)&myip, sizeof(myip)); #if 0 /* XXX - Can NOT assume this is our root server! */ bcopy(ap->arp_spa, (char *)&rootip, sizeof(rootip)); #endif + free(pkt); /* Compute our "natural" netmask. */ if (IN_CLASSA(myip.s_addr)) netmask = IN_CLASSA_NET; else if (IN_CLASSB(myip.s_addr)) netmask = IN_CLASSB_NET; else netmask = IN_CLASSC_NET; d->myip = myip; return (0); } /* * Broadcast a RARP request (i.e. who knows who I am) */ static ssize_t -rarpsend(d, pkt, len) - struct iodesc *d; - void *pkt; - size_t len; +rarpsend(struct iodesc *d, void *pkt, size_t len) { #ifdef RARP_DEBUG if (debug) printf("rarpsend: called\n"); #endif return (sendether(d, pkt, len, bcea, ETHERTYPE_REVARP)); } /* * Returns 0 if this is the packet we're waiting for * else -1 (and errno == 0) */ static ssize_t -rarprecv(d, pkt, len, tleft) - struct iodesc *d; - void *pkt; - size_t len; - time_t tleft; +rarprecv(struct iodesc *d, void **pkt, void **payload, time_t tleft) { ssize_t n; struct ether_arp *ap; - u_int16_t etype; /* host order */ + void *ptr = NULL; + uint16_t etype; /* host order */ #ifdef RARP_DEBUG if (debug) printf("rarprecv: "); #endif - n = readether(d, pkt, len, tleft, &etype); + n = readether(d, ptr, (void **)&ap, tleft, &etype); errno = 0; /* XXX */ if (n == -1 || n < sizeof(struct ether_arp)) { #ifdef RARP_DEBUG if (debug) printf("bad len=%d\n", n); #endif + free(ptr); return (-1); } if (etype != ETHERTYPE_REVARP) { #ifdef RARP_DEBUG if (debug) printf("bad type=0x%x\n", etype); #endif + free(ptr); return (-1); } - ap = (struct ether_arp *)pkt; if (ap->arp_hrd != htons(ARPHRD_ETHER) || ap->arp_pro != htons(ETHERTYPE_IP) || ap->arp_hln != sizeof(ap->arp_sha) || ap->arp_pln != sizeof(ap->arp_spa) ) { #ifdef RARP_DEBUG if (debug) printf("bad hrd/pro/hln/pln\n"); #endif + free(ptr); return (-1); } if (ap->arp_op != htons(ARPOP_REVREPLY)) { #ifdef RARP_DEBUG if (debug) printf("bad op=0x%x\n", ntohs(ap->arp_op)); #endif + free(ptr); return (-1); } /* Is the reply for our Ethernet address? */ if (bcmp(ap->arp_tha, d->myea, 6)) { #ifdef RARP_DEBUG if (debug) printf("unwanted address\n"); #endif + free(ptr); return (-1); } /* We have our answer. */ #ifdef RARP_DEBUG if (debug) printf("got it\n"); #endif + *pkt = ptr; + *payload = ap; return (n); } Index: head/lib/libstand/rpc.c =================================================================== --- head/lib/libstand/rpc.c (revision 317886) +++ head/lib/libstand/rpc.c (revision 317887) @@ -1,438 +1,433 @@ /* $NetBSD: rpc.c,v 1.18 1998/01/23 19:27:45 thorpej Exp $ */ /* * Copyright (c) 1992 Regents of the University of California. * All rights reserved. * * This software was developed by the Computer Systems Engineering group * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and * contributed to Berkeley. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#) Header: rpc.c,v 1.12 93/09/28 08:31:56 leres Exp (LBL) */ #include __FBSDID("$FreeBSD$"); /* * RPC functions used by NFS and bootparams. * Note that bootparams requires the ability to find out the * address of the server from which its response has come. * This is supported by keeping the IP/UDP headers in the * buffer space provided by the caller. (See rpc_fromaddr) */ #include #include #include #include #include #include "rpcv2.h" #include "stand.h" #include "net.h" #include "netif.h" #include "rpc.h" struct auth_info { int32_t authtype; /* auth type */ u_int32_t authlen; /* auth length */ }; struct auth_unix { int32_t ua_time; int32_t ua_hostname; /* null */ int32_t ua_uid; int32_t ua_gid; int32_t ua_gidlist; /* null */ }; struct rpc_call { u_int32_t rp_xid; /* request transaction id */ int32_t rp_direction; /* call direction (0) */ u_int32_t rp_rpcvers; /* rpc version (2) */ u_int32_t rp_prog; /* program */ u_int32_t rp_vers; /* version */ u_int32_t rp_proc; /* procedure */ }; struct rpc_reply { u_int32_t rp_xid; /* request transaction id */ int32_t rp_direction; /* call direction (1) */ int32_t rp_astatus; /* accept status (0: accepted) */ union { u_int32_t rpu_errno; struct { struct auth_info rok_auth; u_int32_t rok_status; } rpu_rok; } rp_u; }; /* Local forwards */ -static ssize_t recvrpc(struct iodesc *, void *, size_t, time_t); +static ssize_t recvrpc(struct iodesc *, void **, void **, time_t); static int rpc_getport(struct iodesc *, n_long, n_long); int rpc_xid; int rpc_port = 0x400; /* predecrement */ /* * Make a rpc call; return length of answer * Note: Caller must leave room for headers. */ ssize_t rpc_call(struct iodesc *d, n_long prog, n_long vers, n_long proc, - void *sdata, size_t slen, void *rdata, size_t rlen) + void *sdata, size_t slen, void **rdata, void **pkt) { - ssize_t cc; + ssize_t cc, rsize; struct auth_info *auth; struct rpc_call *call; struct rpc_reply *reply; char *send_head, *send_tail; - char *recv_head, *recv_tail; + void *ptr; n_long x; int port; /* host order */ #ifdef RPC_DEBUG if (debug) printf("rpc_call: prog=0x%x vers=%d proc=%d\n", prog, vers, proc); #endif port = rpc_getport(d, prog, vers); if (port == -1) return (-1); d->destport = htons(port); /* * Prepend authorization stuff and headers. * Note, must prepend things in reverse order. */ send_head = sdata; send_tail = (char *)sdata + slen; /* Auth verifier is always auth_null */ send_head -= sizeof(*auth); auth = (struct auth_info *)send_head; auth->authtype = htonl(RPCAUTH_NULL); auth->authlen = 0; -#if 1 /* Auth credentials: always auth unix (as root) */ send_head -= sizeof(struct auth_unix); bzero(send_head, sizeof(struct auth_unix)); send_head -= sizeof(*auth); auth = (struct auth_info *)send_head; auth->authtype = htonl(RPCAUTH_UNIX); auth->authlen = htonl(sizeof(struct auth_unix)); -#else - /* Auth credentials: always auth_null (XXX OK?) */ - send_head -= sizeof(*auth); - auth = send_head; - auth->authtype = htonl(RPCAUTH_NULL); - auth->authlen = 0; -#endif /* RPC call structure. */ send_head -= sizeof(*call); call = (struct rpc_call *)send_head; rpc_xid++; call->rp_xid = htonl(rpc_xid); call->rp_direction = htonl(RPC_CALL); call->rp_rpcvers = htonl(RPC_VER2); call->rp_prog = htonl(prog); call->rp_vers = htonl(vers); call->rp_proc = htonl(proc); - /* Make room for the rpc_reply header. */ - recv_head = rdata; - recv_tail = (char *)rdata + rlen; - recv_head -= sizeof(*reply); - + ptr = NULL; cc = sendrecv(d, sendudp, send_head, send_tail - send_head, - recvrpc, recv_head, recv_tail - recv_head); + recvrpc, &ptr, (void **)&reply); #ifdef RPC_DEBUG if (debug) - printf("callrpc: cc=%ld rlen=%lu\n", (long)cc, (u_long)rlen); + printf("callrpc: cc=%zd\n", cc); #endif if (cc == -1) return (-1); if (cc <= sizeof(*reply)) { errno = EBADRPC; + free(ptr); return (-1); } - recv_tail = recv_head + cc; - /* * Check the RPC reply status. * The xid, dir, astatus were already checked. */ - reply = (struct rpc_reply *)recv_head; auth = &reply->rp_u.rpu_rok.rok_auth; x = ntohl(auth->authlen); if (x != 0) { #ifdef RPC_DEBUG if (debug) printf("callrpc: reply auth != NULL\n"); #endif errno = EBADRPC; - return(-1); + free(ptr); + return (-1); } x = ntohl(reply->rp_u.rpu_rok.rok_status); if (x != 0) { printf("callrpc: error = %ld\n", (long)x); errno = EBADRPC; - return(-1); + free(ptr); + return (-1); } - recv_head += sizeof(*reply); - return (ssize_t)(recv_tail - recv_head); + rsize = cc - sizeof(*reply); + *rdata = (void *)((uintptr_t)reply + sizeof(*reply)); + *pkt = ptr; + return (rsize); } /* * Returns true if packet is the one we're waiting for. * This just checks the XID, direction, acceptance. * Remaining checks are done by callrpc */ static ssize_t -recvrpc(struct iodesc *d, void *pkt, size_t len, time_t tleft) +recvrpc(struct iodesc *d, void **pkt, void **payload, time_t tleft) { + void *ptr; struct rpc_reply *reply; ssize_t n; int x; errno = 0; #ifdef RPC_DEBUG if (debug) - printf("recvrpc: called len=%lu\n", (u_long)len); + printf("recvrpc: called\n"); #endif - n = readudp(d, pkt, len, tleft); - if (n <= (4 * 4)) - return -1; + ptr = NULL; + n = readudp(d, &ptr, (void **)&reply, tleft); + if (n <= (4 * 4)) { + free(ptr); + return (-1); + } - reply = (struct rpc_reply *)pkt; - x = ntohl(reply->rp_xid); if (x != rpc_xid) { #ifdef RPC_DEBUG if (debug) printf("recvrpc: rp_xid %d != xid %d\n", x, rpc_xid); #endif - return -1; + free(ptr); + return (-1); } x = ntohl(reply->rp_direction); if (x != RPC_REPLY) { #ifdef RPC_DEBUG if (debug) printf("recvrpc: rp_direction %d != REPLY\n", x); #endif - return -1; + free(ptr); + return (-1); } x = ntohl(reply->rp_astatus); if (x != RPC_MSGACCEPTED) { errno = ntohl(reply->rp_u.rpu_errno); printf("recvrpc: reject, astat=%d, errno=%d\n", x, errno); - return -1; + free(ptr); + return (-1); } + *pkt = ptr; + *payload = reply; /* Return data count (thus indicating success) */ return (n); } /* * Given a pointer to a reply just received, * dig out the IP address/port from the headers. */ void rpc_fromaddr(void *pkt, struct in_addr *addr, u_short *port) { struct hackhdr { /* Tail of IP header: just IP addresses */ n_long ip_src; n_long ip_dst; /* UDP header: */ u_int16_t uh_sport; /* source port */ u_int16_t uh_dport; /* destination port */ int16_t uh_ulen; /* udp length */ u_int16_t uh_sum; /* udp checksum */ /* RPC reply header: */ struct rpc_reply rpc; } *hhdr; hhdr = ((struct hackhdr *)pkt) - 1; addr->s_addr = hhdr->ip_src; *port = hhdr->uh_sport; } /* * RPC Portmapper cache */ #define PMAP_NUM 8 /* need at most 5 pmap entries */ int rpc_pmap_num; struct pmap_list { struct in_addr addr; /* server, net order */ u_int prog; /* host order */ u_int vers; /* host order */ int port; /* host order */ } rpc_pmap_list[PMAP_NUM]; /* * return port number in host order, or -1. * arguments are: * addr .. server, net order. * prog .. host order. * vers .. host order. */ int rpc_pmap_getcache(struct in_addr addr, u_int prog, u_int vers) { struct pmap_list *pl; for (pl = rpc_pmap_list; pl < &rpc_pmap_list[rpc_pmap_num]; pl++) { if (pl->addr.s_addr == addr.s_addr && pl->prog == prog && pl->vers == vers ) { return (pl->port); } } return (-1); } /* * arguments are: * addr .. server, net order. * prog .. host order. * vers .. host order. * port .. host order. */ void rpc_pmap_putcache(struct in_addr addr, u_int prog, u_int vers, int port) { struct pmap_list *pl; /* Don't overflow cache... */ if (rpc_pmap_num >= PMAP_NUM) { /* ... just re-use the last entry. */ rpc_pmap_num = PMAP_NUM - 1; #ifdef RPC_DEBUG printf("rpc_pmap_putcache: cache overflow\n"); #endif } pl = &rpc_pmap_list[rpc_pmap_num]; rpc_pmap_num++; /* Cache answer */ pl->addr = addr; pl->prog = prog; pl->vers = vers; pl->port = port; } /* * Request a port number from the port mapper. * Returns the port in host order. * prog and vers are host order. */ int rpc_getport(struct iodesc *d, n_long prog, n_long vers) { struct args { n_long prog; /* call program */ n_long vers; /* call version */ n_long proto; /* call protocol */ n_long port; /* call port (unused) */ } *args; struct res { n_long port; } *res; struct { n_long h[RPC_HEADER_WORDS]; struct args d; } sdata; - struct { - n_long h[RPC_HEADER_WORDS]; - struct res d; - n_long pad; - } rdata; + void *pkt; ssize_t cc; int port; #ifdef RPC_DEBUG if (debug) printf("%s: prog=0x%x vers=%d\n", __func__, prog, vers); #endif /* This one is fixed forever. */ if (prog == PMAPPROG) { port = PMAPPORT; goto out; } /* Try for cached answer first */ port = rpc_pmap_getcache(d->destip, prog, vers); if (port != -1) goto out; args = &sdata.d; args->prog = htonl(prog); args->vers = htonl(vers); args->proto = htonl(IPPROTO_UDP); args->port = 0; - res = &rdata.d; + pkt = NULL; cc = rpc_call(d, PMAPPROG, PMAPVERS, PMAPPROC_GETPORT, - args, sizeof(*args), res, sizeof(*res)); + args, sizeof(*args), (void **)&res, &pkt); if (cc < sizeof(*res)) { printf("getport: %s", strerror(errno)); errno = EBADRPC; + free(pkt); return (-1); } port = (int)ntohl(res->port); + free(pkt); rpc_pmap_putcache(d->destip, prog, vers, port); out: #ifdef RPC_DEBUG if (debug) printf("%s: port=%u\n", __func__, port); #endif return (port); } Index: head/lib/libstand/rpc.h =================================================================== --- head/lib/libstand/rpc.h (revision 317886) +++ head/lib/libstand/rpc.h (revision 317887) @@ -1,66 +1,66 @@ /* $NetBSD: rpc.h,v 1.8 1996/09/26 23:22:03 cgd Exp $ */ /* * Copyright (c) 1992 Regents of the University of California. * All rights reserved. * * This software was developed by the Computer Systems Engineering group * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and * contributed to Berkeley. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ /* XXX defines we can't easily get from system includes */ #define PMAPPORT 111 #define PMAPPROG 100000 #define PMAPVERS 2 #define PMAPPROC_NULL 0 #define PMAPPROC_SET 1 #define PMAPPROC_UNSET 2 #define PMAPPROC_GETPORT 3 #define PMAPPROC_DUMP 4 #define PMAPPROC_CALLIT 5 /* RPC functions: */ ssize_t rpc_call(struct iodesc *, n_long, n_long, n_long, - void *, size_t, void *, size_t); + void *, size_t, void **, void **); void rpc_fromaddr(void *, struct in_addr *, u_short *); int rpc_pmap_getcache(struct in_addr, u_int, u_int); void rpc_pmap_putcache(struct in_addr, u_int, u_int, int); extern int rpc_port; /* decrement before bind */ /* * How much space to leave in front of RPC requests. * In 32-bit words (alignment) we have: * 12: Ether + IP + UDP + padding * 6: RPC call header * 7: Auth UNIX * 2: Auth NULL */ #define RPC_HEADER_WORDS 28 Index: head/lib/libstand/tftp.c =================================================================== --- head/lib/libstand/tftp.c (revision 317886) +++ head/lib/libstand/tftp.c (revision 317887) @@ -1,766 +1,784 @@ /* $NetBSD: tftp.c,v 1.4 1997/09/17 16:57:07 drochner Exp $ */ /* * Copyright (c) 1996 * Matthias Drochner. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed for the NetBSD Project * by Matthias Drochner. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /* * Simple TFTP implementation for libsa. * Assumes: * - socket descriptor (int) at open_file->f_devdata * - server host IP in global servip * Restrictions: * - read only * - lseek only with SEEK_SET or SEEK_CUR * - no big time differences between transfers ( #include #include #include #include #include #include #include "stand.h" #include "net.h" #include "netif.h" #include "tftp.h" struct tftp_handle; static int tftp_open(const char *path, struct open_file *f); static int tftp_close(struct open_file *f); static int tftp_parse_oack(struct tftp_handle *h, char *buf, size_t len); static int tftp_read(struct open_file *f, void *buf, size_t size, size_t *resid); static int tftp_write(struct open_file *f, void *buf, size_t size, size_t *resid); static off_t tftp_seek(struct open_file *f, off_t offset, int where); static int tftp_set_blksize(struct tftp_handle *h, const char *str); static int tftp_stat(struct open_file *f, struct stat *sb); static ssize_t sendrecv_tftp(struct tftp_handle *h, ssize_t (*sproc)(struct iodesc *, void *, size_t), void *sbuf, size_t ssize, - ssize_t (*rproc)(struct tftp_handle *h, void *, ssize_t, time_t, unsigned short *), - void *rbuf, size_t rsize, unsigned short *rtype); + ssize_t (*rproc)(struct tftp_handle *h, void **, void **, time_t, unsigned short *), + void **, void **, unsigned short *rtype); struct fs_ops tftp_fsops = { "tftp", tftp_open, tftp_close, tftp_read, tftp_write, tftp_seek, tftp_stat, null_readdir }; extern struct in_addr servip; static int tftpport = 2000; static int is_open = 0; /* * The legacy TFTP_BLKSIZE value was SEGSIZE(512). * TFTP_REQUESTED_BLKSIZE of 1428 is (Ethernet MTU, less the TFTP, UDP and * IP header lengths). */ #define TFTP_REQUESTED_BLKSIZE 1428 /* * Choose a blksize big enough so we can test with Ethernet * Jumbo frames in the future. */ #define TFTP_MAX_BLKSIZE 9008 struct tftp_handle { struct iodesc *iodesc; int currblock; /* contents of lastdata */ int islastblock; /* flag */ int validsize; int off; char *path; /* saved for re-requests */ unsigned int tftp_blksize; unsigned long tftp_tsize; - struct { - u_char header[HEADER_SIZE]; - struct tftphdr t; - u_char space[TFTP_MAX_BLKSIZE]; - } __packed __aligned(4) lastdata; + void *pkt; + struct tftphdr *tftp_hdr; }; #define TFTP_MAX_ERRCODE EOPTNEG static const int tftperrors[TFTP_MAX_ERRCODE + 1] = { 0, /* ??? */ ENOENT, EPERM, ENOSPC, EINVAL, /* ??? */ EINVAL, /* ??? */ EEXIST, EINVAL, /* ??? */ EINVAL, /* Option negotiation failed. */ }; static int tftp_getnextblock(struct tftp_handle *h); /* send error message back. */ static void tftp_senderr(struct tftp_handle *h, u_short errcode, const char *msg) { struct { u_char header[HEADER_SIZE]; struct tftphdr t; u_char space[63]; /* +1 from t */ } __packed __aligned(4) wbuf; char *wtail; int len; len = strlen(msg); if (len > sizeof(wbuf.space)) len = sizeof(wbuf.space); wbuf.t.th_opcode = htons((u_short) ERROR); wbuf.t.th_code = htons(errcode); wtail = wbuf.t.th_msg; bcopy(msg, wtail, len); wtail[len] = '\0'; wtail += len + 1; sendudp(h->iodesc, &wbuf.t, wtail - (char *) &wbuf.t); } static void tftp_sendack(struct tftp_handle *h) { struct { u_char header[HEADER_SIZE]; struct tftphdr t; } __packed __aligned(4) wbuf; char *wtail; wbuf.t.th_opcode = htons((u_short) ACK); wtail = (char *) &wbuf.t.th_block; wbuf.t.th_block = htons((u_short) h->currblock); wtail += 2; sendudp(h->iodesc, &wbuf.t, wtail - (char *) &wbuf.t); } static ssize_t -recvtftp(struct tftp_handle *h, void *pkt, ssize_t len, time_t tleft, +recvtftp(struct tftp_handle *h, void **pkt, void **payload, time_t tleft, unsigned short *rtype) { struct iodesc *d = h->iodesc; struct tftphdr *t; + void *ptr = NULL; + ssize_t len; errno = 0; - len = readudp(d, pkt, len, tleft); + len = readudp(d, &ptr, (void **)&t, tleft); - if (len < 4) + if (len < 4) { + free(ptr); return (-1); + } - t = (struct tftphdr *) pkt; *rtype = ntohs(t->th_opcode); switch (ntohs(t->th_opcode)) { case DATA: { int got; if (htons(t->th_block) != (u_short) d->xid) { /* * Expected block? */ + free(ptr); return (-1); } if (d->xid == 1) { /* * First data packet from new port. */ struct udphdr *uh; - uh = (struct udphdr *) pkt - 1; + uh = (struct udphdr *) t - 1; d->destport = uh->uh_sport; } /* else check uh_sport has not changed??? */ - got = len - (t->th_data - (char *) t); - return got; + got = len - (t->th_data - (char *)t); + *pkt = ptr; + *payload = t; + return (got); } case ERROR: if ((unsigned) ntohs(t->th_code) > TFTP_MAX_ERRCODE) { printf("illegal tftp error %d\n", ntohs(t->th_code)); errno = EIO; } else { #ifdef TFTP_DEBUG printf("tftp-error %d\n", ntohs(t->th_code)); #endif errno = tftperrors[ntohs(t->th_code)]; } + free(ptr); return (-1); case OACK: { struct udphdr *uh; int tftp_oack_len; /* * Unexpected OACK. TFTP transfer already in progress. * Drop the pkt. */ if (d->xid != 1) { + free(ptr); return (-1); } /* * Remember which port this OACK came from, because we need * to send the ACK or errors back to it. */ - uh = (struct udphdr *) pkt - 1; + uh = (struct udphdr *) t - 1; d->destport = uh->uh_sport; /* Parse options ACK-ed by the server. */ tftp_oack_len = len - sizeof(t->th_opcode); if (tftp_parse_oack(h, t->th_u.tu_stuff, tftp_oack_len) != 0) { tftp_senderr(h, EOPTNEG, "Malformed OACK"); errno = EIO; + free(ptr); return (-1); } + *pkt = ptr; + *payload = t; return (0); } default: #ifdef TFTP_DEBUG printf("tftp type %d not handled\n", ntohs(t->th_opcode)); #endif + free(ptr); return (-1); } } /* send request, expect first block (or error) */ static int tftp_makereq(struct tftp_handle *h) { struct { u_char header[HEADER_SIZE]; struct tftphdr t; u_char space[FNAME_SIZE + 6]; } __packed __aligned(4) wbuf; char *wtail; int l; ssize_t res; + void *pkt; struct tftphdr *t; char *tftp_blksize = NULL; int blksize_l; unsigned short rtype = 0; /* * Allow overriding default TFTP block size by setting * a tftp.blksize environment variable. */ if ((tftp_blksize = getenv("tftp.blksize")) != NULL) { tftp_set_blksize(h, tftp_blksize); } wbuf.t.th_opcode = htons((u_short) RRQ); wtail = wbuf.t.th_stuff; l = strlen(h->path); #ifdef TFTP_PREPEND_PATH if (l > FNAME_SIZE - (sizeof(TFTP_PREPEND_PATH) - 1)) return (ENAMETOOLONG); bcopy(TFTP_PREPEND_PATH, wtail, sizeof(TFTP_PREPEND_PATH) - 1); wtail += sizeof(TFTP_PREPEND_PATH) - 1; #else if (l > FNAME_SIZE) return (ENAMETOOLONG); #endif bcopy(h->path, wtail, l + 1); wtail += l + 1; bcopy("octet", wtail, 6); wtail += 6; bcopy("blksize", wtail, 8); wtail += 8; blksize_l = sprintf(wtail, "%d", h->tftp_blksize); wtail += blksize_l + 1; bcopy("tsize", wtail, 6); wtail += 6; bcopy("0", wtail, 2); wtail += 2; - t = &h->lastdata.t; - /* h->iodesc->myport = htons(--tftpport); */ h->iodesc->myport = htons(tftpport + (getsecs() & 0x3ff)); h->iodesc->destport = htons(IPPORT_TFTP); h->iodesc->xid = 1; /* expected block */ h->currblock = 0; h->islastblock = 0; h->validsize = 0; + pkt = NULL; res = sendrecv_tftp(h, &sendudp, &wbuf.t, wtail - (char *) &wbuf.t, - &recvtftp, t, sizeof(*t) + h->tftp_blksize, &rtype); + &recvtftp, &pkt, (void **)&t, &rtype); + if (res == -1) { + free(pkt); + return (errno); + } + free(h->pkt); + h->pkt = pkt; + h->tftp_hdr = t; + if (rtype == OACK) return (tftp_getnextblock(h)); /* Server ignored our blksize request, revert to TFTP default. */ h->tftp_blksize = SEGSIZE; switch (rtype) { case DATA: { h->currblock = 1; h->validsize = res; h->islastblock = 0; if (res < h->tftp_blksize) { h->islastblock = 1; /* very short file */ tftp_sendack(h); } return (0); } case ERROR: default: return (errno); } } /* ack block, expect next */ static int tftp_getnextblock(struct tftp_handle *h) { struct { u_char header[HEADER_SIZE]; struct tftphdr t; } __packed __aligned(4) wbuf; char *wtail; int res; + void *pkt; struct tftphdr *t; unsigned short rtype = 0; wbuf.t.th_opcode = htons((u_short) ACK); wtail = (char *) &wbuf.t.th_block; wbuf.t.th_block = htons((u_short) h->currblock); wtail += 2; - t = &h->lastdata.t; - h->iodesc->xid = h->currblock + 1; /* expected block */ + pkt = NULL; res = sendrecv_tftp(h, &sendudp, &wbuf.t, wtail - (char *) &wbuf.t, - &recvtftp, t, sizeof(*t) + h->tftp_blksize, &rtype); + &recvtftp, &pkt, (void **)&t, &rtype); - if (res == -1) /* 0 is OK! */ + if (res == -1) { /* 0 is OK! */ + free(pkt); return (errno); + } + free(h->pkt); + h->pkt = pkt; + h->tftp_hdr = t; h->currblock++; h->validsize = res; if (res < h->tftp_blksize) h->islastblock = 1; /* EOF */ if (h->islastblock == 1) { /* Send an ACK for the last block */ wbuf.t.th_block = htons((u_short) h->currblock); sendudp(h->iodesc, &wbuf.t, wtail - (char *)&wbuf.t); } return (0); } static int tftp_open(const char *path, struct open_file *f) { struct tftp_handle *tftpfile; struct iodesc *io; int res; size_t pathsize; const char *extraslash; if (netproto != NET_TFTP) return (EINVAL); - if (strcmp(f->f_dev->dv_name, "net") != 0) { -#ifdef __i386__ - if (strcmp(f->f_dev->dv_name, "pxe") != 0) - return (EINVAL); -#else + if (f->f_dev->dv_type != DEVT_NET) return (EINVAL); -#endif - } if (is_open) return (EBUSY); tftpfile = (struct tftp_handle *) malloc(sizeof(*tftpfile)); if (!tftpfile) return (ENOMEM); memset(tftpfile, 0, sizeof(*tftpfile)); tftpfile->tftp_blksize = TFTP_REQUESTED_BLKSIZE; tftpfile->iodesc = io = socktodesc(*(int *) (f->f_devdata)); if (io == NULL) return (EINVAL); io->destip = servip; tftpfile->off = 0; pathsize = (strlen(rootpath) + 1 + strlen(path) + 1) * sizeof(char); tftpfile->path = malloc(pathsize); if (tftpfile->path == NULL) { free(tftpfile); return(ENOMEM); } if (rootpath[strlen(rootpath) - 1] == '/' || path[0] == '/') extraslash = ""; else extraslash = "/"; res = snprintf(tftpfile->path, pathsize, "%s%s%s", rootpath, extraslash, path); if (res < 0 || res > pathsize) { free(tftpfile->path); free(tftpfile); return(ENOMEM); } res = tftp_makereq(tftpfile); if (res) { free(tftpfile->path); free(tftpfile); return (res); } f->f_fsdata = (void *) tftpfile; is_open = 1; return (0); } static int tftp_read(struct open_file *f, void *addr, size_t size, size_t *resid /* out */) { struct tftp_handle *tftpfile; tftpfile = (struct tftp_handle *) f->f_fsdata; while (size > 0) { int needblock, count; twiddle(32); needblock = tftpfile->off / tftpfile->tftp_blksize + 1; if (tftpfile->currblock > needblock) { /* seek backwards */ tftp_senderr(tftpfile, 0, "No error: read aborted"); tftp_makereq(tftpfile); /* no error check, it worked * for open */ } while (tftpfile->currblock < needblock) { int res; res = tftp_getnextblock(tftpfile); if (res) { /* no answer */ #ifdef TFTP_DEBUG printf("tftp: read error\n"); #endif return (res); } if (tftpfile->islastblock) break; } if (tftpfile->currblock == needblock) { int offinblock, inbuffer; offinblock = tftpfile->off % tftpfile->tftp_blksize; inbuffer = tftpfile->validsize - offinblock; if (inbuffer < 0) { #ifdef TFTP_DEBUG printf("tftp: invalid offset %d\n", tftpfile->off); #endif return (EINVAL); } count = (size < inbuffer ? size : inbuffer); - bcopy(tftpfile->lastdata.t.th_data + offinblock, + bcopy(tftpfile->tftp_hdr->th_data + offinblock, addr, count); addr = (char *)addr + count; tftpfile->off += count; size -= count; if ((tftpfile->islastblock) && (count == inbuffer)) break; /* EOF */ } else { #ifdef TFTP_DEBUG printf("tftp: block %d not found\n", needblock); #endif return (EINVAL); } } if (resid) *resid = size; return (0); } static int tftp_close(struct open_file *f) { struct tftp_handle *tftpfile; tftpfile = (struct tftp_handle *) f->f_fsdata; /* let it time out ... */ if (tftpfile) { free(tftpfile->path); + free(tftpfile->pkt); free(tftpfile); } is_open = 0; return (0); } static int tftp_write(struct open_file *f __unused, void *start __unused, size_t size __unused, size_t *resid __unused /* out */) { return (EROFS); } static int tftp_stat(struct open_file *f, struct stat *sb) { struct tftp_handle *tftpfile; tftpfile = (struct tftp_handle *) f->f_fsdata; sb->st_mode = 0444 | S_IFREG; sb->st_nlink = 1; sb->st_uid = 0; sb->st_gid = 0; sb->st_size = (off_t) tftpfile->tftp_tsize; return (0); } static off_t tftp_seek(struct open_file *f, off_t offset, int where) { struct tftp_handle *tftpfile; tftpfile = (struct tftp_handle *) f->f_fsdata; switch (where) { case SEEK_SET: tftpfile->off = offset; break; case SEEK_CUR: tftpfile->off += offset; break; default: errno = EOFFSET; return (-1); } return (tftpfile->off); } static ssize_t sendrecv_tftp(struct tftp_handle *h, ssize_t (*sproc)(struct iodesc *, void *, size_t), void *sbuf, size_t ssize, - ssize_t (*rproc)(struct tftp_handle *, void *, ssize_t, time_t, unsigned short *), - void *rbuf, size_t rsize, unsigned short *rtype) + ssize_t (*rproc)(struct tftp_handle *, void **, void **, time_t, + unsigned short *), + void **pkt, void **payload, unsigned short *rtype) { struct iodesc *d = h->iodesc; ssize_t cc; time_t t, t1, tleft; #ifdef TFTP_DEBUG if (debug) printf("sendrecv: called\n"); #endif tleft = MINTMO; t = t1 = getsecs(); for (;;) { if ((getsecs() - t) > MAXTMO) { errno = ETIMEDOUT; return -1; } cc = (*sproc)(d, sbuf, ssize); if (cc != -1 && cc < ssize) panic("sendrecv: short write! (%zd < %zu)", cc, ssize); if (cc == -1) { /* Error on transmit; wait before retrying */ while ((getsecs() - t1) < tleft); continue; } recvnext: /* Try to get a packet and process it. */ - cc = (*rproc)(h, rbuf, rsize, tleft, rtype); + cc = (*rproc)(h, pkt, payload, tleft, rtype); /* Return on data, EOF or real error. */ if (cc != -1 || errno != 0) return (cc); if ((getsecs() - t1) < tleft) { goto recvnext; } /* Timed out or didn't get the packet we're waiting for */ tleft += MINTMO; if (tleft > (2 * MINTMO)) { tleft = (2 * MINTMO); } t1 = getsecs(); } } static int tftp_set_blksize(struct tftp_handle *h, const char *str) { char *endptr; int new_blksize; int ret = 0; if (h == NULL || str == NULL) return (ret); new_blksize = (unsigned int)strtol(str, &endptr, 0); /* * Only accept blksize value if it is numeric. * RFC2348 specifies that acceptable values are 8-65464. * Let's choose a limit less than MAXRSPACE. */ if (*endptr == '\0' && new_blksize >= 8 && new_blksize <= TFTP_MAX_BLKSIZE) { h->tftp_blksize = new_blksize; ret = 1; } return (ret); } /* * In RFC2347, the TFTP Option Acknowledgement package (OACK) * is used to acknowledge a client's option negotiation request. * The format of an OACK packet is: * +-------+---~~---+---+---~~---+---+---~~---+---+---~~---+---+ * | opc | opt1 | 0 | value1 | 0 | optN | 0 | valueN | 0 | * +-------+---~~---+---+---~~---+---+---~~---+---+---~~---+---+ * * opc * The opcode field contains a 6, for Option Acknowledgment. * * opt1 * The first option acknowledgment, copied from the original * request. * * value1 * The acknowledged value associated with the first option. If * and how this value may differ from the original request is * detailed in the specification for the option. * * optN, valueN * The final option/value acknowledgment pair. */ static int tftp_parse_oack(struct tftp_handle *h, char *buf, size_t len) { /* * We parse the OACK strings into an array * of name-value pairs. */ char *tftp_options[128] = { 0 }; char *val = buf; int i = 0; int option_idx = 0; int blksize_is_set = 0; int tsize = 0; unsigned int orig_blksize; while (option_idx < 128 && i < len) { if (buf[i] == '\0') { if (&buf[i] > val) { tftp_options[option_idx] = val; val = &buf[i] + 1; ++option_idx; } } ++i; } /* Save the block size we requested for sanity check later. */ orig_blksize = h->tftp_blksize; /* * Parse individual TFTP options. * * "blksize" is specified in RFC2348. * * "tsize" is specified in RFC2349. */ for (i = 0; i < option_idx; i += 2) { if (strcasecmp(tftp_options[i], "blksize") == 0) { if (i + 1 < option_idx) blksize_is_set = tftp_set_blksize(h, tftp_options[i + 1]); } else if (strcasecmp(tftp_options[i], "tsize") == 0) { if (i + 1 < option_idx) tsize = strtol(tftp_options[i + 1], (char **)NULL, 10); if (tsize != 0) h->tftp_tsize = tsize; } else { /* Do not allow any options we did not expect to be ACKed. */ printf("unexpected tftp option '%s'\n", tftp_options[i]); return (-1); } } if (!blksize_is_set) { /* * If TFTP blksize was not set, try defaulting * to the legacy TFTP blksize of SEGSIZE(512) */ h->tftp_blksize = SEGSIZE; } else if (h->tftp_blksize > orig_blksize) { /* * Server should not be proposing block sizes that * exceed what we said we can handle. */ printf("unexpected blksize %u\n", h->tftp_blksize); return (-1); } #ifdef TFTP_DEBUG printf("tftp_blksize: %u\n", h->tftp_blksize); printf("tftp_tsize: %lu\n", h->tftp_tsize); #endif return 0; } Index: head/lib/libstand/udp.c =================================================================== --- head/lib/libstand/udp.c (revision 317886) +++ head/lib/libstand/udp.c (revision 317887) @@ -1,272 +1,278 @@ /* Taken from $NetBSD: net.c,v 1.20 1997/12/26 22:41:30 scottr Exp $ */ /* * Copyright (c) 1992 Regents of the University of California. * All rights reserved. * * This software was developed by the Computer Systems Engineering group * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and * contributed to Berkeley. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#) Header: net.c,v 1.9 93/08/06 19:32:15 leres Exp (LBL) */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include "stand.h" #include "net.h" /* Caller must leave room for ethernet, ip and udp headers in front!! */ ssize_t -sendudp(d, pkt, len) - struct iodesc *d; - void *pkt; - size_t len; +sendudp(struct iodesc *d, void *pkt, size_t len) { ssize_t cc; struct ip *ip; struct udphdr *uh; u_char *ea; #ifdef NET_DEBUG if (debug) { printf("sendudp: d=%lx called.\n", (long)d); if (d) { printf("saddr: %s:%d", inet_ntoa(d->myip), ntohs(d->myport)); printf(" daddr: %s:%d\n", inet_ntoa(d->destip), ntohs(d->destport)); } } #endif uh = (struct udphdr *)pkt - 1; ip = (struct ip *)uh - 1; len += sizeof(*ip) + sizeof(*uh); bzero(ip, sizeof(*ip) + sizeof(*uh)); ip->ip_v = IPVERSION; /* half-char */ ip->ip_hl = sizeof(*ip) >> 2; /* half-char */ ip->ip_len = htons(len); ip->ip_p = IPPROTO_UDP; /* char */ ip->ip_ttl = IPDEFTTL; /* char */ ip->ip_src = d->myip; ip->ip_dst = d->destip; ip->ip_sum = in_cksum(ip, sizeof(*ip)); /* short, but special */ uh->uh_sport = d->myport; uh->uh_dport = d->destport; uh->uh_ulen = htons(len - sizeof(*ip)); #ifndef UDP_NO_CKSUM { struct udpiphdr *ui; struct ip tip; /* Calculate checksum (must save and restore ip header) */ tip = *ip; ui = (struct udpiphdr *)ip; bzero(&ui->ui_x1, sizeof(ui->ui_x1)); ui->ui_len = uh->uh_ulen; uh->uh_sum = in_cksum(ui, len); *ip = tip; } #endif if (ip->ip_dst.s_addr == INADDR_BROADCAST || ip->ip_src.s_addr == 0 || netmask == 0 || SAMENET(ip->ip_src, ip->ip_dst, netmask)) ea = arpwhohas(d, ip->ip_dst); else ea = arpwhohas(d, gateip); cc = sendether(d, ip, len, ea, ETHERTYPE_IP); if (cc == -1) return (-1); if (cc != len) panic("sendudp: bad write (%zd != %zd)", cc, len); return (cc - (sizeof(*ip) + sizeof(*uh))); } /* * Receive a UDP packet and validate it is for us. - * Caller leaves room for the headers (Ether, IP, UDP) */ ssize_t -readudp(d, pkt, len, tleft) - struct iodesc *d; - void *pkt; - size_t len; - time_t tleft; +readudp(struct iodesc *d, void **pkt, void **payload, time_t tleft) { ssize_t n; size_t hlen; struct ip *ip; struct udphdr *uh; - u_int16_t etype; /* host order */ + uint16_t etype; /* host order */ + void *ptr; #ifdef NET_DEBUG if (debug) printf("readudp: called\n"); #endif - uh = (struct udphdr *)pkt - 1; - ip = (struct ip *)uh - 1; + ip = NULL; + ptr = NULL; + n = readether(d, &ptr, (void **)&ip, tleft, &etype); + if (n == -1 || n < sizeof(*ip) + sizeof(*uh)) { + free(ptr); + return (-1); + } - n = readether(d, ip, len + sizeof(*ip) + sizeof(*uh), tleft, &etype); - if (n == -1 || n < sizeof(*ip) + sizeof(*uh)) - return -1; - /* Ethernet address checks now in readether() */ /* Need to respond to ARP requests. */ if (etype == ETHERTYPE_ARP) { struct arphdr *ah = (void *)ip; if (ah->ar_op == htons(ARPOP_REQUEST)) { /* Send ARP reply */ arp_reply(d, ah); } - return -1; + free(ptr); + return (-1); } if (etype != ETHERTYPE_IP) { #ifdef NET_DEBUG if (debug) printf("readudp: not IP. ether_type=%x\n", etype); #endif - return -1; + free(ptr); + return (-1); } /* Check ip header */ if (ip->ip_v != IPVERSION || ip->ip_p != IPPROTO_UDP) { /* half char */ #ifdef NET_DEBUG if (debug) printf("readudp: IP version or not UDP. ip_v=%d ip_p=%d\n", ip->ip_v, ip->ip_p); #endif - return -1; + free(ptr); + return (-1); } hlen = ip->ip_hl << 2; if (hlen < sizeof(*ip) || in_cksum(ip, hlen) != 0) { #ifdef NET_DEBUG if (debug) printf("readudp: short hdr or bad cksum.\n"); #endif - return -1; + free(ptr); + return (-1); } if (n < ntohs(ip->ip_len)) { #ifdef NET_DEBUG if (debug) printf("readudp: bad length %d < %d.\n", (int)n, ntohs(ip->ip_len)); #endif - return -1; + free(ptr); + return (-1); } if (d->myip.s_addr && ip->ip_dst.s_addr != d->myip.s_addr) { #ifdef NET_DEBUG if (debug) { printf("readudp: bad saddr %s != ", inet_ntoa(d->myip)); printf("%s\n", inet_ntoa(ip->ip_dst)); } #endif - return -1; + free(ptr); + return (-1); } + uh = (struct udphdr *)((uintptr_t)ip + sizeof (*ip)); /* If there were ip options, make them go away */ if (hlen != sizeof(*ip)) { - bcopy(((u_char *)ip) + hlen, uh, len - hlen); + bcopy(((u_char *)ip) + hlen, uh, uh->uh_ulen - hlen); ip->ip_len = htons(sizeof(*ip)); n -= hlen - sizeof(*ip); } if (uh->uh_dport != d->myport) { #ifdef NET_DEBUG if (debug) printf("readudp: bad dport %d != %d\n", d->myport, ntohs(uh->uh_dport)); #endif - return -1; + free(ptr); + return (-1); } #ifndef UDP_NO_CKSUM if (uh->uh_sum) { struct udpiphdr *ui; struct ip tip; n = ntohs(uh->uh_ulen) + sizeof(*ip); if (n > RECV_SIZE - ETHER_SIZE) { printf("readudp: huge packet, udp len %d\n", (int)n); - return -1; + free(ptr); + return (-1); } /* Check checksum (must save and restore ip header) */ tip = *ip; ui = (struct udpiphdr *)ip; bzero(&ui->ui_x1, sizeof(ui->ui_x1)); ui->ui_len = uh->uh_ulen; if (in_cksum(ui, n) != 0) { #ifdef NET_DEBUG if (debug) printf("readudp: bad cksum\n"); #endif - *ip = tip; - return -1; + free(ptr); + return (-1); } *ip = tip; } #endif if (ntohs(uh->uh_ulen) < sizeof(*uh)) { #ifdef NET_DEBUG if (debug) printf("readudp: bad udp len %d < %d\n", ntohs(uh->uh_ulen), (int)sizeof(*uh)); #endif - return -1; + free(ptr); + return (-1); } n = (n > (ntohs(uh->uh_ulen) - sizeof(*uh))) ? ntohs(uh->uh_ulen) - sizeof(*uh) : n; + *pkt = ptr; + *payload = (void *)((uintptr_t)uh + sizeof(*uh)); return (n); } Index: head/sys/boot/common/dev_net.c =================================================================== --- head/sys/boot/common/dev_net.c (revision 317886) +++ head/sys/boot/common/dev_net.c (revision 317887) @@ -1,381 +1,403 @@ /* $NetBSD: dev_net.c,v 1.23 2008/04/28 20:24:06 martin Exp $ */ /*- * Copyright (c) 1997 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Gordon W. Ross. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /*- * This module implements a "raw device" interface suitable for * use by the stand-alone I/O library NFS code. This interface * does not support any "block" access, and exists only for the * purpose of initializing the network interface, getting boot * parameters, and performing the NFS mount. * * At open time, this does: * * find interface - netif_open() * RARP for IP address - rarp_getipaddress() * RPC/bootparams - callrpc(d, RPC_BOOTPARAMS, ...) * RPC/mountd - nfs_mount(sock, ip, path) * * the root file handle from mountd is saved in a global * for use by the NFS open code (NFS/lookup). */ #include #include #include #include #include #include #include +#include #include #include #include #include #include #include "dev_net.h" #include "bootstrap.h" #ifdef NETIF_DEBUG int debug = 0; #endif static char *netdev_name; static int netdev_sock = -1; static int netdev_opens; static int net_init(void); static int net_open(struct open_file *, ...); static int net_close(struct open_file *); static void net_cleanup(void); -static int net_strategy(); +static int net_strategy(void *, int, daddr_t, size_t, char *, size_t *); static int net_print(int); static int net_getparams(int sock); struct devsw netdev = { "net", DEVT_NET, net_init, net_strategy, net_open, net_close, noioctl, net_print, net_cleanup }; static int net_init(void) { return (0); } /* * Called by devopen after it sets f->f_dev to our devsw entry. * This opens the low-level device and sets f->f_devdata. * This is declared with variable arguments... */ static int net_open(struct open_file *f, ...) { struct iodesc *d; va_list args; char *devname; /* Device part of file name (or NULL). */ int error = 0; va_start(args, f); devname = va_arg(args, char*); va_end(args); /* Before opening another interface, close the previous one first. */ if (netdev_sock >= 0 && strcmp(devname, netdev_name) != 0) net_cleanup(); /* On first open, do netif open, mount, etc. */ if (netdev_opens == 0) { /* Find network interface. */ if (netdev_sock < 0) { netdev_sock = netif_open(devname); if (netdev_sock < 0) { printf("net_open: netif_open() failed\n"); return (ENXIO); } netdev_name = strdup(devname); #ifdef NETIF_DEBUG if (debug) printf("net_open: netif_open() succeeded\n"); #endif } /* * If network params were not set by netif_open(), try to get * them via bootp, rarp, etc. */ if (rootip.s_addr == 0) { /* Get root IP address, and path, etc. */ error = net_getparams(netdev_sock); if (error) { /* getparams makes its own noise */ free(netdev_name); netif_close(netdev_sock); netdev_sock = -1; return (error); } } /* * Set the variables required by the kernel's nfs_diskless * mechanism. This is the minimum set of variables required to * mount a root filesystem without needing to obtain additional * info from bootp or other sources. */ d = socktodesc(netdev_sock); setenv("boot.netif.hwaddr", ether_sprintf(d->myea), 1); setenv("boot.netif.ip", inet_ntoa(myip), 1); setenv("boot.netif.netmask", intoa(netmask), 1); setenv("boot.netif.gateway", inet_ntoa(gateip), 1); setenv("boot.netif.server", inet_ntoa(rootip), 1); if (netproto == NET_TFTP) { setenv("boot.tftproot.server", inet_ntoa(rootip), 1); setenv("boot.tftproot.path", rootpath, 1); } else if (netproto == NET_NFS) { setenv("boot.nfsroot.server", inet_ntoa(rootip), 1); setenv("boot.nfsroot.path", rootpath, 1); } if (intf_mtu != 0) { char mtu[16]; snprintf(mtu, sizeof(mtu), "%u", intf_mtu); setenv("boot.netif.mtu", mtu, 1); } } netdev_opens++; f->f_devdata = &netdev_sock; return (error); } static int net_close(struct open_file *f) { #ifdef NETIF_DEBUG if (debug) printf("net_close: opens=%d\n", netdev_opens); #endif f->f_devdata = NULL; return (0); } static void net_cleanup(void) { if (netdev_sock >= 0) { #ifdef NETIF_DEBUG if (debug) printf("net_cleanup: calling netif_close()\n"); #endif rootip.s_addr = 0; free(netdev_name); netif_close(netdev_sock); netdev_sock = -1; } } static int -net_strategy() +net_strategy(void *devdata, int rw, daddr_t blk, size_t size, char *buf, + size_t *rsize) { return (EIO); } #define SUPPORT_BOOTP /* * Get info for NFS boot: our IP address, our hostname, * server IP address, and our root path on the server. * There are two ways to do this: The old, Sun way, * and the more modern, BOOTP way. (RFC951, RFC1048) * * The default is to use the Sun bootparams RPC * (because that is what the kernel will do). * MD code can make try_bootp initialied data, * which will override this common definition. */ #ifdef SUPPORT_BOOTP int try_bootp = 1; #endif extern n_long ip_convertaddr(char *p); static int net_getparams(int sock) { char buf[MAXHOSTNAMELEN]; n_long rootaddr, smask; + struct iodesc *d = socktodesc(sock); + extern struct in_addr servip; #ifdef SUPPORT_BOOTP /* * Try to get boot info using BOOTP. If we succeed, then * the server IP address, gateway, and root path will all * be initialized. If any remain uninitialized, we will * use RARP and RPC/bootparam (the Sun way) to get them. */ - if (try_bootp) - bootp(sock, BOOTP_NONE); + if (try_bootp) { + int rc = -1; + if (bootp_response != NULL) { + rc = dhcp_try_rfc1048(bootp_response->bp_vend, + bootp_response_size - + offsetof(struct bootp, bp_vend)); + + if (servip.s_addr == 0) + servip = bootp_response->bp_siaddr; + if (rootip.s_addr == 0) + rootip = bootp_response->bp_siaddr; + if (gateip.s_addr == 0) + gateip = bootp_response->bp_giaddr; + if (myip.s_addr == 0) + myip = bootp_response->bp_yiaddr; + d->myip = myip; + } + if (rc < 0) + bootp(sock, BOOTP_NONE); + } if (myip.s_addr != 0) goto exit; #ifdef NETIF_DEBUG if (debug) printf("net_open: BOOTP failed, trying RARP/RPC...\n"); #endif #endif /* * Use RARP to get our IP address. This also sets our * netmask to the "natural" default for our address. */ if (rarp_getipaddress(sock)) { printf("net_open: RARP failed\n"); return (EIO); } printf("net_open: client addr: %s\n", inet_ntoa(myip)); /* Get our hostname, server IP address, gateway. */ if (bp_whoami(sock)) { printf("net_open: bootparam/whoami RPC failed\n"); return (EIO); } #ifdef NETIF_DEBUG if (debug) printf("net_open: client name: %s\n", hostname); #endif /* * Ignore the gateway from whoami (unreliable). * Use the "gateway" parameter instead. */ smask = 0; gateip.s_addr = 0; if (bp_getfile(sock, "gateway", &gateip, buf) == 0) { /* Got it! Parse the netmask. */ smask = ip_convertaddr(buf); } if (smask) { netmask = smask; #ifdef NETIF_DEBUG if (debug) printf("net_open: subnet mask: %s\n", intoa(netmask)); #endif } #ifdef NETIF_DEBUG if (gateip.s_addr && debug) printf("net_open: net gateway: %s\n", inet_ntoa(gateip)); #endif /* Get the root server and pathname. */ if (bp_getfile(sock, "root", &rootip, rootpath)) { printf("net_open: bootparam/getfile RPC failed\n"); return (EIO); } exit: netproto = NET_TFTP; if ((rootaddr = net_parse_rootpath()) != INADDR_NONE) { netproto = NET_NFS; rootip.s_addr = rootaddr; } #ifdef NETIF_DEBUG if (debug) { printf("net_open: server addr: %s\n", inet_ntoa(rootip)); printf("net_open: server path: %s\n", rootpath); } #endif return (0); } static int net_print(int verbose) { struct netif_driver *drv; int i, d, cnt; int ret = 0; if (netif_drivers[0] == NULL) return (ret); printf("%s devices:", netdev.dv_name); if ((ret = pager_output("\n")) != 0) return (ret); cnt = 0; for (d = 0; netif_drivers[d]; d++) { drv = netif_drivers[d]; for (i = 0; i < drv->netif_nifs; i++) { printf("\t%s%d:", netdev.dv_name, cnt++); if (verbose) { printf(" (%s%d)", drv->netif_bname, drv->netif_ifs[i].dif_unit); } if ((ret = pager_output("\n")) != 0) return (ret); } } return (ret); } /* * Strip the server's address off of the rootpath if present and return it in * network byte order, leaving just the pathname part in the global rootpath. */ uint32_t net_parse_rootpath() { int i; n_long addr = INADDR_NONE; for (i = 0; rootpath[i] != '\0' && i < FNAME_SIZE; i++) if (rootpath[i] == ':') break; if (i && i != FNAME_SIZE && rootpath[i] == ':') { rootpath[i++] = '\0'; addr = inet_addr(&rootpath[0]); bcopy(&rootpath[i], rootpath, strlen(&rootpath[i])+1); } return (addr); } Index: head/sys/boot/efi/libefi/efinet.c =================================================================== --- head/sys/boot/efi/libefi/efinet.c (revision 317886) +++ head/sys/boot/efi/libefi/efinet.c (revision 317887) @@ -1,384 +1,391 @@ /*- * Copyright (c) 2001 Doug Rabson * Copyright (c) 2002, 2006 Marcel Moolenaar * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include +#include #include #include #include #include #include -#include - #include #include static EFI_GUID sn_guid = EFI_SIMPLE_NETWORK_PROTOCOL; static void efinet_end(struct netif *); -static int efinet_get(struct iodesc *, void *, size_t, time_t); +static ssize_t efinet_get(struct iodesc *, void **, time_t); static void efinet_init(struct iodesc *, void *); static int efinet_match(struct netif *, void *); static int efinet_probe(struct netif *, void *); -static int efinet_put(struct iodesc *, void *, size_t); +static ssize_t efinet_put(struct iodesc *, void *, size_t); struct netif_driver efinetif = { .netif_bname = "efinet", .netif_match = efinet_match, .netif_probe = efinet_probe, .netif_init = efinet_init, .netif_get = efinet_get, .netif_put = efinet_put, .netif_end = efinet_end, .netif_ifs = NULL, .netif_nifs = 0 }; #ifdef EFINET_DEBUG static void dump_mode(EFI_SIMPLE_NETWORK_MODE *mode) { int i; printf("State = %x\n", mode->State); printf("HwAddressSize = %u\n", mode->HwAddressSize); printf("MediaHeaderSize = %u\n", mode->MediaHeaderSize); printf("MaxPacketSize = %u\n", mode->MaxPacketSize); printf("NvRamSize = %u\n", mode->NvRamSize); printf("NvRamAccessSize = %u\n", mode->NvRamAccessSize); printf("ReceiveFilterMask = %x\n", mode->ReceiveFilterMask); printf("ReceiveFilterSetting = %u\n", mode->ReceiveFilterSetting); printf("MaxMCastFilterCount = %u\n", mode->MaxMCastFilterCount); printf("MCastFilterCount = %u\n", mode->MCastFilterCount); printf("MCastFilter = {"); for (i = 0; i < mode->MCastFilterCount; i++) printf(" %s", ether_sprintf(mode->MCastFilter[i].Addr)); printf(" }\n"); printf("CurrentAddress = %s\n", ether_sprintf(mode->CurrentAddress.Addr)); printf("BroadcastAddress = %s\n", ether_sprintf(mode->BroadcastAddress.Addr)); printf("PermanentAddress = %s\n", ether_sprintf(mode->PermanentAddress.Addr)); printf("IfType = %u\n", mode->IfType); printf("MacAddressChangeable = %d\n", mode->MacAddressChangeable); printf("MultipleTxSupported = %d\n", mode->MultipleTxSupported); printf("MediaPresentSupported = %d\n", mode->MediaPresentSupported); printf("MediaPresent = %d\n", mode->MediaPresent); } #endif static int efinet_match(struct netif *nif, void *machdep_hint) { struct devdesc *dev = machdep_hint; if (dev->d_unit == nif->nif_unit) return (1); return(0); } static int efinet_probe(struct netif *nif, void *machdep_hint) { return (0); } -static int +static ssize_t efinet_put(struct iodesc *desc, void *pkt, size_t len) { struct netif *nif = desc->io_netif; EFI_SIMPLE_NETWORK *net; EFI_STATUS status; void *buf; net = nif->nif_devdata; if (net == NULL) return (-1); - status = net->Transmit(net, 0, len, pkt, 0, 0, 0); + status = net->Transmit(net, 0, len, pkt, NULL, NULL, NULL); if (status != EFI_SUCCESS) return (-1); /* Wait for the buffer to be transmitted */ do { buf = NULL; /* XXX Is this needed? */ - status = net->GetStatus(net, 0, &buf); + status = net->GetStatus(net, NULL, &buf); /* * XXX EFI1.1 and the E1000 card returns a different * address than we gave. Sigh. */ } while (status == EFI_SUCCESS && buf == NULL); /* XXX How do we deal with status != EFI_SUCCESS now? */ return ((status == EFI_SUCCESS) ? len : -1); } -static int -efinet_get(struct iodesc *desc, void *pkt, size_t len, time_t timeout) +static ssize_t +efinet_get(struct iodesc *desc, void **pkt, time_t timeout) { struct netif *nif = desc->io_netif; EFI_SIMPLE_NETWORK *net; EFI_STATUS status; UINTN bufsz; time_t t; - char buf[2048]; + char *buf, *ptr; + ssize_t ret = -1; net = nif->nif_devdata; if (net == NULL) - return (0); + return (ret); - t = time(0); - while ((time(0) - t) < timeout) { - bufsz = sizeof(buf); - status = net->Receive(net, 0, &bufsz, buf, 0, 0, 0); + bufsz = net->Mode->MaxPacketSize + ETHER_HDR_LEN + ETHER_CRC_LEN; + buf = malloc(bufsz + ETHER_ALIGN); + if (buf == NULL) + return (ret); + ptr = buf + ETHER_ALIGN; + + t = getsecs(); + while ((getsecs() - t) < timeout) { + status = net->Receive(net, NULL, &bufsz, ptr, NULL, NULL, NULL); if (status == EFI_SUCCESS) { - /* - * XXX EFI1.1 and the E1000 card trash our - * workspace if we do not do this silly copy. - * Either they are not respecting the len - * value or do not like the alignment. - */ - if (bufsz > len) - bufsz = len; - bcopy(buf, pkt, bufsz); - return (bufsz); + *pkt = buf; + ret = (ssize_t)bufsz; + break; } if (status != EFI_NOT_READY) - return (0); + break; } - return (0); + if (ret == -1) + free(buf); + return (ret); } static void efinet_init(struct iodesc *desc, void *machdep_hint) { struct netif *nif = desc->io_netif; EFI_SIMPLE_NETWORK *net; EFI_HANDLE h; EFI_STATUS status; if (nif->nif_driver->netif_ifs[nif->nif_unit].dif_unit < 0) { printf("Invalid network interface %d\n", nif->nif_unit); return; } h = nif->nif_driver->netif_ifs[nif->nif_unit].dif_private; status = BS->HandleProtocol(h, &sn_guid, (VOID **)&nif->nif_devdata); if (status != EFI_SUCCESS) { printf("net%d: cannot fetch interface data (status=%lu)\n", nif->nif_unit, EFI_ERROR_CODE(status)); return; } net = nif->nif_devdata; if (net->Mode->State == EfiSimpleNetworkStopped) { status = net->Start(net); if (status != EFI_SUCCESS) { - printf("net%d: cannot start interface (status=%ld)\n", - nif->nif_unit, (long)status); + printf("net%d: cannot start interface (status=%lu)\n", + nif->nif_unit, EFI_ERROR_CODE(status)); return; } } if (net->Mode->State != EfiSimpleNetworkInitialized) { status = net->Initialize(net, 0, 0); if (status != EFI_SUCCESS) { - printf("net%d: cannot init. interface (status=%ld)\n", - nif->nif_unit, (long)status); + printf("net%d: cannot init. interface (status=%lu)\n", + nif->nif_unit, EFI_ERROR_CODE(status)); return; } } if (net->Mode->ReceiveFilterSetting == 0) { UINT32 mask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST | EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST; - status = net->ReceiveFilters(net, mask, 0, FALSE, 0, 0); + status = net->ReceiveFilters(net, mask, 0, FALSE, 0, NULL); if (status != EFI_SUCCESS) { - printf("net%d: cannot set rx. filters (status=%ld)\n", - nif->nif_unit, (long)status); + printf("net%d: cannot set rx. filters (status=%lu)\n", + nif->nif_unit, EFI_ERROR_CODE(status)); return; } } #ifdef EFINET_DEBUG dump_mode(net->Mode); #endif bcopy(net->Mode->CurrentAddress.Addr, desc->myea, 6); desc->xid = 1; } static void efinet_end(struct netif *nif) { EFI_SIMPLE_NETWORK *net = nif->nif_devdata; if (net == NULL) return; net->Shutdown(net); } static int efinet_dev_init(void); static int efinet_dev_print(int); struct devsw efinet_dev = { .dv_name = "net", .dv_type = DEVT_NET, .dv_init = efinet_dev_init, - .dv_strategy = net_strategy, - .dv_open = net_open, - .dv_close = net_close, + .dv_strategy = NULL, /* Will be set in efinet_dev_init */ + .dv_open = NULL, /* Will be set in efinet_dev_init */ + .dv_close = NULL, /* Will be set in efinet_dev_init */ .dv_ioctl = noioctl, .dv_print = efinet_dev_print, .dv_cleanup = NULL }; static int efinet_dev_init() { struct netif_dif *dif; struct netif_stats *stats; EFI_DEVICE_PATH *devpath, *node; EFI_SIMPLE_NETWORK *net; EFI_HANDLE *handles, *handles2; EFI_STATUS status; UINTN sz; int err, i, nifs; + extern struct devsw netdev; sz = 0; handles = NULL; - status = BS->LocateHandle(ByProtocol, &sn_guid, 0, &sz, 0); + status = BS->LocateHandle(ByProtocol, &sn_guid, NULL, &sz, NULL); if (status == EFI_BUFFER_TOO_SMALL) { handles = (EFI_HANDLE *)malloc(sz); - status = BS->LocateHandle(ByProtocol, &sn_guid, 0, &sz, + status = BS->LocateHandle(ByProtocol, &sn_guid, NULL, &sz, handles); if (EFI_ERROR(status)) free(handles); } if (EFI_ERROR(status)) return (efi_status_to_errno(status)); handles2 = (EFI_HANDLE *)malloc(sz); if (handles2 == NULL) { free(handles); return (ENOMEM); } nifs = 0; for (i = 0; i < sz / sizeof(EFI_HANDLE); i++) { devpath = efi_lookup_devpath(handles[i]); if (devpath == NULL) continue; if ((node = efi_devpath_last_node(devpath)) == NULL) continue; if (DevicePathType(node) != MESSAGING_DEVICE_PATH || DevicePathSubType(node) != MSG_MAC_ADDR_DP) continue; /* * Open the network device in exclusive mode. Without this * we will be racing with the UEFI network stack. It will * pull packets off the network leading to lost packets. */ status = BS->OpenProtocol(handles[i], &sn_guid, (void **)&net, - IH, 0, EFI_OPEN_PROTOCOL_EXCLUSIVE); + IH, NULL, EFI_OPEN_PROTOCOL_EXCLUSIVE); if (status != EFI_SUCCESS) { printf("Unable to open network interface %d for " - "exclusive access: %d\n", i, EFI_ERROR(status)); + "exclusive access: %lu\n", i, + EFI_ERROR_CODE(status)); } handles2[nifs] = handles[i]; nifs++; } free(handles); if (nifs == 0) { err = ENOENT; goto done; } err = efi_register_handles(&efinet_dev, handles2, NULL, nifs); if (err != 0) goto done; efinetif.netif_ifs = calloc(nifs, sizeof(struct netif_dif)); stats = calloc(nifs, sizeof(struct netif_stats)); if (efinetif.netif_ifs == NULL || stats == NULL) { free(efinetif.netif_ifs); free(stats); efinetif.netif_ifs = NULL; err = ENOMEM; goto done; } efinetif.netif_nifs = nifs; for (i = 0; i < nifs; i++) { dif = &efinetif.netif_ifs[i]; dif->dif_unit = i; dif->dif_nsel = 1; dif->dif_stats = &stats[i]; dif->dif_private = handles2[i]; } + + efinet_dev.dv_open = netdev.dv_open; + efinet_dev.dv_close = netdev.dv_close; + efinet_dev.dv_strategy = netdev.dv_strategy; + done: free(handles2); return (err); } static int efinet_dev_print(int verbose) { CHAR16 *text; EFI_HANDLE h; int unit, ret = 0; printf("%s devices:", efinet_dev.dv_name); if ((ret = pager_output("\n")) != 0) return (ret); for (unit = 0, h = efi_find_handle(&efinet_dev, 0); h != NULL; h = efi_find_handle(&efinet_dev, ++unit)) { printf(" %s%d:", efinet_dev.dv_name, unit); if (verbose) { text = efi_devpath_name(efi_lookup_devpath(h)); if (text != NULL) { printf(" %S", text); efi_free_devpath_name(text); } } if ((ret = pager_output("\n")) != 0) break; } return (ret); } Index: head/sys/boot/efi/libefi/time.c =================================================================== --- head/sys/boot/efi/libefi/time.c (revision 317886) +++ head/sys/boot/efi/libefi/time.c (revision 317887) @@ -1,234 +1,234 @@ /*- * Copyright (c) 1999, 2000 * Intel Corporation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * * This product includes software developed by Intel Corporation and * its contributors. * * 4. Neither the name of Intel Corporation or its contributors may be * used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION AND CONTRIBUTORS ``AS IS'' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL INTEL CORPORATION OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * */ #include __FBSDID("$FreeBSD$"); #include #include #include #include /* // Accurate only for the past couple of centuries; // that will probably do. // // (#defines From FreeBSD 3.2 lib/libc/stdtime/tzfile.h) */ #define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0)) #define SECSPERHOUR ( 60*60 ) #define SECSPERDAY (24 * SECSPERHOUR) void efi_time_init(void) { } void efi_time_fini(void) { } static time_t efi_time(EFI_TIME *ETime) { /* // These arrays give the cumulative number of days up to the first of the // month number used as the index (1 -> 12) for regular and leap years. // The value at index 13 is for the whole year. */ static time_t CumulativeDays[2][14] = { {0, 0, 31, 31 + 28, 31 + 28 + 31, 31 + 28 + 31 + 30, 31 + 28 + 31 + 30 + 31, 31 + 28 + 31 + 30 + 31 + 30, 31 + 28 + 31 + 30 + 31 + 30 + 31, 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31, 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30, 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31, 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30, 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31 }, {0, 0, 31, 31 + 29, 31 + 29 + 31, 31 + 29 + 31 + 30, 31 + 29 + 31 + 30 + 31, 31 + 29 + 31 + 30 + 31 + 30, 31 + 29 + 31 + 30 + 31 + 30 + 31, 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31, 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30, 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31, 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30, 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31 }}; time_t UTime; int Year; /* // Do a santity check */ if ( ETime->Year < 1998 || ETime->Year > 2099 || ETime->Month == 0 || ETime->Month > 12 || ETime->Day == 0 || ETime->Month > 31 || ETime->Hour > 23 || ETime->Minute > 59 || ETime->Second > 59 || ETime->TimeZone < -1440 || (ETime->TimeZone > 1440 && ETime->TimeZone != 2047) ) { return (0); } /* // Years */ UTime = 0; for (Year = 1970; Year != ETime->Year; ++Year) { UTime += (CumulativeDays[isleap(Year)][13] * SECSPERDAY); } /* // UTime should now be set to 00:00:00 on Jan 1 of the file's year. // // Months */ UTime += (CumulativeDays[isleap(ETime->Year)][ETime->Month] * SECSPERDAY); /* // UTime should now be set to 00:00:00 on the first of the file's month and year // // Days -- Don't count the file's day */ UTime += (((ETime->Day > 0) ? ETime->Day-1:0) * SECSPERDAY); /* // Hours */ UTime += (ETime->Hour * SECSPERHOUR); /* // Minutes */ UTime += (ETime->Minute * 60); /* // Seconds */ UTime += ETime->Second; /* // EFI time is repored in local time. Adjust for any time zone offset to // get true UT */ if ( ETime->TimeZone != EFI_UNSPECIFIED_TIMEZONE ) { /* // TimeZone is kept in minues... */ UTime += (ETime->TimeZone * 60); } return UTime; } static int EFI_GetTimeOfDay( OUT struct timeval *tp, OUT struct timezone *tzp ) { EFI_TIME EfiTime; EFI_TIME_CAPABILITIES Capabilities; EFI_STATUS Status; /* // Get time from EFI */ Status = RS->GetTime(&EfiTime, &Capabilities); if (EFI_ERROR(Status)) return (-1); /* // Convert to UNIX time (ie seconds since the epoch */ tp->tv_sec = efi_time( &EfiTime ); tp->tv_usec = 0; /* EfiTime.Nanosecond * 1000; */ /* // Do something with the timezone if needed */ if (tzp) { tzp->tz_minuteswest = EfiTime.TimeZone == EFI_UNSPECIFIED_TIMEZONE ? 0 : EfiTime.TimeZone; /* // This isn't quit right since it doesn't deal with EFI_TIME_IN_DAYLIGHT */ tzp->tz_dsttime = EfiTime.Daylight & EFI_TIME_ADJUST_DAYLIGHT ? 1 : 0; } return (0); } time_t time(time_t *tloc) { struct timeval tv; EFI_GetTimeOfDay(&tv, 0); if (tloc) *tloc = tv.tv_sec; return tv.tv_sec; } time_t getsecs(void) { - return time(0); + return time(NULL); } Index: head/sys/boot/efi/loader/Makefile =================================================================== --- head/sys/boot/efi/loader/Makefile (revision 317886) +++ head/sys/boot/efi/loader/Makefile (revision 317887) @@ -1,173 +1,178 @@ # $FreeBSD$ MAN= .include MK_SSP= no PROG= loader.sym INTERNALPROG= WARNS?= 3 +LOADER_NET_SUPPORT?= yes # architecture-specific loader code SRCS= autoload.c \ bootinfo.c \ conf.c \ copy.c \ devicename.c \ main.c \ self_reloc.c \ smbios.c \ vers.c .if ${MK_ZFS} != "no" SRCS+= zfs.c .PATH: ${.CURDIR}/../../zfs SRCS+= skein.c skein_block.c # Do not unroll skein loops, reduce code size CFLAGS+= -DSKEIN_LOOP=111 .PATH: ${.CURDIR}/../../../crypto/skein # Disable warnings that are currently incompatible with the zfs boot code CWARNFLAGS.zfs.c+= -Wno-sign-compare CWARNFLAGS.zfs.c+= -Wno-array-bounds CWARNFLAGS.zfs.c+= -Wno-missing-prototypes +.endif + +.if defined(LOADER_NET_SUPPORT) +CFLAGS+= -I${.CURDIR}/../../../../lib/libstand .endif .if ${COMPILER_TYPE} == "gcc" && ${COMPILER_VERSION} > 40201 CWARNFLAGS.self_reloc.c+= -Wno-error=maybe-uninitialized .endif # We implement a slightly non-standard %S in that it always takes a # CHAR16 that's common in UEFI-land instead of a wchar_t. This only # seems to matter on arm64 where wchar_t defaults to an int instead # of a short. There's no good cast to use here so just ignore the # warnings for now. CWARNFLAGS.main.c+= -Wno-format .PATH: ${.CURDIR}/arch/${MACHINE} # For smbios.c .PATH: ${.CURDIR}/../../i386/libi386 .include "${.CURDIR}/arch/${MACHINE}/Makefile.inc" CFLAGS+= -I${.CURDIR} CFLAGS+= -I${.CURDIR}/arch/${MACHINE} CFLAGS+= -I${.CURDIR}/../include CFLAGS+= -I${.CURDIR}/../include/${MACHINE} CFLAGS+= -I${.CURDIR}/../../../contrib/dev/acpica/include CFLAGS+= -I${.CURDIR}/../../.. CFLAGS+= -I${.CURDIR}/../../i386/libi386 .if ${MK_ZFS} != "no" CFLAGS+= -I${.CURDIR}/../../zfs CFLAGS+= -I${.CURDIR}/../../../cddl/boot/zfs CFLAGS+= -I${.CURDIR}/../../../crypto/skein CFLAGS+= -DEFI_ZFS_BOOT .endif CFLAGS+= -DNO_PCI -DEFI # make buildenv doesn't set DESTDIR, this means LIBSTAND # will be wrong when crossbuilding. .if exists(${.OBJDIR}/../../../../lib/libstand/libstand.a) LIBSTAND= ${.OBJDIR}/../../../../lib/libstand/libstand.a .endif .if !defined(BOOT_HIDE_SERIAL_NUMBERS) # Export serial numbers, UUID, and asset tag from loader. CFLAGS+= -DSMBIOS_SERIAL_NUMBERS .if defined(BOOT_LITTLE_ENDIAN_UUID) # Use little-endian UUID format as defined in SMBIOS 2.6. CFLAGS+= -DSMBIOS_LITTLE_ENDIAN_UUID .elif defined(BOOT_NETWORK_ENDIAN_UUID) # Use network-endian UUID format for backward compatibility. CFLAGS+= -DSMBIOS_NETWORK_ENDIAN_UUID .endif .endif .if ${MK_FORTH} != "no" BOOT_FORTH= yes CFLAGS+= -DBOOT_FORTH CFLAGS+= -I${.CURDIR}/../../ficl CFLAGS+= -I${.CURDIR}/../../ficl/${MACHINE_CPUARCH} LIBFICL= ${.OBJDIR}/../../ficl/libficl.a .endif LOADER_FDT_SUPPORT?= no .if ${MK_FDT} != "no" && ${LOADER_FDT_SUPPORT} != "no" CFLAGS+= -I${.CURDIR}/../../fdt CFLAGS+= -I${.OBJDIR}/../../fdt CFLAGS+= -DLOADER_FDT_SUPPORT LIBEFI_FDT= ${.OBJDIR}/../../efi/fdt/libefi_fdt.a LIBFDT= ${.OBJDIR}/../../fdt/libfdt.a .endif # Include bcache code. HAVE_BCACHE= yes .if defined(EFI_STAGING_SIZE) CFLAGS+= -DEFI_STAGING_SIZE=${EFI_STAGING_SIZE} .endif # Always add MI sources .PATH: ${.CURDIR}/../../common .include "${.CURDIR}/../../common/Makefile.inc" CFLAGS+= -I${.CURDIR}/../../common FILES+= loader.efi FILESMODE_loader.efi= ${BINMODE} LDSCRIPT= ${.CURDIR}/arch/${MACHINE}/ldscript.${MACHINE} LDFLAGS+= -Wl,-T${LDSCRIPT} -Wl,-Bsymbolic -shared CLEANFILES+= loader.efi NEWVERSWHAT= "EFI loader" ${MACHINE} NM?= nm OBJCOPY?= objcopy .if ${MACHINE_CPUARCH} == "amd64" EFI_TARGET= efi-app-x86_64 .elif ${MACHINE_CPUARCH} == "i386" EFI_TARGET= efi-app-ia32 .else EFI_TARGET= binary .endif # Arbitrarily set the PE/COFF header timestamps to 1 Jan 2016 00:00:00 # for build reproducibility. SOURCE_DATE_EPOCH?=1451606400 loader.efi: ${PROG} if ${NM} ${.ALLSRC} | grep ' U '; then \ echo "Undefined symbols in ${.ALLSRC}"; \ exit 1; \ fi SOURCE_DATE_EPOCH=${SOURCE_DATE_EPOCH} \ ${OBJCOPY} -j .peheader -j .text -j .sdata -j .data \ -j .dynamic -j .dynsym -j .rel.dyn \ -j .rela.dyn -j .reloc -j .eh_frame -j set_Xcommand_set \ -j set_Xficl_compile_set \ --output-target=${EFI_TARGET} ${.ALLSRC} ${.TARGET} LIBEFI= ${.OBJDIR}/../libefi/libefi.a DPADD= ${LIBFICL} ${LIBEFI} ${LIBFDT} ${LIBEFI_FDT} ${LIBSTAND} \ ${LDSCRIPT} LDADD= ${LIBFICL} ${LIBEFI} ${LIBFDT} ${LIBEFI_FDT} ${LIBSTAND} .include beforedepend ${OBJS}: machine CLEANFILES+= machine machine: .NOMETA ln -sf ${.CURDIR}/../../../${MACHINE}/include machine .if ${MACHINE_CPUARCH} == "amd64" || ${MACHINE_CPUARCH} == "i386" beforedepend ${OBJS}: x86 CLEANFILES+= x86 x86: .NOMETA ln -sf ${.CURDIR}/../../../x86/include x86 .endif Index: head/sys/boot/i386/libi386/pxe.c =================================================================== --- head/sys/boot/i386/libi386/pxe.c (revision 317886) +++ head/sys/boot/i386/libi386/pxe.c (revision 317887) @@ -1,688 +1,540 @@ /*- * Copyright (c) 2000 Alfred Perlstein * Copyright (c) 2000 Paul Saab * Copyright (c) 2000 John Baldwin * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include +#include #include #include +#include +#include #include #include +#include #include #include #include #include #include #include #include #include "btxv86.h" #include "pxe.h" /* * Allocate the PXE buffers statically instead of sticking grimy fingers into * BTX's private data area. The scratch buffer is used to send information to * the PXE BIOS, and the data buffer is used to receive data from the PXE BIOS. */ #define PXE_BUFFER_SIZE 0x2000 -#define PXE_TFTP_BUFFER_SIZE 512 static char scratch_buffer[PXE_BUFFER_SIZE]; static char data_buffer[PXE_BUFFER_SIZE]; static pxenv_t *pxenv_p = NULL; /* PXENV+ */ static pxe_t *pxe_p = NULL; /* !PXE */ -static BOOTPLAYER bootplayer; /* PXE Cached information. */ +#ifdef PXE_DEBUG static int pxe_debug = 0; -static int pxe_sock = -1; -static int pxe_opens = 0; +#endif void pxe_enable(void *pxeinfo); static void (*pxe_call)(int func); static void pxenv_call(int func); static void bangpxe_call(int func); static int pxe_init(void); -static int pxe_strategy(void *devdata, int flag, daddr_t dblk, - size_t size, char *buf, size_t *rsize); -static int pxe_open(struct open_file *f, ...); -static int pxe_close(struct open_file *f); static int pxe_print(int verbose); static void pxe_cleanup(void); -static void pxe_setnfshandle(char *rootpath); static void pxe_perror(int error); static int pxe_netif_match(struct netif *nif, void *machdep_hint); static int pxe_netif_probe(struct netif *nif, void *machdep_hint); static void pxe_netif_init(struct iodesc *desc, void *machdep_hint); -static int pxe_netif_get(struct iodesc *desc, void *pkt, size_t len, - time_t timeout); -static int pxe_netif_put(struct iodesc *desc, void *pkt, size_t len); +static ssize_t pxe_netif_get(struct iodesc *, void **, time_t); +static ssize_t pxe_netif_put(struct iodesc *desc, void *pkt, size_t len); static void pxe_netif_end(struct netif *nif); -int nfs_getrootfh(struct iodesc*, char*, uint32_t*, u_char*); - extern struct netif_stats pxe_st[]; extern u_int16_t __bangpxeseg; extern u_int16_t __bangpxeoff; extern void __bangpxeentry(void); extern u_int16_t __pxenvseg; extern u_int16_t __pxenvoff; extern void __pxenventry(void); -extern struct in_addr servip; struct netif_dif pxe_ifs[] = { /* dif_unit dif_nsel dif_stats dif_private */ {0, 1, &pxe_st[0], 0} }; -struct netif_stats pxe_st[NENTS(pxe_ifs)]; +struct netif_stats pxe_st[nitems(pxe_ifs)]; struct netif_driver pxenetif = { - "pxenet", - pxe_netif_match, - pxe_netif_probe, - pxe_netif_init, - pxe_netif_get, - pxe_netif_put, - pxe_netif_end, - pxe_ifs, - NENTS(pxe_ifs) + .netif_bname = "pxenet", + .netif_match = pxe_netif_match, + .netif_probe = pxe_netif_probe, + .netif_init = pxe_netif_init, + .netif_get = pxe_netif_get, + .netif_put = pxe_netif_put, + .netif_end = pxe_netif_end, + .netif_ifs = pxe_ifs, + .netif_nifs = nitems(pxe_ifs) }; struct netif_driver *netif_drivers[] = { &pxenetif, NULL }; struct devsw pxedisk = { - "pxe", - DEVT_NET, - pxe_init, - pxe_strategy, - pxe_open, - pxe_close, - noioctl, - pxe_print, - pxe_cleanup + .dv_name = "net", + .dv_type = DEVT_NET, + .dv_init = pxe_init, + .dv_strategy = NULL, /* Will be set in pxe_init */ + .dv_open = NULL, /* Will be set in pxe_init */ + .dv_close = NULL, /* Will be set in pxe_init */ + .dv_ioctl = noioctl, + .dv_print = pxe_print, + .dv_cleanup = pxe_cleanup }; /* * 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. */ void pxe_enable(void *pxeinfo) { pxenv_p = (pxenv_t *)pxeinfo; pxe_p = (pxe_t *)PTOV(pxenv_p->PXEPtr.segment * 16 + pxenv_p->PXEPtr.offset); pxe_call = NULL; } /* * return true if pxe structures are found/initialized, * also figures out our IP information via the pxe cached info struct */ static int pxe_init(void) { t_PXENV_GET_CACHED_INFO *gci_p; int counter; uint8_t checksum; uint8_t *checkptr; + extern struct devsw netdev; if (pxenv_p == NULL) return (0); /* look for "PXENV+" */ if (bcmp((void *)pxenv_p->Signature, S_SIZE("PXENV+"))) { pxenv_p = NULL; return (0); } /* make sure the size is something we can handle */ if (pxenv_p->Length > sizeof(*pxenv_p)) { printf("PXENV+ structure too large, ignoring\n"); pxenv_p = NULL; return (0); } /* * do byte checksum: * add up each byte in the structure, the total should be 0 */ checksum = 0; checkptr = (uint8_t *) pxenv_p; for (counter = 0; counter < pxenv_p->Length; counter++) checksum += *checkptr++; if (checksum != 0) { printf("PXENV+ structure failed checksum, ignoring\n"); pxenv_p = NULL; return (0); } /* * PXENV+ passed, so use that if !PXE is not available or * the checksum fails. */ pxe_call = pxenv_call; if (pxenv_p->Version >= 0x0200) { for (;;) { if (bcmp((void *)pxe_p->Signature, S_SIZE("!PXE"))) { pxe_p = NULL; break; } checksum = 0; checkptr = (uint8_t *)pxe_p; for (counter = 0; counter < pxe_p->StructLength; counter++) checksum += *checkptr++; if (checksum != 0) { pxe_p = NULL; break; } pxe_call = bangpxe_call; break; } } - + + pxedisk.dv_open = netdev.dv_open; + pxedisk.dv_close = netdev.dv_close; + pxedisk.dv_strategy = netdev.dv_strategy; + printf("\nPXE version %d.%d, real mode entry point ", (uint8_t) (pxenv_p->Version >> 8), (uint8_t) (pxenv_p->Version & 0xFF)); if (pxe_call == bangpxe_call) printf("@%04x:%04x\n", pxe_p->EntryPointSP.segment, pxe_p->EntryPointSP.offset); else printf("@%04x:%04x\n", pxenv_p->RMEntry.segment, pxenv_p->RMEntry.offset); gci_p = (t_PXENV_GET_CACHED_INFO *) scratch_buffer; bzero(gci_p, sizeof(*gci_p)); gci_p->PacketType = PXENV_PACKET_TYPE_BINL_REPLY; pxe_call(PXENV_GET_CACHED_INFO); if (gci_p->Status != 0) { pxe_perror(gci_p->Status); pxe_p = NULL; return (0); } - bcopy(PTOV((gci_p->Buffer.segment << 4) + gci_p->Buffer.offset), - &bootplayer, gci_p->BufferSize); + free(bootp_response); + if ((bootp_response = malloc(gci_p->BufferSize)) != NULL) { + bootp_response_size = gci_p->BufferSize; + bcopy(PTOV((gci_p->Buffer.segment << 4) + gci_p->Buffer.offset), + bootp_response, bootp_response_size); + } return (1); } - static int -pxe_strategy(void *devdata, int flag, daddr_t dblk, size_t size, - char *buf, size_t *rsize) -{ - return (EIO); -} - -static int -pxe_open(struct open_file *f, ...) -{ - va_list args; - char *devname; /* Device part of file name (or NULL). */ - char temp[FNAME_SIZE]; - int error = 0; - int i; - - va_start(args, f); - devname = va_arg(args, char*); - va_end(args); - - /* On first open, do netif open, mount, etc. */ - if (pxe_opens == 0) { - /* Find network interface. */ - if (pxe_sock < 0) { - pxe_sock = netif_open(devname); - if (pxe_sock < 0) { - printf("pxe_open: netif_open() failed\n"); - return (ENXIO); - } - if (pxe_debug) - printf("pxe_open: netif_open() succeeded\n"); - - if (socktodesc(pxe_sock) == NULL) { - printf("pxe_open: bad socket %d\n", pxe_sock); - return (ENXIO); - } - - } - if (rootip.s_addr == 0) { - /* - * Try to extract the RFC1048 data from PXE. - * If fail 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. - */ - - if (dhcp_try_rfc1048(bootplayer.vendor.d, BOOTP_DHCPVEND) < 0) { - if (pxe_debug) - printf("pxe_open: no RFC1048 data in PXE Cache\n"); - bootp(pxe_sock, BOOTP_PXE); - } else if (pxe_debug) { - printf("pxe_open: loaded RFC1048 data from PXE Cache\n"); - } - -#ifdef LOADER_TFTP_SUPPORT - bootp(pxe_sock, BOOTP_PXE); -#endif - if (rootip.s_addr == 0) - rootip.s_addr = bootplayer.sip; - if (gateip.s_addr == 0) - gateip.s_addr = bootplayer.gip; - if (myip.s_addr == 0) - myip.s_addr = bootplayer.yip; - if (servip.s_addr == 0) - servip = rootip; - - netproto = NET_TFTP; - - if (!rootpath[0]) - strcpy(rootpath, PXENFSROOTPATH); - - for (i = 0; rootpath[i] != '\0' && i < FNAME_SIZE; i++) - if (rootpath[i] == ':') - break; - if (i && i != FNAME_SIZE && rootpath[i] == ':') { - rootpath[i++] = '\0'; - if (inet_addr(&rootpath[0]) != INADDR_NONE) { - netproto = NET_NFS; - rootip.s_addr = inet_addr(&rootpath[0]); - } - bcopy(&rootpath[i], &temp[0], strlen(&rootpath[i]) + 1); - bcopy(&temp[0], &rootpath[0], strlen(&rootpath[i]) + 1); - } - setenv("boot.netif.ip", inet_ntoa(myip), 1); - setenv("boot.netif.netmask", intoa(netmask), 1); - setenv("boot.netif.gateway", inet_ntoa(gateip), 1); - setenv("boot.netif.server", inet_ntoa(rootip), 1); - if (bootplayer.Hardware == ETHER_TYPE) { - sprintf(temp, "%6D", bootplayer.CAddr, ":"); - setenv("boot.netif.hwaddr", temp, 1); - } - if (intf_mtu != 0) { - char mtu[16]; - snprintf(sizeof(mtu), mtu, "%u", intf_mtu); - setenv("boot.netif.mtu", mtu, 1); - } - printf("pxe_open: server addr: %s\n", inet_ntoa(rootip)); - printf("pxe_open: server path: %s\n", rootpath); - printf("pxe_open: gateway ip: %s\n", inet_ntoa(gateip)); - printf("pxe_open: my ip: %s\n", inet_ntoa(myip)); - printf("pxe_open: netmask: %s\n", intoa(netmask)); - printf("pxe_open: servip: %s\n", inet_ntoa(servip)); - - if (netproto == NET_TFTP) { - setenv("boot.tftproot.server", inet_ntoa(rootip), 1); - setenv("boot.tftproot.path", rootpath, 1); - } else if (netproto == NET_NFS) { - setenv("boot.nfsroot.server", inet_ntoa(rootip), 1); - setenv("boot.nfsroot.path", rootpath, 1); - } - setenv("dhcp.host-name", hostname, 1); - - setenv("pxeboot.ip", inet_ntoa(myip), 1); - if (bootplayer.Hardware == ETHER_TYPE) { - sprintf(temp, "%6D", bootplayer.CAddr, ":"); - setenv("pxeboot.hwaddr", temp, 1); - } - } - } - pxe_opens++; - f->f_devdata = &pxe_sock; - return (error); -} - -static int -pxe_close(struct open_file *f) -{ - -#ifdef PXE_DEBUG - if (pxe_debug) - printf("pxe_close: opens=%d\n", pxe_opens); -#endif - - /* On last close, do netif close, etc. */ - f->f_devdata = NULL; - /* Extra close call? */ - if (pxe_opens <= 0) - return (0); - pxe_opens--; - /* Not last close? */ - if (pxe_opens > 0) - return (0); - - if (netproto == NET_NFS) { - /* get an NFS filehandle for our root filesystem */ - pxe_setnfshandle(rootpath); - } - - if (pxe_sock >= 0) { - -#ifdef PXE_DEBUG - if (pxe_debug) - printf("pxe_close: calling netif_close()\n"); -#endif - netif_close(pxe_sock); - pxe_sock = -1; - } - return (0); -} - -static int pxe_print(int verbose) { - char line[255]; if (pxe_call == NULL) return (0); printf("%s devices:", pxedisk.dv_name); if (pager_output("\n") != 0) return (1); + printf(" %s0:", pxedisk.dv_name); if (verbose) { - snprintf(line, sizeof(line), " pxe0: %s:%s\n", - inet_ntoa(rootip), rootpath); - } else { - snprintf(line, sizeof(line), " pxe0:\n"); + printf(" %s:%s", inet_ntoa(rootip), rootpath); } - return (pager_output(line)); + return (pager_output("\n")); } static void pxe_cleanup(void) { #ifdef PXE_DEBUG t_PXENV_UNLOAD_STACK *unload_stack_p = (t_PXENV_UNLOAD_STACK *)scratch_buffer; t_PXENV_UNDI_SHUTDOWN *undi_shutdown_p = (t_PXENV_UNDI_SHUTDOWN *)scratch_buffer; #endif if (pxe_call == NULL) return; pxe_call(PXENV_UNDI_SHUTDOWN); #ifdef PXE_DEBUG if (pxe_debug && undi_shutdown_p->Status != 0) printf("pxe_cleanup: UNDI_SHUTDOWN failed %x\n", undi_shutdown_p->Status); #endif pxe_call(PXENV_UNLOAD_STACK); #ifdef PXE_DEBUG if (pxe_debug && unload_stack_p->Status != 0) printf("pxe_cleanup: UNLOAD_STACK failed %x\n", unload_stack_p->Status); #endif } void pxe_perror(int err) { return; } -/* - * Reach inside the libstand NFS code and dig out an NFS handle - * for the root filesystem. - */ -#define NFS_V3MAXFHSIZE 64 - -struct nfs_iodesc { - struct iodesc *iodesc; - off_t off; - uint32_t fhsize; - u_char fh[NFS_V3MAXFHSIZE]; - /* structure truncated */ -}; -extern struct nfs_iodesc nfs_root_node; -extern int rpc_port; - -static void -pxe_rpcmountcall() -{ - struct iodesc *d; - int error; - - if (!(d = socktodesc(pxe_sock))) - return; - d->myport = htons(--rpc_port); - d->destip = rootip; - if ((error = nfs_getrootfh(d, rootpath, &nfs_root_node.fhsize, - nfs_root_node.fh)) != 0) { - printf("NFS MOUNT RPC error: %d\n", error); - nfs_root_node.fhsize = 0; - } - nfs_root_node.iodesc = d; -} - -static void -pxe_setnfshandle(char *rootpath) -{ - int i; - u_char *fh; - char buf[2 * NFS_V3MAXFHSIZE + 3], *cp; - - /* - * If NFS files were never opened, we need to do mount call - * ourselves. Use nfs_root_node.iodesc as flag indicating - * previous NFS usage. - */ - if (nfs_root_node.iodesc == NULL) - pxe_rpcmountcall(); - - fh = &nfs_root_node.fh[0]; - buf[0] = 'X'; - cp = &buf[1]; - for (i = 0; i < nfs_root_node.fhsize; i++, cp += 2) - sprintf(cp, "%02x", fh[i]); - sprintf(cp, "X"); - setenv("boot.nfsroot.nfshandle", buf, 1); - sprintf(buf, "%d", nfs_root_node.fhsize); - setenv("boot.nfsroot.nfshandlelen", buf, 1); -} - void pxenv_call(int func) { #ifdef PXE_DEBUG if (pxe_debug) printf("pxenv_call %x\n", func); #endif bzero(&v86, sizeof(v86)); bzero(data_buffer, sizeof(data_buffer)); __pxenvseg = pxenv_p->RMEntry.segment; __pxenvoff = pxenv_p->RMEntry.offset; v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS; v86.es = VTOPSEG(scratch_buffer); v86.edi = VTOPOFF(scratch_buffer); v86.addr = (VTOPSEG(__pxenventry) << 16) | VTOPOFF(__pxenventry); v86.ebx = func; v86int(); v86.ctl = V86_FLAGS; } void bangpxe_call(int func) { #ifdef PXE_DEBUG if (pxe_debug) printf("bangpxe_call %x\n", func); #endif bzero(&v86, sizeof(v86)); bzero(data_buffer, sizeof(data_buffer)); __bangpxeseg = pxe_p->EntryPointSP.segment; __bangpxeoff = pxe_p->EntryPointSP.offset; v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS; v86.edx = VTOPSEG(scratch_buffer); v86.eax = VTOPOFF(scratch_buffer); v86.addr = (VTOPSEG(__bangpxeentry) << 16) | VTOPOFF(__bangpxeentry); v86.ebx = func; v86int(); v86.ctl = V86_FLAGS; } static int pxe_netif_match(struct netif *nif, void *machdep_hint) { - return 1; + return (1); } static int pxe_netif_probe(struct netif *nif, void *machdep_hint) { - t_PXENV_UDP_OPEN *udpopen_p = (t_PXENV_UDP_OPEN *)scratch_buffer; - if (pxe_call == NULL) - return -1; + return (-1); - bzero(udpopen_p, sizeof(*udpopen_p)); - udpopen_p->src_ip = bootplayer.yip; - pxe_call(PXENV_UDP_OPEN); - - if (udpopen_p->status != 0) { - printf("pxe_netif_probe: failed %x\n", udpopen_p->status); - return -1; - } - return 0; + return (0); } static void pxe_netif_end(struct netif *nif) { - t_PXENV_UDP_CLOSE *udpclose_p = (t_PXENV_UDP_CLOSE *)scratch_buffer; - bzero(udpclose_p, sizeof(*udpclose_p)); + t_PXENV_UNDI_CLOSE *undi_close_p; - pxe_call(PXENV_UDP_CLOSE); - if (udpclose_p->status != 0) - printf("pxe_end failed %x\n", udpclose_p->status); + undi_close_p = (t_PXENV_UNDI_CLOSE *)scratch_buffer; + bzero(undi_close_p, sizeof(*undi_close_p)); + pxe_call(PXENV_UNDI_CLOSE); + if (undi_close_p->Status != 0) + printf("undi close failed: %x\n", undi_close_p->Status); } static void pxe_netif_init(struct iodesc *desc, void *machdep_hint) { - int i; - for (i = 0; i < 6; ++i) - desc->myea[i] = bootplayer.CAddr[i]; - desc->xid = bootplayer.ident; -} + t_PXENV_UNDI_GET_INFORMATION *undi_info_p; + t_PXENV_UNDI_OPEN *undi_open_p; + uint8_t *mac; + int i, len; -static int -pxe_netif_get(struct iodesc *desc, void *pkt, size_t len, time_t timeout) -{ - return len; + undi_info_p = (t_PXENV_UNDI_GET_INFORMATION *)scratch_buffer; + bzero(undi_info_p, sizeof(*undi_info_p)); + pxe_call(PXENV_UNDI_GET_INFORMATION); + if (undi_info_p->Status != 0) { + printf("undi get info failed: %x\n", undi_info_p->Status); + return; + } + + /* Make sure the CurrentNodeAddress is valid. */ + for (i = 0; i < undi_info_p->HwAddrLen; ++i) { + if (undi_info_p->CurrentNodeAddress[i] != 0) + break; + } + if (i < undi_info_p->HwAddrLen) { + for (i = 0; i < undi_info_p->HwAddrLen; ++i) { + if (undi_info_p->CurrentNodeAddress[i] != 0xff) + break; + } + } + if (i < undi_info_p->HwAddrLen) + mac = undi_info_p->CurrentNodeAddress; + else + mac = undi_info_p->PermNodeAddress; + + len = min(sizeof (desc->myea), undi_info_p->HwAddrLen); + for (i = 0; i < len; ++i) + desc->myea[i] = mac[i]; + + if (bootp_response != NULL) + desc->xid = bootp_response->bp_xid; + else + desc->xid = 0; + + undi_open_p = (t_PXENV_UNDI_OPEN *)scratch_buffer; + bzero(undi_open_p, sizeof(*undi_open_p)); + undi_open_p->PktFilter = FLTR_DIRECTED | FLTR_BRDCST; + pxe_call(PXENV_UNDI_OPEN); + if (undi_open_p->Status != 0) + printf("undi open failed: %x\n", undi_open_p->Status); } static int -pxe_netif_put(struct iodesc *desc, void *pkt, size_t len) +pxe_netif_receive(void **pkt) { - return len; -} + t_PXENV_UNDI_ISR *isr = (t_PXENV_UNDI_ISR *)scratch_buffer; + char *buf, *ptr, *frame; + size_t size, rsize; -ssize_t -sendudp(struct iodesc *h, void *pkt, size_t len) -{ - t_PXENV_UDP_WRITE *udpwrite_p = (t_PXENV_UDP_WRITE *)scratch_buffer; - bzero(udpwrite_p, sizeof(*udpwrite_p)); + bzero(isr, sizeof(*isr)); + isr->FuncFlag = PXENV_UNDI_ISR_IN_START; + pxe_call(PXENV_UNDI_ISR); + if (isr->Status != 0) + return (-1); - udpwrite_p->ip = h->destip.s_addr; - udpwrite_p->dst_port = h->destport; - udpwrite_p->src_port = h->myport; - udpwrite_p->buffer_size = len; - udpwrite_p->buffer.segment = VTOPSEG(pkt); - udpwrite_p->buffer.offset = VTOPOFF(pkt); + bzero(isr, sizeof(*isr)); + isr->FuncFlag = PXENV_UNDI_ISR_IN_PROCESS; + pxe_call(PXENV_UNDI_ISR); + if (isr->Status != 0) + return (-1); - if (netmask == 0 || SAMENET(myip, h->destip, netmask)) - udpwrite_p->gw = 0; - else - udpwrite_p->gw = gateip.s_addr; + while (isr->FuncFlag == PXENV_UNDI_ISR_OUT_TRANSMIT) { + /* + * Wait till transmit is done. + */ + bzero(isr, sizeof(*isr)); + isr->FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT; + pxe_call(PXENV_UNDI_ISR); + if (isr->Status != 0 || + isr->FuncFlag == PXENV_UNDI_ISR_OUT_DONE) + return (-1); + } - pxe_call(PXENV_UDP_WRITE); + while (isr->FuncFlag != PXENV_UNDI_ISR_OUT_RECEIVE) { + if (isr->Status != 0 || + isr->FuncFlag == PXENV_UNDI_ISR_OUT_DONE) { + return (-1); + } + bzero(isr, sizeof(*isr)); + isr->FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT; + pxe_call(PXENV_UNDI_ISR); + } -#if 0 - /* XXX - I dont know why we need this. */ - delay(1000); -#endif - if (udpwrite_p->status != 0) { - /* XXX: This happens a lot. It shouldn't. */ - if (udpwrite_p->status != 1) - printf("sendudp failed %x\n", udpwrite_p->status); - return -1; + size = isr->FrameLength; + buf = malloc(size + ETHER_ALIGN); + if (buf == NULL) + return (-1); + ptr = buf + ETHER_ALIGN; + rsize = 0; + + while (rsize < size) { + frame = (char *)((uintptr_t)isr->Frame.segment << 4); + frame += isr->Frame.offset; + bcopy(PTOV(frame), ptr, isr->BufferLength); + ptr += isr->BufferLength; + rsize += isr->BufferLength; + + bzero(isr, sizeof(*isr)); + isr->FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT; + pxe_call(PXENV_UNDI_ISR); + if (isr->Status != 0) { + free(buf); + return (-1); + } + + /* Did we got another update? */ + if (isr->FuncFlag == PXENV_UNDI_ISR_OUT_RECEIVE) + continue; + break; } - return len; + + *pkt = buf; + return (rsize); } -ssize_t -readudp(struct iodesc *h, void *pkt, size_t len, time_t timeout) +static ssize_t +pxe_netif_get(struct iodesc *desc, void **pkt, time_t timeout) { - t_PXENV_UDP_READ *udpread_p = (t_PXENV_UDP_READ *)scratch_buffer; - struct udphdr *uh = NULL; + time_t t; + void *ptr; + int ret = -1; - uh = (struct udphdr *) pkt - 1; - bzero(udpread_p, sizeof(*udpread_p)); + t = getsecs(); + while ((getsecs() - t) < timeout) { + ret = pxe_netif_receive(&ptr); + if (ret != -1) { + *pkt = ptr; + break; + } + } + return (ret); +} - udpread_p->dest_ip = h->myip.s_addr; - udpread_p->d_port = h->myport; - udpread_p->buffer_size = len; - udpread_p->buffer.segment = VTOPSEG(data_buffer); - udpread_p->buffer.offset = VTOPOFF(data_buffer); +static ssize_t +pxe_netif_put(struct iodesc *desc, void *pkt, size_t len) +{ + t_PXENV_UNDI_TRANSMIT *trans_p; + t_PXENV_UNDI_TBD *tbd_p; + char *data; - pxe_call(PXENV_UDP_READ); + trans_p = (t_PXENV_UNDI_TRANSMIT *)scratch_buffer; + bzero(trans_p, sizeof(*trans_p)); + tbd_p = (t_PXENV_UNDI_TBD *)(scratch_buffer + sizeof(*trans_p)); + bzero(tbd_p, sizeof(*tbd_p)); -#if 0 - /* XXX - I dont know why we need this. */ - delay(1000); -#endif - if (udpread_p->status != 0) { - /* XXX: This happens a lot. It shouldn't. */ - if (udpread_p->status != 1) - printf("readudp failed %x\n", udpread_p->status); - return -1; + data = scratch_buffer + sizeof(*trans_p) + sizeof(*tbd_p); + + trans_p->TBD.segment = VTOPSEG(tbd_p); + trans_p->TBD.offset = VTOPOFF(tbd_p); + + tbd_p->ImmedLength = len; + tbd_p->Xmit.segment = VTOPSEG(data); + tbd_p->Xmit.offset = VTOPOFF(data); + bcopy(pkt, data, len); + + pxe_call(PXENV_UNDI_TRANSMIT); + if (trans_p->Status != 0) { + return (-1); } - bcopy(data_buffer, pkt, udpread_p->buffer_size); - uh->uh_sport = udpread_p->s_port; - return udpread_p->buffer_size; + + return (len); } Index: head/sys/boot/i386/libi386/pxe.h =================================================================== --- head/sys/boot/i386/libi386/pxe.h (revision 317886) +++ head/sys/boot/i386/libi386/pxe.h (revision 317887) @@ -1,513 +1,513 @@ /* * Copyright (c) 2000 Alfred Perlstein * All rights reserved. * Copyright (c) 2000 Paul Saab * All rights reserved. * Copyright (c) 2000 John Baldwin * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ /* * The typedefs and structures declared in this file * clearly violate style(9), the reason for this is to conform to the * typedefs/structure-names used in the Intel literature to avoid confusion. * * It's for your own good. :) */ /* It seems that intel didn't think about ABI, * either that or 16bit ABI != 32bit ABI (which seems reasonable) * I have to thank Intel for the hair loss I incurred trying to figure * out why PXE was mis-reading structures I was passing it (at least * from my point of view) * * Solution: use gcc's '__packed' to correctly align * structures passed into PXE * Question: does this really work for PXE's expected ABI? */ #define PACKED __packed #define S_SIZE(s) s, sizeof(s) - 1 #define PXENFSROOTPATH "/pxeroot" typedef struct { uint16_t offset; uint16_t segment; } SEGOFF16_t; typedef struct { uint16_t Seg_Addr; uint32_t Phy_Addr; uint16_t Seg_Size; } SEGDESC_t; typedef uint16_t SEGSEL_t; typedef uint16_t PXENV_STATUS_t; typedef uint32_t IP4_t; typedef uint32_t ADDR32_t; typedef uint16_t UDP_PORT_t; #define MAC_ADDR_LEN 16 typedef uint8_t MAC_ADDR[MAC_ADDR_LEN]; /* PXENV+ */ typedef struct { uint8_t Signature[6]; /* 'PXENV+' */ uint16_t Version; /* MSB = major, LSB = minor */ uint8_t Length; /* structure length */ uint8_t Checksum; /* checksum pad */ SEGOFF16_t RMEntry; /* SEG:OFF to PXE entry point */ /* don't use PMOffset and PMSelector (from the 2.1 PXE manual) */ uint32_t PMOffset; /* Protected mode entry */ SEGSEL_t PMSelector; /* Protected mode selector */ SEGSEL_t StackSeg; /* Stack segment address */ uint16_t StackSize; /* Stack segment size (bytes) */ SEGSEL_t BC_CodeSeg; /* BC Code segment address */ uint16_t BC_CodeSize; /* BC Code segment size (bytes) */ SEGSEL_t BC_DataSeg; /* BC Data segment address */ uint16_t BC_DataSize; /* BC Data segment size (bytes) */ SEGSEL_t UNDIDataSeg; /* UNDI Data segment address */ uint16_t UNDIDataSize; /* UNDI Data segment size (bytes) */ SEGSEL_t UNDICodeSeg; /* UNDI Code segment address */ uint16_t UNDICodeSize; /* UNDI Code segment size (bytes) */ SEGOFF16_t PXEPtr; /* SEG:OFF to !PXE struct, only present when Version > 2.1 */ } PACKED pxenv_t; /* !PXE */ typedef struct { uint8_t Signature[4]; uint8_t StructLength; uint8_t StructCksum; uint8_t StructRev; uint8_t reserved_1; SEGOFF16_t UNDIROMID; SEGOFF16_t BaseROMID; SEGOFF16_t EntryPointSP; SEGOFF16_t EntryPointESP; SEGOFF16_t StatusCallout; uint8_t reserved_2; uint8_t SegDescCn; SEGSEL_t FirstSelector; SEGDESC_t Stack; SEGDESC_t UNDIData; SEGDESC_t UNDICode; SEGDESC_t UNDICodeWrite; SEGDESC_t BC_Data; SEGDESC_t BC_Code; SEGDESC_t BC_CodeWrite; } PACKED pxe_t; #define PXENV_START_UNDI 0x0000 typedef struct { PXENV_STATUS_t Status; uint16_t ax; uint16_t bx; uint16_t dx; uint16_t di; uint16_t es; } PACKED t_PXENV_START_UNDI; #define PXENV_UNDI_STARTUP 0x0001 typedef struct { PXENV_STATUS_t Status; } PACKED t_PXENV_UNDI_STARTUP; #define PXENV_UNDI_CLEANUP 0x0002 typedef struct { PXENV_STATUS_t Status; } PACKED t_PXENV_UNDI_CLEANUP; #define PXENV_UNDI_INITIALIZE 0x0003 typedef struct { PXENV_STATUS_t Status; ADDR32_t ProtocolIni; /* Phys addr of a copy of the driver module */ uint8_t reserved[8]; } PACKED t_PXENV_UNDI_INITALIZE; #define MAXNUM_MCADDR 8 typedef struct { PXENV_STATUS_t Status; uint16_t MCastAddrCount; MAC_ADDR McastAddr[MAXNUM_MCADDR]; } PACKED t_PXENV_UNDI_MCAST_ADDRESS; #define PXENV_UNDI_RESET_ADAPTER 0x0004 typedef struct { PXENV_STATUS_t Status; t_PXENV_UNDI_MCAST_ADDRESS R_Mcast_Buf; } PACKED t_PXENV_UNDI_RESET; #define PXENV_UNDI_SHUTDOWN 0x0005 typedef struct { PXENV_STATUS_t Status; } PACKED t_PXENV_UNDI_SHUTDOWN; #define PXENV_UNDI_OPEN 0x0006 typedef struct { PXENV_STATUS_t Status; uint16_t OpenFlag; uint16_t PktFilter; # define FLTR_DIRECTED 0x0001 # define FLTR_BRDCST 0x0002 # define FLTR_PRMSCS 0x0004 # define FLTR_SRC_RTG 0x0008 t_PXENV_UNDI_MCAST_ADDRESS R_Mcast_Buf; } PACKED t_PXENV_UNDI_OPEN; #define PXENV_UNDI_CLOSE 0x0007 typedef struct { PXENV_STATUS_t Status; } PACKED t_PXENV_UNDI_CLOSE; #define PXENV_UNDI_TRANSMIT 0x0008 typedef struct { PXENV_STATUS_t Status; uint8_t Protocol; # define P_UNKNOWN 0 # define P_IP 1 # define P_ARP 2 # define P_RARP 3 uint8_t XmitFlag; # define XMT_DESTADDR 0x0000 # define XMT_BROADCAST 0x0001 SEGOFF16_t DestAddr; SEGOFF16_t TBD; uint32_t Reserved[2]; } PACKED t_PXENV_UNDI_TRANSMIT; #define MAX_DATA_BLKS 8 typedef struct { uint16_t ImmedLength; SEGOFF16_t Xmit; uint16_t DataBlkCount; struct DataBlk { uint8_t TDPtrType; uint8_t TDRsvdByte; uint16_t TDDataLen; SEGOFF16_t TDDataPtr; } DataBlock[MAX_DATA_BLKS]; } PACKED t_PXENV_UNDI_TBD; #define PXENV_UNDI_SET_MCAST_ADDRESS 0x0009 typedef struct { PXENV_STATUS_t Status; t_PXENV_UNDI_MCAST_ADDRESS R_Mcast_Buf; } PACKED t_PXENV_UNDI_SET_MCAST_ADDR; #define PXENV_UNDI_SET_STATION_ADDRESS 0x000A typedef struct { PXENV_STATUS_t Status; MAC_ADDR StationAddress; /* Temp MAC address to use */ } PACKED t_PXENV_UNDI_SET_STATION_ADDR; #define PXENV_UNDI_SET_PACKET_FILTER 0x000B typedef struct { PXENV_STATUS_t Status; uint8_t filter; /* see UNDI_OPEN (0x0006) */ } PACKED t_PXENV_UNDI_SET_PACKET_FILTER; #define PXENV_UNDI_GET_INFORMATION 0x000C typedef struct { PXENV_STATUS_t Status; uint16_t BaseIo; /* Adapter base I/O address */ uint16_t IntNumber; /* Adapter IRQ number */ uint16_t MaxTranUnit; /* Adapter maximum transmit unit */ uint16_t HwType; /* Type of protocol at the hardware addr */ # define ETHER_TYPE 1 # define EXP_ETHER_TYPE 2 # define IEEE_TYPE 6 # define ARCNET_TYPE 7 uint16_t HwAddrLen; /* Length of hardware address */ MAC_ADDR CurrentNodeAddress; /* Current hardware address */ MAC_ADDR PermNodeAddress; /* Permanent hardware address */ SEGSEL_t ROMAddress; /* Real mode ROM segment address */ uint16_t RxBufCt; /* Receive queue length */ uint16_t TxBufCt; /* Transmit queue length */ } PACKED t_PXENV_UNDI_GET_INFORMATION; #define PXENV_UNDI_GET_STATISTICS 0x000D typedef struct { PXENV_STATUS_t Status; uint32_t XmitGoodFrames; /* Number of successful transmissions */ uint32_t RcvGoodFrames; /* Number of good frames received */ uint32_t RcvCRCErrors; /* Number of frames with CRC errors */ uint32_t RcvResourceErrors; /* Number of frames dropped */ } PACKED t_PXENV_UNDI_GET_STATISTICS; #define PXENV_UNDI_CLEAR_STATISTICS 0x000E typedef struct { PXENV_STATUS_t Status; } PACKED t_PXENV_UNDI_CLEAR_STATISTICS; #define PXENV_UNDI_INITIATE_DIAGS 0x000F typedef struct { PXENV_STATUS_t Status; } PACKED t_PXENV_UNDI_INITIATE_DIAGS; #define PXENV_UNDI_FORCE_INTERRUPT 0x0010 typedef struct { PXENV_STATUS_t Status; } PACKED t_PXENV_UNDI_FORCE_INTERRUPT; #define PXENV_UNDI_GET_MCAST_ADDRESS 0x0011 typedef struct { PXENV_STATUS_t Status; IP4_t InetAddr; /* IP mulicast address */ MAC_ADDR MediaAddr; /* MAC multicast address */ } PACKED t_PXENV_UNDI_GET_MCAST_ADDR; #define PXENV_UNDI_GET_NIC_TYPE 0x0012 typedef struct { PXENV_STATUS_t Status; uint8_t NicType; /* Type of NIC */ # define PCI_NIC 2 # define PnP_NIC 3 # define CardBus_NIC 4 union { struct { uint16_t Vendor_ID; uint16_t Dev_ID; uint8_t Base_Class; uint8_t Sub_Class; uint8_t Prog_Intf; uint8_t Rev; uint16_t BusDevFunc; uint16_t SubVendor_ID; uint16_t SubDevice_ID; } pci, cardbus; struct { uint32_t EISA_Dev_ID; uint8_t Base_Class; uint8_t Sub_Class; uint8_t Prog_Intf; uint16_t CardSelNum; } pnp; } info; } PACKED t_PXENV_UNDI_GET_NIC_TYPE; #define PXENV_UNDI_GET_IFACE_INFO 0x0013 typedef struct { PXENV_STATUS_t Status; uint8_t IfaceType[16]; /* Name of MAC type in ASCII. */ uint32_t LinkSpeed; /* Defined in NDIS 2.0 spec */ uint32_t ServiceFlags; /* Defined in NDIS 2.0 spec */ uint32_t Reserved[4]; /* must be 0 */ } PACKED t_PXENV_UNDI_GET_NDIS_INFO; #define PXENV_UNDI_ISR 0x0014 typedef struct { PXENV_STATUS_t Status; uint16_t FuncFlag; /* PXENV_UNDI_ISR_OUT_xxx */ uint16_t BufferLength; /* Length of Frame */ uint16_t FrameLength; /* Total length of receiver frame */ uint16_t FrameHeaderLength; /* Length of the media header in Frame */ SEGOFF16_t Frame; /* receive buffer */ uint8_t ProtType; /* Protocol type */ uint8_t PktType; /* Packet Type */ # define PXENV_UNDI_ISR_IN_START 1 # define PXENV_UNDI_ISR_IN_PROCESS 2 # define PXENV_UNDI_ISR_IN_GET_NEXT 3 /* one of these will be returned for PXENV_UNDI_ISR_IN_START */ # define PXENV_UNDI_ISR_OUT_OURS 0 # define PXENV_UNDI_ISR_OUT_NOT_OUTS 1 /* * one of these will bre returned for PXEND_UNDI_ISR_IN_PROCESS * and PXENV_UNDI_ISR_IN_GET_NEXT */ # define PXENV_UNDI_ISR_OUT_DONE 0 # define PXENV_UNDI_ISR_OUT_TRANSMIT 2 -# define PXENV_UNDI_ISR_OUT_RECIEVE 3 +# define PXENV_UNDI_ISR_OUT_RECEIVE 3 # define PXENV_UNDI_ISR_OUT_BUSY 4 } PACKED t_PXENV_UNDI_ISR; #define PXENV_STOP_UNDI 0x0015 typedef struct { PXENV_STATUS_t Status; } PACKED t_PXENV_STOP_UNDI; #define PXENV_TFTP_OPEN 0x0020 typedef struct { PXENV_STATUS_t Status; IP4_t ServerIPAddress; IP4_t GatewayIPAddress; uint8_t FileName[128]; UDP_PORT_t TFTPPort; uint16_t PacketSize; } PACKED t_PXENV_TFTP_OPEN; #define PXENV_TFTP_CLOSE 0x0021 typedef struct { PXENV_STATUS_t Status; } PACKED t_PXENV_TFTP_CLOSE; #define PXENV_TFTP_READ 0x0022 typedef struct { PXENV_STATUS_t Status; uint16_t PacketNumber; uint16_t BufferSize; SEGOFF16_t Buffer; } PACKED t_PXENV_TFTP_READ; #define PXENV_TFTP_READ_FILE 0x0023 typedef struct { PXENV_STATUS_t Status; uint8_t FileName[128]; uint32_t BufferSize; ADDR32_t Buffer; IP4_t ServerIPAddress; IP4_t GatewayIPAdress; IP4_t McastIPAdress; UDP_PORT_t TFTPClntPort; UDP_PORT_t TFTPSrvPort; uint16_t TFTPOpenTimeOut; uint16_t TFTPReopenDelay; } PACKED t_PXENV_TFTP_READ_FILE; #define PXENV_TFTP_GET_FSIZE 0x0025 typedef struct { PXENV_STATUS_t Status; IP4_t ServerIPAddress; IP4_t GatewayIPAdress; uint8_t FileName[128]; uint32_t FileSize; } PACKED t_PXENV_TFTP_GET_FSIZE; #define PXENV_UDP_OPEN 0x0030 typedef struct { PXENV_STATUS_t status; IP4_t src_ip; /* IP address of this station */ } PACKED t_PXENV_UDP_OPEN; #define PXENV_UDP_CLOSE 0x0031 typedef struct { PXENV_STATUS_t status; } PACKED t_PXENV_UDP_CLOSE; #define PXENV_UDP_READ 0x0032 typedef struct { PXENV_STATUS_t status; IP4_t src_ip; /* IP of sender */ IP4_t dest_ip; /* Only accept packets sent to this IP */ UDP_PORT_t s_port; /* UDP source port of sender */ UDP_PORT_t d_port; /* Only accept packets sent to this port */ uint16_t buffer_size; /* Size of the packet buffer */ SEGOFF16_t buffer; /* SEG:OFF to the packet buffer */ } PACKED t_PXENV_UDP_READ; #define PXENV_UDP_WRITE 0x0033 typedef struct { PXENV_STATUS_t status; IP4_t ip; /* dest ip addr */ IP4_t gw; /* ip gateway */ UDP_PORT_t src_port; /* source udp port */ UDP_PORT_t dst_port; /* destination udp port */ uint16_t buffer_size; /* Size of the packet buffer */ SEGOFF16_t buffer; /* SEG:OFF to the packet buffer */ } PACKED t_PXENV_UDP_WRITE; #define PXENV_UNLOAD_STACK 0x0070 typedef struct { PXENV_STATUS_t Status; uint8_t reserved[10]; } PACKED t_PXENV_UNLOAD_STACK; #define PXENV_GET_CACHED_INFO 0x0071 typedef struct { PXENV_STATUS_t Status; uint16_t PacketType; /* type (defined right here) */ # define PXENV_PACKET_TYPE_DHCP_DISCOVER 1 # define PXENV_PACKET_TYPE_DHCP_ACK 2 # define PXENV_PACKET_TYPE_BINL_REPLY 3 uint16_t BufferSize; /* max to copy, leave at 0 for pointer */ SEGOFF16_t Buffer; /* copy to, leave at 0 for pointer */ uint16_t BufferLimit; /* max size of buffer in BC dataseg ? */ } PACKED t_PXENV_GET_CACHED_INFO; /* structure filled in by PXENV_GET_CACHED_INFO * (how we determine which IP we downloaded the initial bootstrap from) * words can't describe... */ typedef struct { uint8_t opcode; # define BOOTP_REQ 1 # define BOOTP_REP 2 uint8_t Hardware; /* hardware type */ uint8_t Hardlen; /* hardware addr len */ uint8_t Gatehops; /* zero it */ uint32_t ident; /* random number chosen by client */ uint16_t seconds; /* seconds since did initial bootstrap */ uint16_t Flags; /* seconds since did initial bootstrap */ # define BOOTP_BCAST 0x8000 /* ? */ IP4_t cip; /* Client IP */ IP4_t yip; /* Your IP */ IP4_t sip; /* IP to use for next boot stage */ IP4_t gip; /* Relay IP ? */ MAC_ADDR CAddr; /* Client hardware address */ uint8_t Sname[64]; /* Server's hostname (Optional) */ uint8_t bootfile[128]; /* boot filename */ union { # if 1 # define BOOTP_DHCPVEND 1024 /* DHCP extended vendor field size */ # else # define BOOTP_DHCPVEND 312 /* DHCP standard vendor field size */ # endif uint8_t d[BOOTP_DHCPVEND]; /* raw array of vendor/dhcp options */ struct { uint8_t magic[4]; /* DHCP magic cookie */ # ifndef VM_RFC1048 # define VM_RFC1048 0x63825363L /* ? */ # endif uint32_t flags; /* bootp flags/opcodes */ uint8_t pad[56]; /* I don't think intel knows what a union does... */ } v; } vendor; } PACKED BOOTPLAYER; #define PXENV_RESTART_TFTP 0x0073 #define t_PXENV_RESTART_TFTP t_PXENV_TFTP_READ_FILE #define PXENV_START_BASE 0x0075 typedef struct { PXENV_STATUS_t Status; } PACKED t_PXENV_START_BASE; #define PXENV_STOP_BASE 0x0076 typedef struct { PXENV_STATUS_t Status; } PACKED t_PXENV_STOP_BASE; Index: head/sys/boot/i386/loader/Makefile =================================================================== --- head/sys/boot/i386/loader/Makefile (revision 317886) +++ head/sys/boot/i386/loader/Makefile (revision 317887) @@ -1,134 +1,139 @@ # $FreeBSD$ .include MK_SSP= no LOADER?= loader PROG= ${LOADER}.sym MAN= INTERNALPROG= NEWVERSWHAT?= "bootstrap loader" x86 VERSION_FILE= ${.CURDIR}/../loader/version +LOADER_NET_SUPPORT?= yes # architecture-specific loader code SRCS= main.c conf.c vers.c # Put LOADER_FIREWIRE_SUPPORT=yes in /etc/make.conf for FireWire/dcons support .if defined(LOADER_FIREWIRE_SUPPORT) CFLAGS+= -DLOADER_FIREWIRE_SUPPORT LIBFIREWIRE= ${.OBJDIR}/../libfirewire/libfirewire.a .endif # Set by zfsloader Makefile .if defined(LOADER_ZFS_SUPPORT) CFLAGS+= -DLOADER_ZFS_SUPPORT LIBZFSBOOT= ${.OBJDIR}/../../zfs/libzfsboot.a +.endif + +.if defined(LOADER_NET_SUPPORT) +CFLAGS+= -I${.CURDIR}/../../../../lib/libstand .endif # Enable PXE TFTP or NFS support, not both. .if defined(LOADER_TFTP_SUPPORT) CFLAGS+= -DLOADER_TFTP_SUPPORT .else CFLAGS+= -DLOADER_NFS_SUPPORT .endif # Include bcache code. HAVE_BCACHE= yes # Enable PnP and ISA-PnP code. HAVE_PNP= yes HAVE_ISABUS= yes .if ${MK_FORTH} != "no" # Enable BootForth BOOT_FORTH= yes CFLAGS+= -DBOOT_FORTH -I${.CURDIR}/../../ficl -I${.CURDIR}/../../ficl/i386 .if ${MACHINE_CPUARCH} == "amd64" LIBFICL= ${.OBJDIR}/../../ficl32/libficl.a .else LIBFICL= ${.OBJDIR}/../../ficl/libficl.a .endif .endif .if defined(LOADER_BZIP2_SUPPORT) CFLAGS+= -DLOADER_BZIP2_SUPPORT .endif .if !defined(LOADER_NO_GZIP_SUPPORT) CFLAGS+= -DLOADER_GZIP_SUPPORT .endif .if defined(LOADER_NANDFS_SUPPORT) CFLAGS+= -DLOADER_NANDFS_SUPPORT .endif .if !defined(LOADER_NO_GELI_SUPPORT) CFLAGS+= -DLOADER_GELI_SUPPORT CFLAGS+= -I${.CURDIR}/../../geli LIBGELIBOOT= ${.OBJDIR}/../../geli/libgeliboot.a .PATH: ${.CURDIR}/../../../opencrypto SRCS+= xform_aes_xts.c CFLAGS+= -I${.CURDIR}/../../.. -D_STAND .endif # Always add MI sources .PATH: ${.CURDIR}/../../common .include "${.CURDIR}/../../common/Makefile.inc" CFLAGS+= -I${.CURDIR}/../../common CFLAGS+= -I. CLEANFILES= ${LOADER} ${LOADER}.bin loader.help CFLAGS+= -Wall LDFLAGS= -static -Ttext 0x0 # i386 standalone support library LIBI386= ${.OBJDIR}/../libi386/libi386.a CFLAGS+= -I${.CURDIR}/.. LIBSTAND= ${.OBJDIR}/../../libstand32/libstand.a # BTX components CFLAGS+= -I${.CURDIR}/../btx/lib # Debug me! #CFLAGS+= -g #LDFLAGS+= -g # Pick up ../Makefile.inc early. .include ${LOADER}: ${LOADER}.bin ${BTXLDR} ${BTXKERN} btxld -v -f aout -e ${LOADER_ADDRESS} -o ${.TARGET} -l ${BTXLDR} \ -b ${BTXKERN} ${LOADER}.bin ${LOADER}.bin: ${LOADER}.sym strip -R .comment -R .note -o ${.TARGET} ${.ALLSRC} loader.help: help.common help.i386 cat ${.ALLSRC} | awk -f ${.CURDIR}/../../common/merge_help.awk > ${.TARGET} FILES= ${LOADER} # XXX INSTALLFLAGS_loader= -b FILESMODE_${LOADER}= ${BINMODE} -b .if !defined(LOADER_ONLY) .PATH: ${.CURDIR}/../../forth .include "${.CURDIR}/../../forth/Makefile.inc" FILES+= pcibios.4th FILES+= loader.rc menu.rc .endif # XXX crt0.o needs to be first for pxeboot(8) to work OBJS= ${BTXCRT} DPADD= ${LIBFICL} ${LIBFIREWIRE} ${LIBZFSBOOT} ${LIBI386} ${LIBGELIBOOT} ${LIBSTAND} LDADD= ${LIBFICL} ${LIBFIREWIRE} ${LIBZFSBOOT} ${LIBI386} ${LIBGELIBOOT} ${LIBSTAND} .include .if ${MACHINE_CPUARCH} == "amd64" beforedepend ${OBJS}: machine CLEANFILES+= machine CFLAGS+= -DLOADER_PREFER_AMD64 machine: .NOMETA ln -sf ${.CURDIR}/../../../i386/include machine .endif Index: head/sys/boot/ofw/libofw/ofw_net.c =================================================================== --- head/sys/boot/ofw/libofw/ofw_net.c (revision 317886) +++ head/sys/boot/ofw/libofw/ofw_net.c (revision 317887) @@ -1,260 +1,275 @@ /*- * Copyright (c) 2000-2001 Benno Rice * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include "openfirm.h" static int ofwn_probe(struct netif *, void *); static int ofwn_match(struct netif *, void *); static void ofwn_init(struct iodesc *, void *); -static int ofwn_get(struct iodesc *, void *, size_t, time_t); -static int ofwn_put(struct iodesc *, void *, size_t); +static ssize_t ofwn_get(struct iodesc *, void **, time_t); +static ssize_t ofwn_put(struct iodesc *, void *, size_t); static void ofwn_end(struct netif *); extern struct netif_stats ofwn_stats[]; struct netif_dif ofwn_ifs[] = { /* dif_unit dif_nsel dif_stats dif_private */ { 0, 1, &ofwn_stats[0], 0, }, }; -struct netif_stats ofwn_stats[NENTS(ofwn_ifs)]; +struct netif_stats ofwn_stats[nitems(ofwn_ifs)]; struct netif_driver ofwnet = { "net", /* netif_bname */ ofwn_match, /* netif_match */ ofwn_probe, /* netif_probe */ ofwn_init, /* netif_init */ ofwn_get, /* netif_get */ ofwn_put, /* netif_put */ ofwn_end, /* netif_end */ ofwn_ifs, /* netif_ifs */ - NENTS(ofwn_ifs) /* netif_nifs */ + nitems(ofwn_ifs) /* netif_nifs */ }; static ihandle_t netinstance; static void *dmabuf; static int ofwn_match(struct netif *nif, void *machdep_hint) { return 1; } static int ofwn_probe(struct netif *nif, void *machdep_hint) { return 0; } -static int +static ssize_t ofwn_put(struct iodesc *desc, void *pkt, size_t len) { size_t sendlen; ssize_t rv; #if defined(NETIF_DEBUG) struct ether_header *eh; printf("netif_put: desc=0x%x pkt=0x%x len=%d\n", desc, pkt, len); eh = pkt; printf("dst: %s ", ether_sprintf(eh->ether_dhost)); printf("src: %s ", ether_sprintf(eh->ether_shost)); printf("type: 0x%x\n", eh->ether_type & 0xffff); #endif sendlen = len; if (sendlen < 60) { sendlen = 60; #if defined(NETIF_DEBUG) printf("netif_put: length padded to %d\n", sendlen); #endif } if (dmabuf) { bcopy(pkt, dmabuf, sendlen); pkt = dmabuf; } rv = OF_write(netinstance, pkt, len); #if defined(NETIF_DEBUG) printf("netif_put: OF_write returned %d\n", rv); #endif return rv; } -static int -ofwn_get(struct iodesc *desc, void *pkt, size_t len, time_t timeout) +static ssize_t +ofwn_get(struct iodesc *desc, void **pkt, time_t timeout) { time_t t; - int length; + ssize_t length; + size_t len; + char *buf, *ptr; #if defined(NETIF_DEBUG) - printf("netif_get: pkt=%p, maxlen=%d, timeout=%d\n", pkt, len, - timeout); + printf("netif_get: pkt=%p, timeout=%d\n", pkt, timeout); #endif + /* + * We should read the "max-frame-size" int property instead, + * but at this time the iodesc does not have mtu, so we will take + * a small shortcut here. + */ + len = ETHER_MAX_LEN; + buf = malloc(len + ETHER_ALIGN); + if (buf == NULL) + return (-1); + ptr = buf + ETHER_ALIGN; + t = getsecs(); do { - length = OF_read(netinstance, pkt, len); + length = OF_read(netinstance, ptr, len); } while ((length == -2 || length == 0) && (getsecs() - t < timeout)); #if defined(NETIF_DEBUG) printf("netif_get: received length=%d (%x)\n", length, length); #endif - if (length < 12) - return -1; + if (length < 12) { + free(buf); + return (-1); + } #if defined(NETIF_VERBOSE_DEBUG) { - char *ch = pkt; + char *ch = ptr; int i; for(i = 0; i < 96; i += 4) { printf("%02x%02x%02x%02x ", ch[i], ch[i+1], ch[i+2], ch[i+3]); } printf("\n"); } #endif #if defined(NETIF_DEBUG) { - struct ether_header *eh = pkt; + struct ether_header *eh = ptr; printf("dst: %s ", ether_sprintf(eh->ether_dhost)); printf("src: %s ", ether_sprintf(eh->ether_shost)); printf("type: 0x%x\n", eh->ether_type & 0xffff); } #endif - return length; + *pkt = buf; + return (length); } extern char *strchr(); static void ofwn_init(struct iodesc *desc, void *machdep_hint) { phandle_t netdev; char path[64]; char *ch; int pathlen; pathlen = OF_getprop(chosen, "bootpath", path, 64); if ((ch = strchr(path, ':')) != NULL) *ch = '\0'; netdev = OF_finddevice(path); #ifdef __sparc64__ if (OF_getprop(netdev, "mac-address", desc->myea, 6) == -1) #else if (OF_getprop(netdev, "local-mac-address", desc->myea, 6) == -1) #endif goto punt; printf("boot: ethernet address: %s\n", ether_sprintf(desc->myea)); if ((netinstance = OF_open(path)) == -1) { printf("Could not open network device.\n"); goto punt; } #if defined(NETIF_DEBUG) printf("ofwn_init: Open Firmware instance handle: %08x\n", netinstance); #endif #ifndef __sparc64__ dmabuf = NULL; if (OF_call_method("dma-alloc", netinstance, 1, 1, (64 * 1024), &dmabuf) < 0) { printf("Failed to allocate DMA buffer (got %08x).\n", dmabuf); goto punt; } #if defined(NETIF_DEBUG) printf("ofwn_init: allocated DMA buffer: %08x\n", dmabuf); #endif #endif return; punt: printf("\n"); printf("Could not boot from %s.\n", path); OF_enter(); } static void ofwn_end(struct netif *nif) { #ifdef BROKEN /* dma-free freezes at least some Apple ethernet controllers */ OF_call_method("dma-free", netinstance, 2, 0, dmabuf, MAXPHYS); #endif OF_close(netinstance); } #if 0 int ofwn_getunit(const char *path) { int i; char newpath[255]; OF_canon(path, newpath, 254); for (i = 0; i < nofwninfo; i++) { printf(">>> test =\t%s\n", ofwninfo[i].ofwn_path); if (strcmp(path, ofwninfo[i].ofwn_path) == 0) return i; if (strcmp(newpath, ofwninfo[i].ofwn_path) == 0) return i; } return -1; } #endif Index: head/sys/boot/uboot/lib/net.c =================================================================== --- head/sys/boot/uboot/lib/net.c (revision 317886) +++ head/sys/boot/uboot/lib/net.c (revision 317887) @@ -1,362 +1,364 @@ /*- * Copyright (c) 2000-2001 Benno Rice * Copyright (c) 2007 Semihalf, Rafal Jaworowski * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include "api_public.h" #include "glue.h" #include "libuboot.h" #include "dev_net.h" static int net_probe(struct netif *, void *); static int net_match(struct netif *, void *); static void net_init(struct iodesc *, void *); -static int net_get(struct iodesc *, void *, size_t, time_t); -static int net_put(struct iodesc *, void *, size_t); +static ssize_t net_get(struct iodesc *, void **, time_t); +static ssize_t net_put(struct iodesc *, void *, size_t); static void net_end(struct netif *); extern struct netif_stats net_stats[]; struct netif_dif net_ifs[] = { /* dif_unit dif_nsel dif_stats dif_private */ { 0, 1, &net_stats[0], 0, }, }; -struct netif_stats net_stats[NENTS(net_ifs)]; +struct netif_stats net_stats[nitems(net_ifs)]; struct netif_driver uboot_net = { "uboot_eth", /* netif_bname */ net_match, /* netif_match */ net_probe, /* netif_probe */ net_init, /* netif_init */ net_get, /* netif_get */ net_put, /* netif_put */ net_end, /* netif_end */ net_ifs, /* netif_ifs */ - NENTS(net_ifs) /* netif_nifs */ + nitems(net_ifs) /* netif_nifs */ }; struct uboot_softc { uint32_t sc_pad; uint8_t sc_rxbuf[ETHER_MAX_LEN]; uint8_t sc_txbuf[ETHER_MAX_LEN + PKTALIGN]; uint8_t *sc_txbufp; int sc_handle; /* device handle for ub_dev_xxx */ }; static struct uboot_softc uboot_softc; /* * get_env_net_params() * * Attempt to obtain all the parms we need for netbooting from the U-Boot * environment. If we fail to obtain the values it may still be possible to * netboot; the net_dev code will attempt to get the values from bootp, rarp, * and other such sources. * * If rootip.s_addr is non-zero net_dev assumes the required global variables * are set and skips the bootp inquiry. For that reason, we don't set rootip * until we've verified that we have at least the minimum required info. * * This is called from netif_init() which can result in it getting called * multiple times, by design. The network code at higher layers zeroes out * rootip when it closes a network interface, so if it gets opened again we have * to obtain all this info again. */ static void get_env_net_params() { char *envstr; in_addr_t rootaddr, serveraddr; /* * Silently get out right away if we don't have rootpath, because none * of the other info we obtain below is sufficient to boot without it. * * If we do have rootpath, copy it into the global var and also set * dhcp.root-path in the env. If we don't get all the other info from * the u-boot env below, we will still try dhcp/bootp, but the server- * provided path will not replace the user-provided value we set here. */ if ((envstr = ub_env_get("rootpath")) == NULL) return; strlcpy(rootpath, envstr, sizeof(rootpath)); setenv("dhcp.root-path", rootpath, 0); /* * Our own IP address must be valid. Silently get out if it's not set, * but whine if it's there and we can't parse it. */ if ((envstr = ub_env_get("ipaddr")) == NULL) return; if ((myip.s_addr = inet_addr(envstr)) == INADDR_NONE) { printf("Could not parse ipaddr '%s'\n", envstr); return; } /* * Netmask is optional, default to the "natural" netmask for our IP, but * whine if it was provided and we couldn't parse it. */ if ((envstr = ub_env_get("netmask")) != NULL && (netmask = inet_addr(envstr)) == INADDR_NONE) { printf("Could not parse netmask '%s'\n", envstr); } if (netmask == INADDR_NONE) { if (IN_CLASSA(myip.s_addr)) netmask = IN_CLASSA_NET; else if (IN_CLASSB(myip.s_addr)) netmask = IN_CLASSB_NET; else netmask = IN_CLASSC_NET; } /* * Get optional serverip before rootpath; the latter can override it. * Whine only if it's present but can't be parsed. */ serveraddr = INADDR_NONE; if ((envstr = ub_env_get("serverip")) != NULL) { if ((serveraddr = inet_addr(envstr)) == INADDR_NONE) printf("Could not parse serverip '%s'\n", envstr); } /* * There must be a rootpath. It may be ip:/path or it may be just the * path in which case the ip needs to be in serverip. */ rootaddr = net_parse_rootpath(); if (rootaddr == INADDR_NONE) rootaddr = serveraddr; if (rootaddr == INADDR_NONE) { printf("No server address for rootpath '%s'\n", envstr); return; } rootip.s_addr = rootaddr; /* * Gateway IP is optional unless rootip is on a different net in which * case whine if it's missing or we can't parse it, and set rootip addr * to zero, which signals to other network code that network params * aren't set (so it will try dhcp, bootp, etc). */ envstr = ub_env_get("gatewayip"); if (!SAMENET(myip, rootip, netmask)) { if (envstr == NULL) { printf("Need gatewayip for a root server on a " "different network.\n"); rootip.s_addr = 0; return; } if ((gateip.s_addr = inet_addr(envstr) == INADDR_NONE)) { printf("Could not parse gatewayip '%s'\n", envstr); rootip.s_addr = 0; return; } } } static int net_match(struct netif *nif, void *machdep_hint) { char **a = (char **)machdep_hint; if (memcmp("net", *a, 3) == 0) return (1); printf("net_match: could not match network device\n"); return (0); } static int net_probe(struct netif *nif, void *machdep_hint) { struct device_info *di; int i; for (i = 0; i < devs_no; i++) if ((di = ub_dev_get(i)) != NULL) if (di->type == DEV_TYP_NET) break; if (i == devs_no) { printf("net_probe: no network devices found, maybe not" " enumerated yet..?\n"); return (-1); } #if defined(NETIF_DEBUG) printf("net_probe: network device found: %d\n", i); #endif uboot_softc.sc_handle = i; return (0); } -static int +static ssize_t net_put(struct iodesc *desc, void *pkt, size_t len) { struct netif *nif = desc->io_netif; struct uboot_softc *sc = nif->nif_devdata; size_t sendlen; ssize_t rv; #if defined(NETIF_DEBUG) struct ether_header *eh; printf("net_put: desc %p, pkt %p, len %d\n", desc, pkt, len); eh = pkt; printf("dst: %s ", ether_sprintf(eh->ether_dhost)); printf("src: %s ", ether_sprintf(eh->ether_shost)); printf("type: 0x%x\n", eh->ether_type & 0xffff); #endif if (len < ETHER_MIN_LEN - ETHER_CRC_LEN) { sendlen = ETHER_MIN_LEN - ETHER_CRC_LEN; bzero(sc->sc_txbufp, sendlen); } else sendlen = len; memcpy(sc->sc_txbufp, pkt, len); rv = ub_dev_send(sc->sc_handle, sc->sc_txbufp, sendlen); #if defined(NETIF_DEBUG) printf("net_put: ub_send returned %d\n", rv); #endif if (rv == 0) rv = len; else rv = -1; return (rv); } -static int -net_get(struct iodesc *desc, void *pkt, size_t len, time_t timeout) +static ssize_t +net_get(struct iodesc *desc, void **pkt, time_t timeout) { struct netif *nif = desc->io_netif; struct uboot_softc *sc = nif->nif_devdata; time_t t; int err, rlen; + size_t len; + char *buf; #if defined(NETIF_DEBUG) - printf("net_get: pkt %p, len %d, timeout %d\n", pkt, len, timeout); + printf("net_get: pkt %p, timeout %d\n", pkt, timeout); #endif t = getsecs(); + len = sizeof(sc->sc_rxbuf); do { err = ub_dev_recv(sc->sc_handle, sc->sc_rxbuf, len, &rlen); if (err != 0) { printf("net_get: ub_dev_recv() failed, error=%d\n", err); rlen = 0; break; } } while ((rlen == -1 || rlen == 0) && (getsecs() - t < timeout)); #if defined(NETIF_DEBUG) printf("net_get: received len %d (%x)\n", rlen, rlen); #endif if (rlen > 0) { - memcpy(pkt, sc->sc_rxbuf, MIN(len, rlen)); - if (rlen != len) { -#if defined(NETIF_DEBUG) - printf("net_get: len %x, rlen %x\n", len, rlen); -#endif - } - return (rlen); + buf = malloc(rlen + ETHER_ALIGN); + if (buf == NULL) + return (-1); + memcpy(buf + ETHER_ALIGN, sc->sc_rxbuf, rlen); + *pkt = buf; + return ((ssize_t)rlen); } return (-1); } static void net_init(struct iodesc *desc, void *machdep_hint) { struct netif *nif = desc->io_netif; struct uboot_softc *sc; struct device_info *di; int err; sc = nif->nif_devdata = &uboot_softc; if ((err = ub_dev_open(sc->sc_handle)) != 0) panic("%s%d: initialisation failed with error %d\n", nif->nif_driver->netif_bname, nif->nif_unit, err); /* Get MAC address */ di = ub_dev_get(sc->sc_handle); memcpy(desc->myea, di->di_net.hwaddr, 6); if (memcmp (desc->myea, "\0\0\0\0\0\0", 6) == 0) { panic("%s%d: empty ethernet address!", nif->nif_driver->netif_bname, nif->nif_unit); } /* Attempt to get netboot params from the u-boot env. */ get_env_net_params(); if (myip.s_addr != 0) desc->myip = myip; #if defined(NETIF_DEBUG) printf("network: %s%d attached to %s\n", nif->nif_driver->netif_bname, nif->nif_unit, ether_sprintf(desc->myea)); #endif /* Set correct alignment for TX packets */ sc->sc_txbufp = sc->sc_txbuf; if ((unsigned long)sc->sc_txbufp % PKTALIGN) sc->sc_txbufp += PKTALIGN - (unsigned long)sc->sc_txbufp % PKTALIGN; } static void net_end(struct netif *nif) { struct uboot_softc *sc = nif->nif_devdata; int err; if ((err = ub_dev_close(sc->sc_handle)) != 0) panic("%s%d: net_end failed with error %d\n", nif->nif_driver->netif_bname, nif->nif_unit, err); }