From da8fb057e520892de8cd09d883c0efa57c4deb66 Mon Sep 17 00:00:00 2001 From: Toomas Soome Date: Sat, 6 May 2017 20:32:27 +0000 Subject: [PATCH] loader: network read rework The current read from network is working from up to down - we have some protocol needing the data from the network, so we build the buffer space for that protocol, add the extra space for headers and pass this buffer down to be filled by nif get call in hope, we have guessed the incoming packet size right. Amazingly enough this approach mostly does work, but not always... So, this update does work from down to up - we allocate buffer (based on MTU or frame size info), fill it up, and pass on for upper layers. The obvious problem is that when we should free the buffer - if at all. In the current implementation the upper layer will free the packet on error or when the packet is no longer needed. While working on the issue, the additional issue did pop up - the bios implementation does not have generic get/put interface but is using pxe udpsend/udpreceive instead. So the udp calls are gone and undi interface is implemented instead. Which in turn means slight other changes as we do not need to have duplicated pxe implementation and can just use dev_net. To align packet content, the actual read from nic is using shifted buffer by ETHER_ALIGN (2). Reviewed by: bapt Differential Revision: https://reviews.freebsd.org/D10232 --- lib/libstand/arp.c | 54 ++-- lib/libstand/bootp.c | 83 ++--- lib/libstand/bootp.h | 4 + lib/libstand/bootparam.c | 101 +++---- lib/libstand/ether.c | 39 ++- lib/libstand/net.c | 10 +- lib/libstand/net.h | 11 +- lib/libstand/netif.c | 57 ++-- lib/libstand/netif.h | 8 +- lib/libstand/nfs.c | 147 +++++---- lib/libstand/rarp.c | 43 ++- lib/libstand/rpc.c | 81 +++-- lib/libstand/rpc.h | 2 +- lib/libstand/tftp.c | 84 ++++-- lib/libstand/udp.c | 64 ++-- sys/boot/common/dev_net.c | 30 +- sys/boot/efi/libefi/efinet.c | 89 +++--- sys/boot/efi/libefi/time.c | 2 +- sys/boot/efi/loader/Makefile | 5 + sys/boot/i386/libi386/pxe.c | 552 +++++++++++++--------------------- sys/boot/i386/libi386/pxe.h | 2 +- sys/boot/i386/loader/Makefile | 5 + sys/boot/ofw/libofw/ofw_net.c | 47 ++- sys/boot/uboot/lib/net.c | 32 +- 24 files changed, 725 insertions(+), 827 deletions(-) diff --git a/lib/libstand/arp.c b/lib/libstand/arp.c index dac8f90886d..841010c3195 100644 --- a/lib/libstand/arp.c +++ b/lib/libstand/arp.c @@ -65,17 +65,16 @@ 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 { @@ -83,13 +82,6 @@ arpwhohas(d, addr) 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 @@ arpwhohas(d, addr) /* 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)); } @@ -143,14 +139,12 @@ arpwhohas(d, addr) 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 @@ arpsend(d, pkt, len) * 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 @@ arprecv(d, pkt, len, tleft) 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 @@ arprecv(d, pkt, len, tleft) if (debug) printf("bad hrd/pro/hln/pln\n"); #endif + free(ptr); return (-1); } @@ -220,6 +213,7 @@ arprecv(d, pkt, len, tleft) printf("is request\n"); #endif arp_reply(d, ah); + free(ptr); return (-1); } @@ -228,6 +222,7 @@ arprecv(d, pkt, len, tleft) if (debug) printf("not ARP reply\n"); #endif + free(ptr); return (-1); } @@ -239,6 +234,7 @@ arprecv(d, pkt, len, tleft) 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 @@ arprecv(d, pkt, len, tleft) if (debug) printf("got it\n"); #endif + *pkt = ptr; + *payload = ah; return (n); } @@ -256,9 +254,7 @@ arprecv(d, pkt, len, tleft) * 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; diff --git a/lib/libstand/bootp.c b/lib/libstand/bootp.c index 9fc656f4a99..ec3cd7b5dc2 100644 --- a/lib/libstand/bootp.c +++ b/lib/libstand/bootp.c @@ -38,6 +38,7 @@ #include __FBSDID("$FreeBSD$"); +#include #include #include #include @@ -72,7 +73,7 @@ static char vm_cmu[4] = VM_CMU; /* 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 void setenv_(u_char *cp, u_char *ep, struct dhcp_opt *opts); 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) @@ -175,8 +174,7 @@ bootp(sock, flag) 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; } @@ -187,7 +185,7 @@ bootp(sock, flag) 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); @@ -205,20 +203,21 @@ bootp(sock, flag) 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) { @@ -258,14 +257,12 @@ bootp(sock, flag) /* 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; @@ -286,30 +283,25 @@ bootpsend(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 @@ -328,8 +320,21 @@ time_t tleft; /* 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) @@ -338,8 +343,11 @@ time_t tleft; 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); } @@ -356,9 +364,7 @@ dhcp_try_rfc1048(u_char *cp, u_int len) } 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; @@ -445,8 +451,7 @@ vend_rfc1048(cp, len) #ifdef BOOTP_VEND_CMU static void -vend_cmu(cp) - u_char *cp; +vend_cmu(u_char *cp) { struct cmu_vend *vp; diff --git a/lib/libstand/bootp.h b/lib/libstand/bootp.h index 98358007e07..9fb746f4916 100644 --- a/lib/libstand/bootp.h +++ b/lib/libstand/bootp.h @@ -147,6 +147,10 @@ struct cmu_vend { /* 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_ */ diff --git a/lib/libstand/bootparam.c b/lib/libstand/bootparam.c index e4d2f1022c9..1de2d53d77f 100644 --- a/lib/libstand/bootparam.c +++ b/lib/libstand/bootparam.c @@ -104,8 +104,7 @@ int xdr_string_decode(char **p, char *str, int *len_p); * 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,22 +125,19 @@ bp_whoami(sockfd) 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. @@ -156,19 +152,19 @@ bp_whoami(sockfd) * 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). */ @@ -196,7 +192,7 @@ bp_whoami(sockfd) 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 +200,27 @@ bp_whoami(sockfd) 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 +232,18 @@ bp_whoami(sockfd) * 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 +251,6 @@ bp_getfile(sockfd, key, serv_addr, pathname) } send_tail = (char*) sdata.d; - recv_head = (char*) rdata.d; /* * Build request message. @@ -281,17 +272,16 @@ bp_getfile(sockfd, key, serv_addr, pathname) 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 +289,29 @@ bp_getfile(sockfd, key, serv_addr, pathname) /* 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 +322,14 @@ bp_getfile(sockfd, key, serv_addr, pathname) 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); @@ -351,18 +341,15 @@ xdr_string_encode(pkt, str, len) } 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; @@ -381,9 +368,7 @@ xdr_string_decode(pkt, str, len_p) 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 +399,7 @@ xdr_inaddr_encode(pkt, ia) } 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; diff --git a/lib/libstand/ether.c b/lib/libstand/ether.c index df42f31a8b7..3616777e795 100644 --- a/lib/libstand/ether.c +++ b/lib/libstand/ether.c @@ -54,12 +54,7 @@ __FBSDID("$FreeBSD$"); /* 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 @@ sendether(d, pkt, len, dea, etype) /* * 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) { @@ -120,8 +114,12 @@ readether(d, pkt, len, tleft, etype) 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 @@ readether(d, pkt, len, tleft, etype) */ static char digits[] = "0123456789abcdef"; char * -ether_sprintf(ap) - u_char *ap; +ether_sprintf(u_char *ap) { int i; static char etherbuf[18]; diff --git a/lib/libstand/net.c b/lib/libstand/net.c index 38759a80227..ae6e74511e1 100644 --- a/lib/libstand/net.c +++ b/lib/libstand/net.c @@ -70,10 +70,10 @@ __FBSDID("$FreeBSD$"); */ 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 @@ sendrecv(struct iodesc *d, } /* 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); diff --git a/lib/libstand/net.h b/lib/libstand/net.h index 5221885a266..740b5d970f8 100644 --- a/lib/libstand/net.h +++ b/lib/libstand/net.h @@ -106,16 +106,15 @@ 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); diff --git a/lib/libstand/netif.c b/lib/libstand/netif.c index c260690c503..105f9a31ab5 100644 --- a/lib/libstand/netif.c +++ b/lib/libstand/netif.c @@ -59,7 +59,7 @@ int netif_debug = 0; */ void -netif_init() +netif_init(void) { struct netif_driver *drv; int d, i; @@ -76,13 +76,11 @@ netif_init() } 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 @@ 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; @@ -162,9 +159,7 @@ netif_select(machdep_hint) } 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 @@ 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; @@ -199,8 +191,7 @@ netif_attach(nif, desc, machdep_hint) } void -netif_detach(nif) - struct netif *nif; +netif_detach(struct netif *nif) { struct netif_driver *drv = nif->nif_driver; @@ -217,11 +208,7 @@ netif_detach(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; @@ -238,20 +225,17 @@ netif_get(desc, pkt, len, timo) 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 @@ netif_put(desc, pkt, len) 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 @@ socktodesc(sock) } int -netif_open(machdep_hint) - void *machdep_hint; +netif_open(void *machdep_hint) { int fd; struct iodesc *s; @@ -313,23 +295,22 @@ fnd: 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); } diff --git a/lib/libstand/netif.h b/lib/libstand/netif.h index dac285107a7..44165ab0d88 100644 --- a/lib/libstand/netif.h +++ b/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 @@ 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 *); diff --git a/lib/libstand/nfs.c b/lib/libstand/nfs.c index 8a7e111fcdd..6c387b8d8ef 100644 --- a/lib/libstand/nfs.c +++ b/lib/libstand/nfs.c @@ -185,6 +185,7 @@ set_nfs_read_size(void) 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 @@ nfs_getrootfh(struct iodesc *d, char *path, uint32_t *fhlenp, u_char *fhp) 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 @@ nfs_getrootfh(struct iodesc *d, char *path, uint32_t *fhlenp, u_char *fhp) #endif args = &sdata.d; - repl = &rdata.d; bzero(args, sizeof(*args)); len = strlen(path); @@ -224,18 +220,25 @@ nfs_getrootfh(struct iodesc *d, char *path, uint32_t *fhlenp, u_char *fhp) 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 @@ nfs_getrootfh(struct iodesc *d, char *path, uint32_t *fhlenp, u_char *fhp) 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 @@ nfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd) 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 @@ nfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd) #endif args = &sdata.d; - repl = &rdata.d; bzero(args, sizeof(*args)); args->fhsize = htonl(d->fhsize); @@ -289,23 +288,30 @@ nfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd) 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 @@ nfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd) 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 @@ nfs_readlink(struct nfs_iodesc *d, char *buf) 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 @@ nfs_readlink(struct nfs_iodesc *d, char *buf) #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 @@ nfs_readlink(struct nfs_iodesc *d, char *buf) 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 @@ nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len) 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 @@ nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len) 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 @@ nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len) 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 @@ nfs_open(const char *upath, struct open_file *f) 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 @@ nfs_close(struct open_file *f) 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,11 +777,12 @@ 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; @@ -787,14 +792,12 @@ nfs_readdir(struct open_file *f, struct dirent *d) 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,16 @@ nfs_readdir(struct open_file *f, struct dirent *d) 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) | @@ -826,8 +834,8 @@ nfs_readdir(struct open_file *f, struct dirent *d) if (rent->follows == 0) { /* fid0 is actually eof */ if (rent->fid0 != 0) { - cookie = 0; - return (ENOENT); + rc = ENOENT; + goto err; } goto refill; } @@ -842,4 +850,11 @@ nfs_readdir(struct open_file *f, struct dirent *d) pos += 2; buf = (u_char *)&rent->nameplus[pos]; return (0); + +err: + free(pkt); + pkt = NULL; + pfp = NULL; + cookie = 0; + return (rc); } diff --git a/lib/libstand/rarp.c b/lib/libstand/rarp.c index 9ec050da1fb..8d996d04a3f 100644 --- a/lib/libstand/rarp.c +++ b/lib/libstand/rarp.c @@ -54,17 +54,17 @@ __FBSDID("$FreeBSD$"); 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 @@ rarp_getipaddress(sock) 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 @@ rarp_getipaddress(sock) 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 @@ rarp_getipaddress(sock) * 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 @@ rarpsend(d, pkt, len) * 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 @@ rarprecv(d, pkt, len, tleft) 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 @@ rarprecv(d, pkt, len, tleft) if (debug) printf("bad hrd/pro/hln/pln\n"); #endif + free(ptr); return (-1); } @@ -204,6 +193,7 @@ rarprecv(d, pkt, len, tleft) if (debug) printf("bad op=0x%x\n", ntohs(ap->arp_op)); #endif + free(ptr); return (-1); } @@ -213,6 +203,7 @@ rarprecv(d, pkt, len, tleft) if (debug) printf("unwanted address\n"); #endif + free(ptr); return (-1); } @@ -221,5 +212,7 @@ rarprecv(d, pkt, len, tleft) if (debug) printf("got it\n"); #endif + *pkt = ptr; + *payload = ap; return (n); } diff --git a/lib/libstand/rpc.c b/lib/libstand/rpc.c index 79ee45af0ed..932fdc98b90 100644 --- a/lib/libstand/rpc.c +++ b/lib/libstand/rpc.c @@ -97,7 +97,7 @@ struct rpc_reply { }; /* 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 @@ int rpc_port = 0x400; /* predecrement */ */ 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 @@ rpc_call(struct iodesc *d, n_long prog, n_long vers, n_long proc, 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 @@ rpc_call(struct iodesc *d, n_long prog, n_long vers, n_long proc, 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 @@ rpc_call(struct iodesc *d, n_long prog, n_long vers, n_long proc, 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 @@ rpc_call(struct iodesc *d, n_long prog, n_long vers, n_long proc, 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 @@ rpc_call(struct iodesc *d, n_long prog, n_long vers, n_long proc, * 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 @@ recvrpc(struct iodesc *d, void *pkt, size_t len, time_t tleft) 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 @@ recvrpc(struct iodesc *d, void *pkt, size_t len, time_t tleft) 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 @@ recvrpc(struct iodesc *d, void *pkt, size_t len, time_t tleft) 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 @@ rpc_getport(struct iodesc *d, n_long prog, n_long vers) 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 @@ rpc_getport(struct iodesc *d, n_long prog, n_long vers) 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); diff --git a/lib/libstand/rpc.h b/lib/libstand/rpc.h index a892a6939dd..5efe8321014 100644 --- a/lib/libstand/rpc.h +++ b/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); diff --git a/lib/libstand/tftp.c b/lib/libstand/tftp.c index b3d2da7b0ed..922142c2a80 100644 --- a/lib/libstand/tftp.c +++ b/lib/libstand/tftp.c @@ -73,8 +73,8 @@ 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", @@ -114,11 +114,8 @@ struct tftp_handle { 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 @@ tftp_sendack(struct tftp_handle *h) } 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 @@ recvtftp(struct tftp_handle *h, void *pkt, ssize_t len, time_t tleft, /* * Expected block? */ + free(ptr); return (-1); } if (d->xid == 1) { @@ -211,11 +212,13 @@ recvtftp(struct tftp_handle *h, void *pkt, ssize_t len, time_t tleft, * 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 @@ recvtftp(struct tftp_handle *h, void *pkt, ssize_t len, time_t tleft, #endif errno = tftperrors[ntohs(t->th_code)]; } + free(ptr); return (-1); case OACK: { struct udphdr *uh; @@ -237,6 +241,7 @@ recvtftp(struct tftp_handle *h, void *pkt, ssize_t len, time_t tleft, * Drop the pkt. */ if (d->xid != 1) { + free(ptr); return (-1); } @@ -244,7 +249,7 @@ recvtftp(struct tftp_handle *h, void *pkt, ssize_t len, time_t tleft, * 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 @@ recvtftp(struct tftp_handle *h, void *pkt, ssize_t len, time_t tleft, 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 @@ tftp_makereq(struct tftp_handle *h) char *wtail; int l; ssize_t res; + void *pkt; struct tftphdr *t; char *tftp_blksize = NULL; int blksize_l; @@ -314,8 +324,6 @@ tftp_makereq(struct tftp_handle *h) 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 @@ tftp_makereq(struct tftp_handle *h) 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 @@ tftp_getnextblock(struct tftp_handle *h) } __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 @@ tftp_getnextblock(struct tftp_handle *h) 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 @@ tftp_open(const char *path, struct open_file *f) 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 @@ tftp_read(struct open_file *f, void *addr, size_t size, 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 @@ tftp_close(struct open_file *f) if (tftpfile) { free(tftpfile->path); + free(tftpfile->pkt); free(tftpfile); } is_open = 0; @@ -591,8 +608,9 @@ 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; @@ -624,7 +642,7 @@ sendrecv_tftp(struct tftp_handle *h, 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); diff --git a/lib/libstand/udp.c b/lib/libstand/udp.c index db5de892e85..2eba7a18eef 100644 --- a/lib/libstand/udp.c +++ b/lib/libstand/udp.c @@ -59,10 +59,7 @@ __FBSDID("$FreeBSD$"); /* 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 @@ sendudp(d, pkt, len) /* * 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 @@ readudp(d, pkt, len, tleft) /* Send ARP reply */ arp_reply(d, ah); } - return -1; + free(ptr); + return (-1); } if (etype != ETHERTYPE_IP) { @@ -175,7 +170,8 @@ readudp(d, pkt, len, tleft) 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 @@ readudp(d, pkt, len, tleft) 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 @@ readudp(d, pkt, len, tleft) 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 @@ readudp(d, pkt, len, tleft) 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 @@ readudp(d, pkt, len, tleft) 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 @@ readudp(d, pkt, len, tleft) 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 @@ readudp(d, pkt, len, tleft) 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 @@ readudp(d, pkt, len, tleft) if (debug) printf("readudp: bad cksum\n"); #endif - *ip = tip; - return -1; + free(ptr); + return (-1); } *ip = tip; } @@ -263,10 +266,13 @@ readudp(d, pkt, len, tleft) 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); } diff --git a/sys/boot/common/dev_net.c b/sys/boot/common/dev_net.c index c9162975d3b..b7127163c77 100644 --- a/sys/boot/common/dev_net.c +++ b/sys/boot/common/dev_net.c @@ -58,6 +58,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include #include @@ -79,7 +80,7 @@ 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); @@ -216,7 +217,8 @@ net_cleanup(void) } 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 @@ net_getparams(int sock) { char buf[MAXHOSTNAMELEN]; n_long rootaddr, smask; + struct iodesc *d = socktodesc(sock); + extern struct in_addr servip; #ifdef SUPPORT_BOOTP /* @@ -254,8 +258,26 @@ net_getparams(int sock) * 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 diff --git a/sys/boot/efi/libefi/efinet.c b/sys/boot/efi/libefi/efinet.c index c598548ed9f..b5c8ae74ead 100644 --- a/sys/boot/efi/libefi/efinet.c +++ b/sys/boot/efi/libefi/efinet.c @@ -29,6 +29,7 @@ __FBSDID("$FreeBSD$"); #include +#include #include #include @@ -36,19 +37,17 @@ __FBSDID("$FreeBSD$"); #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 +112,7 @@ 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; @@ -125,14 +124,14 @@ efinet_put(struct iodesc *desc, void *pkt, size_t len) 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 +142,42 @@ efinet_put(struct iodesc *desc, void *pkt, size_t len) 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 @@ -205,8 +205,8 @@ efinet_init(struct iodesc *desc, void *machdep_hint) 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 +214,8 @@ efinet_init(struct iodesc *desc, void *machdep_hint) 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 +224,10 @@ efinet_init(struct iodesc *desc, void *machdep_hint) 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 +258,9 @@ 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 @@ -277,13 +277,14 @@ efinet_dev_init() 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 +314,11 @@ efinet_dev_init() * 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 +353,11 @@ efinet_dev_init() 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); diff --git a/sys/boot/efi/libefi/time.c b/sys/boot/efi/libefi/time.c index 99831e1cf1a..1f9ee6f58c0 100644 --- a/sys/boot/efi/libefi/time.c +++ b/sys/boot/efi/libefi/time.c @@ -230,5 +230,5 @@ time(time_t *tloc) time_t getsecs(void) { - return time(0); + return time(NULL); } diff --git a/sys/boot/efi/loader/Makefile b/sys/boot/efi/loader/Makefile index 23845aab2ca..0f54aa4f767 100644 --- a/sys/boot/efi/loader/Makefile +++ b/sys/boot/efi/loader/Makefile @@ -9,6 +9,7 @@ MK_SSP= no 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-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 diff --git a/sys/boot/i386/libi386/pxe.c b/sys/boot/i386/libi386/pxe.c index 56ce5f52c0d..7cb48331792 100644 --- a/sys/boot/i386/libi386/pxe.c +++ b/sys/boot/i386/libi386/pxe.c @@ -30,11 +30,15 @@ __FBSDID("$FreeBSD$"); #include +#include #include #include +#include +#include #include #include +#include #include #include @@ -53,17 +57,15 @@ __FBSDID("$FreeBSD$"); * 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 +73,17 @@ 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; @@ -97,25 +91,24 @@ 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[] = { @@ -124,15 +117,15 @@ struct netif_driver *netif_drivers[] = { }; 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 +153,7 @@ pxe_init(void) int counter; uint8_t checksum; uint8_t *checkptr; + extern struct devsw netdev; if (pxenv_p == NULL) return (0); @@ -215,7 +209,11 @@ pxe_init(void) 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,190 +234,29 @@ pxe_init(void) 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 @@ -458,66 +295,6 @@ 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) { @@ -568,121 +345,196 @@ bangpxe_call(int func) 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; + + 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_get(struct iodesc *desc, void *pkt, size_t len, time_t timeout) +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; + + 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 + 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; + } + + *pkt = buf; + return (rsize); } -static int +static ssize_t +pxe_netif_get(struct iodesc *desc, void **pkt, time_t timeout) +{ + time_t t; + void *ptr; + int ret = -1; + + t = getsecs(); + while ((getsecs() - t) < timeout) { + ret = pxe_netif_receive(&ptr); + if (ret != -1) { + *pkt = ptr; + break; + } + } + return (ret); +} + +static ssize_t pxe_netif_put(struct iodesc *desc, void *pkt, size_t len) { - return len; -} + t_PXENV_UNDI_TRANSMIT *trans_p; + t_PXENV_UNDI_TBD *tbd_p; + char *data; -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)); + 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)); - 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); + data = scratch_buffer + sizeof(*trans_p) + sizeof(*tbd_p); - if (netmask == 0 || SAMENET(myip, h->destip, netmask)) - udpwrite_p->gw = 0; - else - udpwrite_p->gw = gateip.s_addr; + trans_p->TBD.segment = VTOPSEG(tbd_p); + trans_p->TBD.offset = VTOPOFF(tbd_p); - pxe_call(PXENV_UDP_WRITE); + tbd_p->ImmedLength = len; + tbd_p->Xmit.segment = VTOPSEG(data); + tbd_p->Xmit.offset = VTOPOFF(data); + bcopy(pkt, data, len); -#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; + pxe_call(PXENV_UNDI_TRANSMIT); + if (trans_p->Status != 0) { + return (-1); } - return len; -} - -ssize_t -readudp(struct iodesc *h, void *pkt, size_t len, time_t timeout) -{ - t_PXENV_UDP_READ *udpread_p = (t_PXENV_UDP_READ *)scratch_buffer; - struct udphdr *uh = NULL; - - uh = (struct udphdr *) pkt - 1; - bzero(udpread_p, sizeof(*udpread_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); - - pxe_call(PXENV_UDP_READ); - -#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; + + return (len); } diff --git a/sys/boot/i386/libi386/pxe.h b/sys/boot/i386/libi386/pxe.h index 62b6aa79cca..119c86be519 100644 --- a/sys/boot/i386/libi386/pxe.h +++ b/sys/boot/i386/libi386/pxe.h @@ -349,7 +349,7 @@ typedef struct { */ # 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; diff --git a/sys/boot/i386/loader/Makefile b/sys/boot/i386/loader/Makefile index 31bf9834ddb..6bdffc147bc 100644 --- a/sys/boot/i386/loader/Makefile +++ b/sys/boot/i386/loader/Makefile @@ -9,6 +9,7 @@ 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 @@ -25,6 +26,10 @@ 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 diff --git a/sys/boot/ofw/libofw/ofw_net.c b/sys/boot/ofw/libofw/ofw_net.c index 691dedab052..ea5e47e7ed0 100644 --- a/sys/boot/ofw/libofw/ofw_net.c +++ b/sys/boot/ofw/libofw/ofw_net.c @@ -46,8 +46,8 @@ __FBSDID("$FreeBSD$"); 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 @@ struct netif_dif ofwn_ifs[] = { { 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 @@ struct netif_driver ofwnet = { 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 @@ 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; @@ -124,20 +124,32 @@ ofwn_put(struct iodesc *desc, void *pkt, size_t len) 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)); @@ -145,12 +157,14 @@ ofwn_get(struct iodesc *desc, void *pkt, size_t len, time_t timeout) 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 @@ ofwn_get(struct iodesc *desc, void *pkt, size_t len, time_t timeout) #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 @@ ofwn_get(struct iodesc *desc, void *pkt, size_t len, time_t timeout) } #endif - return length; + *pkt = buf; + return (length); } extern char *strchr(); diff --git a/sys/boot/uboot/lib/net.c b/sys/boot/uboot/lib/net.c index 9bc0c075437..a0d1cb4f458 100644 --- a/sys/boot/uboot/lib/net.c +++ b/sys/boot/uboot/lib/net.c @@ -50,8 +50,8 @@ __FBSDID("$FreeBSD$"); 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 @@ struct netif_dif net_ifs[] = { { 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 @@ struct netif_driver uboot_net = { 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 @@ net_probe(struct netif *nif, void *machdep_hint) 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 @@ net_put(struct iodesc *desc, void *pkt, size_t len) 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 @@ net_get(struct iodesc *desc, void *pkt, size_t len, time_t timeout) #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);