Index: lib/libstand/arp.c =================================================================== --- lib/libstand/arp.c +++ lib/libstand/arp.c @@ -65,17 +65,16 @@ /* 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 { @@ -83,13 +82,6 @@ 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) @@ -122,20 +114,24 @@ /* 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 + 2); 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)); } @@ -143,14 +139,12 @@ 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 @@ -166,28 +160,27 @@ * 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); } @@ -196,12 +189,11 @@ 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) || @@ -211,6 +203,7 @@ if (debug) printf("bad hrd/pro/hln/pln\n"); #endif + free(ptr); return (-1); } @@ -220,6 +213,7 @@ printf("is request\n"); #endif arp_reply(d, ah); + free(ptr); return (-1); } @@ -228,6 +222,7 @@ if (debug) printf("not ARP reply\n"); #endif + free(ptr); return (-1); } @@ -239,6 +234,7 @@ if (debug) printf("unwanted address\n"); #endif + free(ptr); return (-1); } /* We don't care who the reply was sent to. */ @@ -248,6 +244,8 @@ if (debug) printf("got it\n"); #endif + *pkt = ptr; + *payload = ah; return (n); } @@ -256,9 +254,7 @@ * 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; Index: lib/libstand/bootp.h =================================================================== --- lib/libstand/bootp.h +++ lib/libstand/bootp.h @@ -148,6 +148,10 @@ /* 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: lib/libstand/bootp.c =================================================================== --- lib/libstand/bootp.c +++ lib/libstand/bootp.c @@ -38,6 +38,7 @@ #include __FBSDID("$FreeBSD$"); +#include #include #include #include @@ -72,7 +73,7 @@ /* 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 *); @@ -89,23 +90,21 @@ 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) @@ -176,8 +175,7 @@ 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; } @@ -188,7 +186,7 @@ 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); @@ -206,20 +204,21 @@ 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) { @@ -259,14 +258,12 @@ /* 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; @@ -287,30 +284,26 @@ } 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 = 0x%p, n = %d\n", + (void *)bp, (int)n); #endif if (bp->bp_xid != htonl(d->xid)) { #ifdef BOOTP_DEBUG @@ -329,8 +322,21 @@ /* 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) @@ -339,8 +345,11 @@ 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); } @@ -357,9 +366,7 @@ } 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; @@ -450,8 +457,7 @@ #ifdef BOOTP_VEND_CMU static void -vend_cmu(cp) - u_char *cp; +vend_cmu(u_char *cp) { struct cmu_vend *vp; Index: lib/libstand/bootparam.c =================================================================== --- lib/libstand/bootparam.c +++ lib/libstand/bootparam.c @@ -104,8 +104,7 @@ * 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 { @@ -126,13 +125,10 @@ 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 = -1; RPC_PRINTF(("bp_whoami: myip=%s\n", inet_ntoa(myip))); @@ -141,7 +137,6 @@ return (-1); } args = &sdata.d; - repl = &rdata.d; /* * Build request args for PMAPPROC_CALLIT. @@ -163,12 +158,12 @@ 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). */ @@ -196,7 +191,7 @@ 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; @@ -204,24 +199,27 @@ 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); } @@ -233,25 +231,18 @@ * 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)); @@ -259,7 +250,6 @@ } send_tail = (char*) sdata.d; - recv_head = (char*) rdata.d; /* * Build request message. @@ -281,17 +271,16 @@ 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. @@ -299,26 +288,29 @@ /* 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); } @@ -329,17 +321,14 @@ 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; 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); @@ -351,10 +340,7 @@ } 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; char *datap; @@ -362,7 +348,7 @@ 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; @@ -381,9 +367,7 @@ 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; @@ -414,9 +398,7 @@ } 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; Index: lib/libstand/ether.c =================================================================== --- lib/libstand/ether.c +++ lib/libstand/ether.c @@ -54,12 +54,7 @@ /* 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; @@ -86,32 +81,31 @@ /* * 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 + 2); /* Validate Ethernet address. */ if (bcmp(d->myea, eh->ether_dhost, 6) != 0 && bcmp(bcea, eh->ether_dhost, 6) != 0) { @@ -120,8 +114,12 @@ 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); @@ -133,8 +131,7 @@ */ static char digits[] = "0123456789abcdef"; char * -ether_sprintf(ap) - u_char *ap; +ether_sprintf(u_char *ap) { int i; static char etherbuf[18]; Index: lib/libstand/net.h =================================================================== --- lib/libstand/net.h +++ lib/libstand/net.h @@ -107,16 +107,15 @@ /* 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); Index: lib/libstand/net.c =================================================================== --- lib/libstand/net.c +++ lib/libstand/net.c @@ -70,10 +70,10 @@ */ 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; @@ -116,7 +116,7 @@ } /* 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); Index: lib/libstand/netif.h =================================================================== --- lib/libstand/netif.h +++ lib/libstand/netif.h @@ -6,15 +6,13 @@ #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; @@ -56,7 +54,7 @@ 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 *); Index: lib/libstand/netif.c =================================================================== --- lib/libstand/netif.c +++ lib/libstand/netif.c @@ -59,7 +59,7 @@ */ void -netif_init() +netif_init(void) { struct netif_driver *drv; int d, i; @@ -76,13 +76,11 @@ } 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); @@ -91,8 +89,7 @@ } struct netif * -netif_select(machdep_hint) - void *machdep_hint; +netif_select(void *machdep_hint) { int d, u, unit_done, s; struct netif_driver *drv; @@ -162,9 +159,7 @@ } 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; @@ -176,10 +171,7 @@ } 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; @@ -199,8 +191,7 @@ } void -netif_detach(nif) - struct netif *nif; +netif_detach(struct netif *nif) { struct netif_driver *drv = nif->nif_driver; @@ -217,11 +208,7 @@ } 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; @@ -238,20 +225,17 @@ 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; @@ -274,12 +258,11 @@ 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; @@ -289,8 +272,7 @@ } int -netif_open(machdep_hint) - void *machdep_hint; +netif_open(void *machdep_hint) { int fd; struct iodesc *s; @@ -313,23 +295,22 @@ 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: lib/libstand/nfs.c =================================================================== --- lib/libstand/nfs.c +++ lib/libstand/nfs.c @@ -185,6 +185,7 @@ int nfs_getrootfh(struct iodesc *d, char *path, uint32_t *fhlenp, u_char *fhp) { + void *pkt = NULL; int len; struct args { uint32_t len; @@ -201,10 +202,6 @@ 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 @@ -213,7 +210,6 @@ #endif args = &sdata.d; - repl = &rdata.d; bzero(args, sizeof(*args)); len = strlen(path); @@ -224,18 +220,25 @@ 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); } @@ -246,6 +249,7 @@ 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; @@ -263,10 +267,6 @@ 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 @@ -275,7 +275,6 @@ #endif args = &sdata.d; - repl = &rdata.d; bzero(args, sizeof(*args)); args->fhsize = htonl(d->fhsize); @@ -289,23 +288,30 @@ 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); } @@ -316,6 +322,7 @@ int nfs_readlink(struct nfs_iodesc *d, char *buf) { + void *pkt = NULL; struct args { uint32_t fhsize; u_char fh[NFS_V3MAXFHSIZE]; @@ -331,11 +338,8 @@ 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) @@ -343,32 +347,41 @@ #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 @@ -380,6 +393,7 @@ 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]; @@ -397,16 +411,11 @@ 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); @@ -421,16 +430,19 @@ 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; @@ -438,9 +450,11 @@ 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); } @@ -481,17 +495,8 @@ 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); @@ -660,9 +665,8 @@ 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); } @@ -773,6 +777,7 @@ 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; @@ -787,14 +792,12 @@ 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)); @@ -810,11 +813,23 @@ 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) { + free(pkt); + pkt = NULL; + pfp = NULL; + cookie = 0; + return (errno); + } repl = (struct nfsv3_readdir_repl *)buf; - if (repl->errno != 0) - return (ntohl(repl->errno)); + if (repl->errno != 0) { + int rc = ntohl(repl->errno); + free(pkt); + pkt = NULL; + pfp = NULL; + cookie = 0; + return (rc); + } pfp = fp; cookie = fp->off; fp->cookie = ((uint64_t)ntohl(repl->cookiev0) << 32) | @@ -826,6 +841,9 @@ if (rent->follows == 0) { /* fid0 is actually eof */ if (rent->fid0 != 0) { + free(pkt); + pkt = NULL; + pfp = NULL; cookie = 0; return (ENOENT); } Index: lib/libstand/rarp.c =================================================================== --- lib/libstand/rarp.c +++ lib/libstand/rarp.c @@ -54,17 +54,17 @@ 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 { @@ -72,13 +72,6 @@ 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) @@ -102,21 +95,21 @@ 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)) @@ -134,10 +127,7 @@ * 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 @@ -153,28 +143,26 @@ * 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); } @@ -183,10 +171,10 @@ 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) || @@ -196,6 +184,7 @@ if (debug) printf("bad hrd/pro/hln/pln\n"); #endif + free(ptr); return (-1); } @@ -204,6 +193,7 @@ if (debug) printf("bad op=0x%x\n", ntohs(ap->arp_op)); #endif + free(ptr); return (-1); } @@ -213,6 +203,7 @@ if (debug) printf("unwanted address\n"); #endif + free(ptr); return (-1); } @@ -221,5 +212,7 @@ if (debug) printf("got it\n"); #endif + *pkt = ptr; + *payload = ap; return (n); } Index: lib/libstand/rpc.h =================================================================== --- lib/libstand/rpc.h +++ lib/libstand/rpc.h @@ -48,7 +48,7 @@ /* 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); Index: lib/libstand/rpc.c =================================================================== --- lib/libstand/rpc.c +++ lib/libstand/rpc.c @@ -97,7 +97,7 @@ }; /* 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; @@ -109,14 +109,14 @@ */ 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 */ @@ -145,7 +145,6 @@ 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)); @@ -153,13 +152,6 @@ 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); @@ -172,34 +164,28 @@ 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) { @@ -208,17 +194,21 @@ 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); } /* @@ -227,8 +217,9 @@ * 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; @@ -236,14 +227,15 @@ 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; - - reply = (struct rpc_reply *)pkt; + ptr = NULL; + n = readudp(d, &ptr, (void **)&reply, tleft); + if (n <= (4 * 4)) { + free(ptr); + return (-1); + } x = ntohl(reply->rp_xid); if (x != rpc_xid) { @@ -251,7 +243,8 @@ 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); @@ -260,16 +253,20 @@ 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); } @@ -387,11 +384,7 @@ 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; @@ -416,16 +409,18 @@ 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); Index: lib/libstand/tftp.c =================================================================== --- lib/libstand/tftp.c +++ lib/libstand/tftp.c @@ -73,8 +73,8 @@ 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", @@ -114,11 +114,8 @@ 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 @@ -181,20 +178,23 @@ } 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: { @@ -204,6 +204,7 @@ /* * Expected block? */ + free(ptr); return (-1); } if (d->xid == 1) { @@ -211,11 +212,13 @@ * 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) { @@ -227,6 +230,7 @@ #endif errno = tftperrors[ntohs(t->th_code)]; } + free(ptr); return (-1); case OACK: { struct udphdr *uh; @@ -237,6 +241,7 @@ * Drop the pkt. */ if (d->xid != 1) { + free(ptr); return (-1); } @@ -244,7 +249,7 @@ * 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. */ @@ -252,14 +257,18 @@ 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); } } @@ -276,6 +285,7 @@ char *wtail; int l; ssize_t res; + void *pkt; struct tftphdr *t; char *tftp_blksize = NULL; int blksize_l; @@ -314,8 +324,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); @@ -325,8 +333,17 @@ 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)); @@ -362,6 +379,7 @@ } __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); @@ -369,16 +387,20 @@ 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) @@ -405,14 +427,8 @@ 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); @@ -507,7 +523,7 @@ 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; @@ -540,6 +556,7 @@ if (tftpfile) { free(tftpfile->path); + free(tftpfile->pkt); free(tftpfile); } is_open = 0; @@ -591,8 +608,9 @@ 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; @@ -624,7 +642,7 @@ 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); Index: lib/libstand/udp.c =================================================================== --- lib/libstand/udp.c +++ lib/libstand/udp.c @@ -59,10 +59,7 @@ /* 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; @@ -131,32 +128,29 @@ /* * 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; - - n = readether(d, ip, len + sizeof(*ip) + sizeof(*uh), tleft, &etype); - if (n == -1 || n < sizeof(*ip) + sizeof(*uh)) - return -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); + } /* Ethernet address checks now in readether() */ @@ -167,7 +161,8 @@ /* Send ARP reply */ arp_reply(d, ah); } - return -1; + free(ptr); + return (-1); } if (etype != ETHERTYPE_IP) { @@ -175,7 +170,8 @@ if (debug) printf("readudp: not IP. ether_type=%x\n", etype); #endif - return -1; + free(ptr); + return (-1); } /* Check ip header */ @@ -185,7 +181,8 @@ 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; @@ -195,7 +192,8 @@ 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 @@ -203,7 +201,8 @@ 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 @@ -212,12 +211,14 @@ 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); } @@ -227,7 +228,8 @@ printf("readudp: bad dport %d != %d\n", d->myport, ntohs(uh->uh_dport)); #endif - return -1; + free(ptr); + return (-1); } #ifndef UDP_NO_CKSUM @@ -238,7 +240,8 @@ 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) */ @@ -251,8 +254,8 @@ if (debug) printf("readudp: bad cksum\n"); #endif - *ip = tip; - return -1; + free(ptr); + return (-1); } *ip = tip; } @@ -263,10 +266,13 @@ 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: sys/boot/common/dev_net.c =================================================================== --- sys/boot/common/dev_net.c +++ sys/boot/common/dev_net.c @@ -58,6 +58,7 @@ #include #include +#include #include #include #include @@ -79,7 +80,7 @@ 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); @@ -216,7 +217,8 @@ } static int -net_strategy() +net_strategy(void *devdata, int rw, daddr_t blk, size_t size, char *buf, + size_t *rsize) { return (EIO); @@ -246,6 +248,8 @@ { char buf[MAXHOSTNAMELEN]; n_long rootaddr, smask; + struct iodesc *d = socktodesc(sock); + extern struct in_addr servip; #ifdef SUPPORT_BOOTP /* @@ -254,8 +258,26 @@ * 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 Index: sys/boot/efi/libefi/efinet.c =================================================================== --- sys/boot/efi/libefi/efinet.c +++ sys/boot/efi/libefi/efinet.c @@ -36,19 +36,17 @@ #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", @@ -113,7 +111,7 @@ return (0); } -static int +static ssize_t efinet_put(struct iodesc *desc, void *pkt, size_t len) { struct netif *nif = desc->io_netif; @@ -125,14 +123,14 @@ 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. @@ -143,41 +141,42 @@ 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); + + bufsz = roundup2(net->Mode->MaxPacketSize, 64) + 256; + buf = malloc(bufsz + 2); + if (buf == NULL) + return (ret); + ptr = buf + 2; - t = time(0); - while ((time(0) - t) < timeout) { - bufsz = sizeof(buf); - status = net->Receive(net, 0, &bufsz, buf, 0, 0, 0); + t = getsecs(); + while ((getsecs() - t) < timeout) { + status = net->Receive(net, 0, &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 @@ -205,8 +204,8 @@ 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; } } @@ -214,8 +213,8 @@ 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; } } @@ -224,10 +223,10 @@ 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; } } @@ -258,9 +257,9 @@ .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 @@ -277,13 +276,14 @@ 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); @@ -313,10 +313,11 @@ * 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]; @@ -351,6 +352,11 @@ 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); Index: sys/boot/efi/libefi/time.c =================================================================== --- sys/boot/efi/libefi/time.c +++ sys/boot/efi/libefi/time.c @@ -230,5 +230,5 @@ time_t getsecs(void) { - return time(0); + return time(NULL); } Index: sys/boot/efi/loader/Makefile =================================================================== --- sys/boot/efi/loader/Makefile +++ sys/boot/efi/loader/Makefile @@ -9,6 +9,7 @@ PROG= loader.sym INTERNALPROG= WARNS?= 3 +LOADER_NET_SUPPORT?= yes # architecture-specific loader code SRCS= autoload.c \ @@ -35,6 +36,10 @@ 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 Index: sys/boot/i386/libi386/pxe.h =================================================================== --- sys/boot/i386/libi386/pxe.h +++ sys/boot/i386/libi386/pxe.h @@ -349,7 +349,7 @@ */ # 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; Index: sys/boot/i386/libi386/pxe.c =================================================================== --- sys/boot/i386/libi386/pxe.c +++ sys/boot/i386/libi386/pxe.c @@ -30,11 +30,14 @@ __FBSDID("$FreeBSD$"); #include +#include #include #include +#include #include #include +#include #include #include @@ -53,17 +56,15 @@ * 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); @@ -71,25 +72,17 @@ 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; @@ -97,25 +90,24 @@ 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[] = { @@ -124,15 +116,15 @@ }; 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 }; /* @@ -160,6 +152,7 @@ int counter; uint8_t checksum; uint8_t *checkptr; + extern struct devsw netdev; if (pxenv_p == NULL) return (0); @@ -215,7 +208,11 @@ 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)); @@ -236,192 +233,29 @@ pxe_p = NULL; return (0); } - bcopy(PTOV((gci_p->Buffer.segment << 4) + gci_p->Buffer.offset), - &bootplayer, gci_p->BufferSize); - 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_NFS; - if (tftpip.s_addr != 0) { - netproto = NET_TFTP; - rootip.s_addr = tftpip.s_addr; - } - - if (netproto == NET_NFS && !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) - 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; + 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 (0); + return (1); } 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 @@ -460,66 +294,6 @@ 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) { @@ -570,121 +344,196 @@ 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; - - bzero(udpopen_p, sizeof(*udpopen_p)); - udpopen_p->src_ip = bootplayer.yip; - pxe_call(PXENV_UDP_OPEN); + return (-1); - 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; + + 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; + } -static int -pxe_netif_get(struct iodesc *desc, void *pkt, size_t len, time_t timeout) -{ - return len; -} + /* 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; -static int -pxe_netif_put(struct iodesc *desc, void *pkt, size_t len) -{ - return len; + 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); } -ssize_t -sendudp(struct iodesc *h, void *pkt, size_t len) +static int +pxe_netif_receive(void **pkt) { - t_PXENV_UDP_WRITE *udpwrite_p = (t_PXENV_UDP_WRITE *)scratch_buffer; - bzero(udpwrite_p, sizeof(*udpwrite_p)); + t_PXENV_UNDI_ISR *isr = (t_PXENV_UNDI_ISR *)scratch_buffer; + char *buf, *ptr, *frame; + size_t size, rsize; + + bzero(isr, sizeof(*isr)); + isr->FuncFlag = PXENV_UNDI_ISR_IN_START; + pxe_call(PXENV_UNDI_ISR); + if (isr->Status != 0) + return (-1); + + bzero(isr, sizeof(*isr)); + isr->FuncFlag = PXENV_UNDI_ISR_IN_PROCESS; + pxe_call(PXENV_UNDI_ISR); + if (isr->Status != 0) + return (-1); + + 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); + } + + 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); + } + + size = isr->FrameLength; + buf = malloc(size + 2); + if (buf == NULL) + return (-1); + ptr = buf + 2; + 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); + } - 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); + /* Did we got another update? */ + if (isr->FuncFlag == PXENV_UNDI_ISR_OUT_RECEIVE) + continue; + break; + } - if (netmask == 0 || SAMENET(myip, h->destip, netmask)) - udpwrite_p->gw = 0; - else - udpwrite_p->gw = gateip.s_addr; + *pkt = buf; + return (rsize); +} - pxe_call(PXENV_UDP_WRITE); +static ssize_t +pxe_netif_get(struct iodesc *desc, void **pkt, time_t timeout) +{ + time_t t; + void *ptr; + int ret = -1; -#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; + t = getsecs(); + while ((getsecs() - t) < timeout) { + ret = pxe_netif_receive(&ptr); + if (ret != -1) { + *pkt = ptr; + break; + } } - return len; + return (ret); } -ssize_t -readudp(struct iodesc *h, void *pkt, size_t len, time_t timeout) +static ssize_t +pxe_netif_put(struct iodesc *desc, void *pkt, size_t len) { - t_PXENV_UDP_READ *udpread_p = (t_PXENV_UDP_READ *)scratch_buffer; - struct udphdr *uh = NULL; + t_PXENV_UNDI_TRANSMIT *trans_p; + t_PXENV_UNDI_TBD *tbd_p; + char *data; - uh = (struct udphdr *) pkt - 1; - bzero(udpread_p, sizeof(*udpread_p)); + 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)); - 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); + data = scratch_buffer + sizeof(*trans_p) + sizeof(*tbd_p); - pxe_call(PXENV_UDP_READ); + trans_p->TBD.segment = VTOPSEG(tbd_p); + trans_p->TBD.offset = VTOPOFF(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; - } - bcopy(data_buffer, pkt, udpread_p->buffer_size); - uh->uh_sport = udpread_p->s_port; - return udpread_p->buffer_size; + 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); + } + + return (len); } Index: sys/boot/i386/loader/Makefile =================================================================== --- sys/boot/i386/loader/Makefile +++ sys/boot/i386/loader/Makefile @@ -9,6 +9,7 @@ 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 @@ -25,6 +26,10 @@ 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 Index: sys/boot/ofw/libofw/ofw_net.c =================================================================== --- sys/boot/ofw/libofw/ofw_net.c +++ sys/boot/ofw/libofw/ofw_net.c @@ -46,8 +46,8 @@ 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[]; @@ -57,7 +57,7 @@ { 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 */ @@ -68,7 +68,7 @@ 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; @@ -87,7 +87,7 @@ return 0; } -static int +static ssize_t ofwn_put(struct iodesc *desc, void *pkt, size_t len) { size_t sendlen; @@ -124,20 +124,32 @@ 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 take + * an small shortcut here. + */ + len = 1500 + 64; + buf = malloc(len + 2); + if (buf == NULL) + return (-1); + ptr = buf + 2; + t = getsecs(); do { - length = OF_read(netinstance, pkt, len); + length = OF_read(netinstance, ptr, len); } while ((length == -2 || length == 0) && (getsecs() - t < timeout)); @@ -145,12 +157,14 @@ 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) { @@ -163,7 +177,7 @@ #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)); @@ -171,7 +185,8 @@ } #endif - return length; + *pkt = buf; + return (length); } extern char *strchr(); Index: sys/boot/uboot/lib/net.c =================================================================== --- sys/boot/uboot/lib/net.c +++ sys/boot/uboot/lib/net.c @@ -50,8 +50,8 @@ 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[]; @@ -61,7 +61,7 @@ { 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 */ @@ -72,7 +72,7 @@ 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 { @@ -232,7 +232,7 @@ return (0); } -static int +static ssize_t net_put(struct iodesc *desc, void *pkt, size_t len) { struct netif *nif = desc->io_netif; @@ -271,18 +271,21 @@ 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); @@ -299,13 +302,12 @@ #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 + 2); + if (buf == NULL) + return (-1); + memcpy(buf + 2, sc->sc_rxbuf, rlen); + *pkt = buf; + return ((ssize_t)rlen); } return (-1);