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
This commit is contained in:
Toomas Soome 2017-05-06 20:32:27 +00:00
parent a872bf12f8
commit da8fb057e5
24 changed files with 725 additions and 827 deletions

View File

@ -65,17 +65,16 @@ int arp_num = 1;
/* Local forwards */ /* Local forwards */
static ssize_t arpsend(struct iodesc *, void *, size_t); 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 */ /* Broadcast an ARP packet, asking who has addr on interface d */
u_char * u_char *
arpwhohas(d, addr) arpwhohas(struct iodesc *d, struct in_addr addr)
struct iodesc *d;
struct in_addr addr;
{ {
int i; int i;
struct ether_arp *ah; struct ether_arp *ah;
struct arp_list *al; struct arp_list *al;
void *pkt;
struct { struct {
struct ether_header eh; struct ether_header eh;
struct { struct {
@ -83,13 +82,6 @@ arpwhohas(d, addr)
u_char pad[18]; /* 60 - sizeof(...) */ u_char pad[18]; /* 60 - sizeof(...) */
} data; } data;
} wbuf; } wbuf;
struct {
struct ether_header eh;
struct {
struct ether_arp arp;
u_char pad[24]; /* extra space */
} data;
} rbuf;
/* Try for cached answer first */ /* Try for cached answer first */
for (i = 0, al = arp_list; i < arp_num; ++i, ++al) 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). */ /* Store ip address in cache (incomplete entry). */
al->addr = addr; al->addr = addr;
pkt = NULL;
ah = NULL;
i = sendrecv(d, i = sendrecv(d,
arpsend, &wbuf.data, sizeof(wbuf.data), arpsend, &wbuf.data, sizeof(wbuf.data),
arprecv, &rbuf.data, sizeof(rbuf.data)); arprecv, &pkt, (void **)&ah);
if (i == -1) { if (i == -1) {
panic("arp: no response for %s\n", panic("arp: no response for %s\n",
inet_ntoa(addr)); inet_ntoa(addr));
} }
/* Store ethernet address in cache */ /* Store ethernet address in cache */
ah = &rbuf.data.arp;
#ifdef ARP_DEBUG #ifdef ARP_DEBUG
if (debug) { if (debug) {
struct ether_header *eh;
eh = (struct ether_header *)((uintptr_t)pkt + ETHER_ALIGN);
printf("arp: response from %s\n", printf("arp: response from %s\n",
ether_sprintf(rbuf.eh.ether_shost)); ether_sprintf(eh->ether_shost));
printf("arp: cacheing %s --> %s\n", printf("arp: cacheing %s --> %s\n",
inet_ntoa(addr), ether_sprintf(ah->arp_sha)); inet_ntoa(addr), ether_sprintf(ah->arp_sha));
} }
@ -143,14 +139,12 @@ arpwhohas(d, addr)
MACPY(ah->arp_sha, al->ea); MACPY(ah->arp_sha, al->ea);
++arp_num; ++arp_num;
free(pkt);
return (al->ea); return (al->ea);
} }
static ssize_t static ssize_t
arpsend(d, pkt, len) arpsend(struct iodesc *d, void *pkt, size_t len)
struct iodesc *d;
void *pkt;
size_t len;
{ {
#ifdef ARP_DEBUG #ifdef ARP_DEBUG
@ -166,28 +160,27 @@ arpsend(d, pkt, len)
* else -1 (and errno == 0) * else -1 (and errno == 0)
*/ */
static ssize_t static ssize_t
arprecv(d, pkt, len, tleft) arprecv(struct iodesc *d, void **pkt, void **payload, time_t tleft)
struct iodesc *d;
void *pkt;
size_t len;
time_t tleft;
{ {
ssize_t n; ssize_t n;
struct ether_arp *ah; struct ether_arp *ah;
u_int16_t etype; /* host order */ u_int16_t etype; /* host order */
void *ptr;
#ifdef ARP_DEBUG #ifdef ARP_DEBUG
if (debug) if (debug)
printf("arprecv: "); printf("arprecv: ");
#endif #endif
n = readether(d, pkt, len, tleft, &etype); ptr = NULL;
n = readether(d, &ptr, (void **)&ah, tleft, &etype);
errno = 0; /* XXX */ errno = 0; /* XXX */
if (n == -1 || n < sizeof(struct ether_arp)) { if (n == -1 || n < sizeof(struct ether_arp)) {
#ifdef ARP_DEBUG #ifdef ARP_DEBUG
if (debug) if (debug)
printf("bad len=%d\n", n); printf("bad len=%d\n", n);
#endif #endif
free(ptr);
return (-1); return (-1);
} }
@ -196,12 +189,11 @@ arprecv(d, pkt, len, tleft)
if (debug) if (debug)
printf("not arp type=%d\n", etype); printf("not arp type=%d\n", etype);
#endif #endif
free(ptr);
return (-1); return (-1);
} }
/* Ethernet address now checked in readether() */ /* Ethernet address now checked in readether() */
ah = (struct ether_arp *)pkt;
if (ah->arp_hrd != htons(ARPHRD_ETHER) || if (ah->arp_hrd != htons(ARPHRD_ETHER) ||
ah->arp_pro != htons(ETHERTYPE_IP) || ah->arp_pro != htons(ETHERTYPE_IP) ||
ah->arp_hln != sizeof(ah->arp_sha) || ah->arp_hln != sizeof(ah->arp_sha) ||
@ -211,6 +203,7 @@ arprecv(d, pkt, len, tleft)
if (debug) if (debug)
printf("bad hrd/pro/hln/pln\n"); printf("bad hrd/pro/hln/pln\n");
#endif #endif
free(ptr);
return (-1); return (-1);
} }
@ -220,6 +213,7 @@ arprecv(d, pkt, len, tleft)
printf("is request\n"); printf("is request\n");
#endif #endif
arp_reply(d, ah); arp_reply(d, ah);
free(ptr);
return (-1); return (-1);
} }
@ -228,6 +222,7 @@ arprecv(d, pkt, len, tleft)
if (debug) if (debug)
printf("not ARP reply\n"); printf("not ARP reply\n");
#endif #endif
free(ptr);
return (-1); return (-1);
} }
@ -239,6 +234,7 @@ arprecv(d, pkt, len, tleft)
if (debug) if (debug)
printf("unwanted address\n"); printf("unwanted address\n");
#endif #endif
free(ptr);
return (-1); return (-1);
} }
/* We don't care who the reply was sent to. */ /* We don't care who the reply was sent to. */
@ -248,6 +244,8 @@ arprecv(d, pkt, len, tleft)
if (debug) if (debug)
printf("got it\n"); printf("got it\n");
#endif #endif
*pkt = ptr;
*payload = ah;
return (n); return (n);
} }
@ -256,9 +254,7 @@ arprecv(d, pkt, len, tleft)
* Notes: Re-uses buffer. Pad to length = 46. * Notes: Re-uses buffer. Pad to length = 46.
*/ */
void void
arp_reply(d, pkt) arp_reply(struct iodesc *d, void *pkt)
struct iodesc *d;
void *pkt; /* the request */
{ {
struct ether_arp *arp = pkt; struct ether_arp *arp = pkt;

View File

@ -38,6 +38,7 @@
#include <sys/cdefs.h> #include <sys/cdefs.h>
__FBSDID("$FreeBSD$"); __FBSDID("$FreeBSD$");
#include <stddef.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/limits.h> #include <sys/limits.h>
#include <sys/endian.h> #include <sys/endian.h>
@ -72,7 +73,7 @@ static char vm_cmu[4] = VM_CMU;
/* Local forwards */ /* Local forwards */
static ssize_t bootpsend(struct iodesc *, void *, size_t); 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); static int vend_rfc1048(u_char *, u_int);
#ifdef BOOTP_VEND_CMU #ifdef BOOTP_VEND_CMU
static void vend_cmu(u_char *); 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; static char expected_dhcpmsgtype = -1, dhcp_ok;
struct in_addr dhcp_serverip; struct in_addr dhcp_serverip;
#endif #endif
struct bootp *bootp_response;
size_t bootp_response_size;
/* Fetch required bootp infomation */ /* Fetch required bootp infomation */
void void
bootp(sock, flag) bootp(int sock, int flag)
int sock;
int flag;
{ {
void *pkt;
struct iodesc *d; struct iodesc *d;
struct bootp *bp; struct bootp *bp;
struct { struct {
u_char header[HEADER_SIZE]; u_char header[HEADER_SIZE];
struct bootp wbootp; struct bootp wbootp;
} wbuf; } wbuf;
struct { struct bootp *rbootp;
u_char header[HEADER_SIZE];
struct bootp rbootp;
} rbuf;
#ifdef BOOTP_DEBUG #ifdef BOOTP_DEBUG
if (debug) if (debug)
@ -175,8 +174,7 @@ bootp(sock, flag)
if(sendrecv(d, if(sendrecv(d,
bootpsend, bp, sizeof(*bp), bootpsend, bp, sizeof(*bp),
bootprecv, &rbuf.rbootp, sizeof(rbuf.rbootp)) bootprecv, &pkt, (void **)&rbootp) == -1) {
== -1) {
printf("bootp: no reply\n"); printf("bootp: no reply\n");
return; return;
} }
@ -187,7 +185,7 @@ bootp(sock, flag)
bp->bp_vend[6] = DHCPREQUEST; bp->bp_vend[6] = DHCPREQUEST;
bp->bp_vend[7] = TAG_REQ_ADDR; bp->bp_vend[7] = TAG_REQ_ADDR;
bp->bp_vend[8] = 4; 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[13] = TAG_SERVERID;
bp->bp_vend[14] = 4; bp->bp_vend[14] = 4;
bcopy(&dhcp_serverip.s_addr, &bp->bp_vend[15], 4); bcopy(&dhcp_serverip.s_addr, &bp->bp_vend[15], 4);
@ -205,20 +203,21 @@ bootp(sock, flag)
expected_dhcpmsgtype = DHCPACK; expected_dhcpmsgtype = DHCPACK;
free(pkt);
if(sendrecv(d, if(sendrecv(d,
bootpsend, bp, sizeof(*bp), bootpsend, bp, sizeof(*bp),
bootprecv, &rbuf.rbootp, sizeof(rbuf.rbootp)) bootprecv, &pkt, (void **)&rbootp) == -1) {
== -1) {
printf("DHCPREQUEST failed\n"); printf("DHCPREQUEST failed\n");
return; return;
} }
} }
#endif #endif
myip = d->myip = rbuf.rbootp.bp_yiaddr; myip = d->myip = rbootp->bp_yiaddr;
servip = rbuf.rbootp.bp_siaddr; servip = rbootp->bp_siaddr;
if(rootip.s_addr == INADDR_ANY) rootip = servip; if (rootip.s_addr == INADDR_ANY)
bcopy(rbuf.rbootp.bp_file, bootfile, sizeof(bootfile)); rootip = servip;
bcopy(rbootp->bp_file, bootfile, sizeof(bootfile));
bootfile[sizeof(bootfile) - 1] = '\0'; bootfile[sizeof(bootfile) - 1] = '\0';
if (!netmask) { if (!netmask) {
@ -258,14 +257,12 @@ bootp(sock, flag)
/* Bump xid so next request will be unique. */ /* Bump xid so next request will be unique. */
++d->xid; ++d->xid;
free(pkt);
} }
/* Transmit a bootp request */ /* Transmit a bootp request */
static ssize_t static ssize_t
bootpsend(d, pkt, len) bootpsend(struct iodesc *d, void *pkt, size_t len)
struct iodesc *d;
void *pkt;
size_t len;
{ {
struct bootp *bp; struct bootp *bp;
@ -286,30 +283,25 @@ bootpsend(d, pkt, len)
} }
static ssize_t static ssize_t
bootprecv(d, pkt, len, tleft) bootprecv(struct iodesc *d, void **pkt, void **payload, time_t tleft)
struct iodesc *d;
void *pkt;
size_t len;
time_t tleft;
{ {
ssize_t n; ssize_t n;
struct bootp *bp; struct bootp *bp;
void *ptr;
#ifdef BOOTP_DEBUGx #ifdef BOOTP_DEBUG
if (debug) if (debug)
printf("bootp_recvoffer: called\n"); printf("bootp_recvoffer: called\n");
#endif #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) if (n == -1 || n < sizeof(struct bootp) - BOOTP_VENDSIZE)
goto bad; goto bad;
bp = (struct bootp *)pkt;
#ifdef BOOTP_DEBUG #ifdef BOOTP_DEBUG
if (debug) if (debug)
printf("bootprecv: checked. bp = 0x%lx, n = %d\n", printf("bootprecv: checked. bp = %p, n = %zd\n", bp, n);
(long)bp, (int)n);
#endif #endif
if (bp->bp_xid != htonl(d->xid)) { if (bp->bp_xid != htonl(d->xid)) {
#ifdef BOOTP_DEBUG #ifdef BOOTP_DEBUG
@ -328,8 +320,21 @@ time_t tleft;
/* Suck out vendor info */ /* Suck out vendor info */
if (bcmp(vm_rfc1048, bp->bp_vend, sizeof(vm_rfc1048)) == 0) { 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; 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 #ifdef BOOTP_VEND_CMU
else if (bcmp(vm_cmu, bp->bp_vend, sizeof(vm_cmu)) == 0) else if (bcmp(vm_cmu, bp->bp_vend, sizeof(vm_cmu)) == 0)
@ -338,8 +343,11 @@ time_t tleft;
else else
printf("bootprecv: unknown vendor 0x%lx\n", (long)bp->bp_vend); printf("bootprecv: unknown vendor 0x%lx\n", (long)bp->bp_vend);
return(n); *pkt = ptr;
*payload = bp;
return (n);
bad: bad:
free(ptr);
errno = 0; errno = 0;
return (-1); return (-1);
} }
@ -356,9 +364,7 @@ dhcp_try_rfc1048(u_char *cp, u_int len)
} }
static int static int
vend_rfc1048(cp, len) vend_rfc1048(u_char *cp, u_int len)
u_char *cp;
u_int len;
{ {
u_char *ep; u_char *ep;
int size; int size;
@ -445,8 +451,7 @@ vend_rfc1048(cp, len)
#ifdef BOOTP_VEND_CMU #ifdef BOOTP_VEND_CMU
static void static void
vend_cmu(cp) vend_cmu(u_char *cp)
u_char *cp;
{ {
struct cmu_vend *vp; struct cmu_vend *vp;

View File

@ -147,6 +147,10 @@ struct cmu_vend {
/* v_flags values */ /* v_flags values */
#define VF_SMASK 1 /* Subnet mask field contains valid data */ #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); int dhcp_try_rfc1048(u_char *cp, u_int len);
#endif /* _BOOTP_H_ */ #endif /* _BOOTP_H_ */

View File

@ -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). * know about us (don't want to broadcast a getport call).
*/ */
int int
bp_whoami(sockfd) bp_whoami(int sockfd)
int sockfd;
{ {
/* RPC structures for PMAPPROC_CALLIT */ /* RPC structures for PMAPPROC_CALLIT */
struct args { struct args {
@ -126,22 +125,19 @@ bp_whoami(sockfd)
n_long h[RPC_HEADER_WORDS]; n_long h[RPC_HEADER_WORDS];
struct args d; struct args d;
} sdata; } sdata;
struct {
n_long h[RPC_HEADER_WORDS];
struct repl d;
} rdata;
char *send_tail, *recv_head; char *send_tail, *recv_head;
struct iodesc *d; struct iodesc *d;
int len, x; void *pkt;
int len, x, rc;
RPC_PRINTF(("bp_whoami: myip=%s\n", inet_ntoa(myip))); RPC_PRINTF(("bp_whoami: myip=%s\n", inet_ntoa(myip)));
rc = -1;
if (!(d = socktodesc(sockfd))) { if (!(d = socktodesc(sockfd))) {
RPC_PRINTF(("bp_whoami: bad socket. %d\n", sockfd)); RPC_PRINTF(("bp_whoami: bad socket. %d\n", sockfd));
return (-1); return (rc);
} }
args = &sdata.d; args = &sdata.d;
repl = &rdata.d;
/* /*
* Build request args for PMAPPROC_CALLIT. * Build request args for PMAPPROC_CALLIT.
@ -156,19 +152,19 @@ bp_whoami(sockfd)
* append encapsulated data (client IP address) * append encapsulated data (client IP address)
*/ */
if (xdr_inaddr_encode(&send_tail, myip)) if (xdr_inaddr_encode(&send_tail, myip))
return (-1); return (rc);
/* RPC: portmap/callit */ /* RPC: portmap/callit */
d->myport = htons(--rpc_port); d->myport = htons(--rpc_port);
d->destip.s_addr = INADDR_BROADCAST; /* XXX: subnet bcast? */ d->destip.s_addr = INADDR_BROADCAST; /* XXX: subnet bcast? */
/* rpc_call will set d->destport */ /* rpc_call will set d->destport */
pkt = NULL;
len = rpc_call(d, PMAPPROG, PMAPVERS, PMAPPROC_CALLIT, len = rpc_call(d, PMAPPROG, PMAPVERS, PMAPPROC_CALLIT,
args, send_tail - (char*)args, args, send_tail - (char*)args, (void **)&repl, &pkt);
repl, sizeof(*repl));
if (len < 8) { if (len < 8) {
printf("bootparamd: 'whoami' call failed\n"); printf("bootparamd: 'whoami' call failed\n");
return (-1); goto done;
} }
/* Save bootparam server address (from IP header). */ /* Save bootparam server address (from IP header). */
@ -196,7 +192,7 @@ bp_whoami(sockfd)
x = ntohl(repl->encap_len); x = ntohl(repl->encap_len);
if (len < x) { if (len < x) {
printf("bp_whoami: short reply, %d < %d\n", len, x); printf("bp_whoami: short reply, %d < %d\n", len, x);
return (-1); goto done;
} }
recv_head = (char*) repl->capsule; recv_head = (char*) repl->capsule;
@ -204,24 +200,27 @@ bp_whoami(sockfd)
hostnamelen = MAXHOSTNAMELEN-1; hostnamelen = MAXHOSTNAMELEN-1;
if (xdr_string_decode(&recv_head, hostname, &hostnamelen)) { if (xdr_string_decode(&recv_head, hostname, &hostnamelen)) {
RPC_PRINTF(("bp_whoami: bad hostname\n")); RPC_PRINTF(("bp_whoami: bad hostname\n"));
return (-1); goto done;
} }
/* domain name */ /* domain name */
domainnamelen = MAXHOSTNAMELEN-1; domainnamelen = MAXHOSTNAMELEN-1;
if (xdr_string_decode(&recv_head, domainname, &domainnamelen)) { if (xdr_string_decode(&recv_head, domainname, &domainnamelen)) {
RPC_PRINTF(("bp_whoami: bad domainname\n")); RPC_PRINTF(("bp_whoami: bad domainname\n"));
return (-1); goto done;
} }
/* gateway address */ /* gateway address */
if (xdr_inaddr_decode(&recv_head, &gateip)) { if (xdr_inaddr_decode(&recv_head, &gateip)) {
RPC_PRINTF(("bp_whoami: bad gateway\n")); RPC_PRINTF(("bp_whoami: bad gateway\n"));
return (-1); goto done;
} }
/* success */ /* success */
return(0); rc = 0;
done:
free(pkt);
return (rc);
} }
@ -233,25 +232,18 @@ bp_whoami(sockfd)
* server pathname * server pathname
*/ */
int int
bp_getfile(sockfd, key, serv_addr, pathname) bp_getfile(int sockfd, char *key, struct in_addr *serv_addr, char *pathname)
int sockfd;
char *key;
char *pathname;
struct in_addr *serv_addr;
{ {
struct { struct {
n_long h[RPC_HEADER_WORDS]; n_long h[RPC_HEADER_WORDS];
n_long d[64]; n_long d[64];
} sdata; } sdata;
struct { void *pkt;
n_long h[RPC_HEADER_WORDS];
n_long d[128];
} rdata;
char serv_name[FNAME_SIZE]; char serv_name[FNAME_SIZE];
char *send_tail, *recv_head; char *rdata, *send_tail;
/* misc... */ /* misc... */
struct iodesc *d; struct iodesc *d;
int sn_len, path_len, rlen; int rc = -1, sn_len, path_len, rlen;
if (!(d = socktodesc(sockfd))) { if (!(d = socktodesc(sockfd))) {
RPC_PRINTF(("bp_getfile: bad socket. %d\n", 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; send_tail = (char*) sdata.d;
recv_head = (char*) rdata.d;
/* /*
* Build request message. * Build request message.
@ -281,17 +272,16 @@ bp_getfile(sockfd, key, serv_addr, pathname)
d->myport = htons(--rpc_port); d->myport = htons(--rpc_port);
d->destip = bp_server_addr; d->destip = bp_server_addr;
/* rpc_call will set d->destport */ /* rpc_call will set d->destport */
pkt = NULL;
rlen = rpc_call(d, rlen = rpc_call(d,
BOOTPARAM_PROG, BOOTPARAM_VERS, BOOTPARAM_GETFILE, BOOTPARAM_PROG, BOOTPARAM_VERS, BOOTPARAM_GETFILE,
sdata.d, send_tail - (char*)sdata.d, sdata.d, send_tail - (char*)sdata.d,
rdata.d, sizeof(rdata.d)); (void **)&rdata, &pkt);
if (rlen < 4) { if (rlen < 4) {
RPC_PRINTF(("bp_getfile: short reply\n")); RPC_PRINTF(("bp_getfile: short reply\n"));
errno = EBADRPC; errno = EBADRPC;
return (-1); goto done;
} }
recv_head = (char*) rdata.d;
/* /*
* Parse result message. * Parse result message.
@ -299,26 +289,29 @@ bp_getfile(sockfd, key, serv_addr, pathname)
/* server name */ /* server name */
sn_len = FNAME_SIZE-1; 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")); RPC_PRINTF(("bp_getfile: bad server name\n"));
return (-1); goto done;
} }
/* server IP address (mountd/NFS) */ /* 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")); RPC_PRINTF(("bp_getfile: bad server addr\n"));
return (-1); goto done;
} }
/* server pathname */ /* server pathname */
path_len = MAXPATHLEN-1; 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")); RPC_PRINTF(("bp_getfile: bad server path\n"));
return (-1); goto done;
} }
/* success */ /* success */
return(0); rc = 0;
done:
free(pkt);
return (rc);
} }
@ -329,17 +322,14 @@ bp_getfile(sockfd, key, serv_addr, pathname)
int int
xdr_string_encode(pkt, str, len) xdr_string_encode(char **pkt, char *str, int len)
char **pkt;
char *str;
int len;
{ {
u_int32_t *lenp; uint32_t *lenp;
char *datap; char *datap;
int padlen = (len + 3) & ~3; /* padded length */ int padlen = (len + 3) & ~3; /* padded length */
/* The data will be int aligned. */ /* The data will be int aligned. */
lenp = (u_int32_t*) *pkt; lenp = (uint32_t *) *pkt;
*pkt += sizeof(*lenp); *pkt += sizeof(*lenp);
*lenp = htonl(len); *lenp = htonl(len);
@ -351,18 +341,15 @@ xdr_string_encode(pkt, str, len)
} }
int int
xdr_string_decode(pkt, str, len_p) xdr_string_decode(char **pkt, char *str, int *len_p)
char **pkt;
char *str;
int *len_p; /* bufsize - 1 */
{ {
u_int32_t *lenp; uint32_t *lenp;
char *datap; char *datap;
int slen; /* string length */ int slen; /* string length */
int plen; /* padded length */ int plen; /* padded length */
/* The data will be int aligned. */ /* The data will be int aligned. */
lenp = (u_int32_t*) *pkt; lenp = (uint32_t *) *pkt;
*pkt += sizeof(*lenp); *pkt += sizeof(*lenp);
slen = ntohl(*lenp); slen = ntohl(*lenp);
plen = (slen + 3) & ~3; plen = (slen + 3) & ~3;
@ -381,9 +368,7 @@ xdr_string_decode(pkt, str, len_p)
int int
xdr_inaddr_encode(pkt, ia) xdr_inaddr_encode(char **pkt, struct in_addr ia)
char **pkt;
struct in_addr ia; /* network order */
{ {
struct xdr_inaddr *xi; struct xdr_inaddr *xi;
u_char *cp; u_char *cp;
@ -414,9 +399,7 @@ xdr_inaddr_encode(pkt, ia)
} }
int int
xdr_inaddr_decode(pkt, ia) xdr_inaddr_decode(char **pkt, struct in_addr *ia)
char **pkt;
struct in_addr *ia; /* network order */
{ {
struct xdr_inaddr *xi; struct xdr_inaddr *xi;
u_char *cp; u_char *cp;

View File

@ -54,12 +54,7 @@ __FBSDID("$FreeBSD$");
/* Caller must leave room for ethernet header in front!! */ /* Caller must leave room for ethernet header in front!! */
ssize_t ssize_t
sendether(d, pkt, len, dea, etype) sendether(struct iodesc *d, void *pkt, size_t len, uint8_t *dea, int etype)
struct iodesc *d;
void *pkt;
size_t len;
u_char *dea;
int etype;
{ {
ssize_t n; ssize_t n;
struct ether_header *eh; 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 * Get a packet of any Ethernet type, with our address or
* the broadcast address. Save the Ether type in arg 5. * the broadcast address. Save the Ether type in etype.
* NOTE: Caller must leave room for the Ether header. * Unless there is an error, we pass the whole packet and the unencapsulated
* data.
*/ */
ssize_t ssize_t
readether(d, pkt, len, tleft, etype) readether(struct iodesc *d, void **pkt, void **payload, time_t tleft,
struct iodesc *d; uint16_t *etype)
void *pkt;
size_t len;
time_t tleft;
u_int16_t *etype;
{ {
ssize_t n; ssize_t n;
struct ether_header *eh; struct ether_header *eh;
void *ptr;
#ifdef ETHER_DEBUG #ifdef ETHER_DEBUG
if (debug) if (debug)
printf("readether: called\n"); printf("readether: called\n");
#endif #endif
eh = (struct ether_header *)pkt - 1; ptr = NULL;
len += sizeof(*eh); n = netif_get(d, &ptr, tleft);
if (n == -1 || n < sizeof(*eh)) {
n = netif_get(d, eh, len, tleft); free(ptr);
if (n == -1 || n < sizeof(*eh))
return (-1); return (-1);
}
eh = (struct ether_header *)((uintptr_t)ptr + ETHER_ALIGN);
/* Validate Ethernet address. */ /* Validate Ethernet address. */
if (bcmp(d->myea, eh->ether_dhost, 6) != 0 && if (bcmp(d->myea, eh->ether_dhost, 6) != 0 &&
bcmp(bcea, 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", printf("readether: not ours (ea=%s)\n",
ether_sprintf(eh->ether_dhost)); ether_sprintf(eh->ether_dhost));
#endif #endif
free(ptr);
return (-1); return (-1);
} }
*pkt = ptr;
*payload = (void *)((uintptr_t)eh + sizeof(*eh));
*etype = ntohs(eh->ether_type); *etype = ntohs(eh->ether_type);
n -= sizeof(*eh); n -= sizeof(*eh);
@ -133,8 +131,7 @@ readether(d, pkt, len, tleft, etype)
*/ */
static char digits[] = "0123456789abcdef"; static char digits[] = "0123456789abcdef";
char * char *
ether_sprintf(ap) ether_sprintf(u_char *ap)
u_char *ap;
{ {
int i; int i;
static char etherbuf[18]; static char etherbuf[18];

View File

@ -70,10 +70,10 @@ __FBSDID("$FreeBSD$");
*/ */
ssize_t ssize_t
sendrecv(struct iodesc *d, sendrecv(struct iodesc *d,
ssize_t (*sproc)(struct iodesc *, void *, size_t), ssize_t (*sproc)(struct iodesc *, void *, size_t),
void *sbuf, size_t ssize, void *sbuf, size_t ssize,
ssize_t (*rproc)(struct iodesc *, void *, size_t, time_t), ssize_t (*rproc)(struct iodesc *, void **, void **, time_t),
void *rbuf, size_t rsize) void **pkt, void **payload)
{ {
ssize_t cc; ssize_t cc;
time_t t, tmo, tlast; time_t t, tmo, tlast;
@ -116,7 +116,7 @@ sendrecv(struct iodesc *d,
} }
/* Try to get a packet and process it. */ /* 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. */ /* Return on data, EOF or real error. */
if (cc != -1 || errno != 0) if (cc != -1 || errno != 0)
return (cc); return (cc);

View File

@ -106,16 +106,15 @@ int rarp_getipaddress(int);
/* Link functions: */ /* Link functions: */
ssize_t sendether(struct iodesc *d, void *pkt, size_t len, ssize_t sendether(struct iodesc *d, void *pkt, size_t len,
u_char *dea, int etype); u_char *dea, int etype);
ssize_t readether(struct iodesc *d, void *pkt, size_t len, ssize_t readether(struct iodesc *, void **, void **, time_t, uint16_t *);
time_t tleft, u_int16_t *etype);
ssize_t sendudp(struct iodesc *, void *, size_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 sendrecv(struct iodesc *,
ssize_t (*)(struct iodesc *, void *, size_t), ssize_t (*)(struct iodesc *, void *, size_t),
void *, size_t, void *, size_t,
ssize_t (*)(struct iodesc *, void *, size_t, time_t), ssize_t (*)(struct iodesc *, void **, void **, time_t),
void *, size_t); void **, void **);
/* bootp/DHCP */ /* bootp/DHCP */
void bootp(int, int); void bootp(int, int);

View File

@ -59,7 +59,7 @@ int netif_debug = 0;
*/ */
void void
netif_init() netif_init(void)
{ {
struct netif_driver *drv; struct netif_driver *drv;
int d, i; int d, i;
@ -76,13 +76,11 @@ netif_init()
} }
int int
netif_match(nif, machdep_hint) netif_match(struct netif *nif, void *machdep_hint)
struct netif *nif;
void *machdep_hint;
{ {
struct netif_driver *drv = nif->nif_driver; struct netif_driver *drv = nif->nif_driver;
#if 0 #if NETIF_DEBUG
if (netif_debug) if (netif_debug)
printf("%s%d: netif_match (%d)\n", drv->netif_bname, printf("%s%d: netif_match (%d)\n", drv->netif_bname,
nif->nif_unit, nif->nif_sel); nif->nif_unit, nif->nif_sel);
@ -91,8 +89,7 @@ netif_match(nif, machdep_hint)
} }
struct netif * struct netif *
netif_select(machdep_hint) netif_select(void *machdep_hint)
void *machdep_hint;
{ {
int d, u, unit_done, s; int d, u, unit_done, s;
struct netif_driver *drv; struct netif_driver *drv;
@ -162,9 +159,7 @@ netif_select(machdep_hint)
} }
int int
netif_probe(nif, machdep_hint) netif_probe(struct netif *nif, void *machdep_hint)
struct netif *nif;
void *machdep_hint;
{ {
struct netif_driver *drv = nif->nif_driver; struct netif_driver *drv = nif->nif_driver;
@ -176,10 +171,7 @@ netif_probe(nif, machdep_hint)
} }
void void
netif_attach(nif, desc, machdep_hint) netif_attach(struct netif *nif, struct iodesc *desc, void *machdep_hint)
struct netif *nif;
struct iodesc *desc;
void *machdep_hint;
{ {
struct netif_driver *drv = nif->nif_driver; struct netif_driver *drv = nif->nif_driver;
@ -199,8 +191,7 @@ netif_attach(nif, desc, machdep_hint)
} }
void void
netif_detach(nif) netif_detach(struct netif *nif)
struct netif *nif;
{ {
struct netif_driver *drv = nif->nif_driver; struct netif_driver *drv = nif->nif_driver;
@ -217,11 +208,7 @@ netif_detach(nif)
} }
ssize_t ssize_t
netif_get(desc, pkt, len, timo) netif_get(struct iodesc *desc, void **pkt, time_t timo)
struct iodesc *desc;
void *pkt;
size_t len;
time_t timo;
{ {
#ifdef NETIF_DEBUG #ifdef NETIF_DEBUG
struct netif *nif = desc->io_netif; 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, panic("%s%d: no netif_get support\n", drv->netif_bname,
nif->nif_unit); nif->nif_unit);
#endif #endif
rv = drv->netif_get(desc, pkt, len, timo); rv = drv->netif_get(desc, pkt, timo);
#ifdef NETIF_DEBUG #ifdef NETIF_DEBUG
if (netif_debug) if (netif_debug)
printf("%s%d: netif_get returning %d\n", drv->netif_bname, printf("%s%d: netif_get returning %d\n", drv->netif_bname,
nif->nif_unit, (int)rv); nif->nif_unit, (int)rv);
#endif #endif
return rv; return (rv);
} }
ssize_t ssize_t
netif_put(desc, pkt, len) netif_put(struct iodesc *desc, void *pkt, size_t len)
struct iodesc *desc;
void *pkt;
size_t len;
{ {
#ifdef NETIF_DEBUG #ifdef NETIF_DEBUG
struct netif *nif = desc->io_netif; 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, printf("%s%d: netif_put returning %d\n", drv->netif_bname,
nif->nif_unit, (int)rv); nif->nif_unit, (int)rv);
#endif #endif
return rv; return (rv);
} }
struct iodesc * struct iodesc *
socktodesc(sock) socktodesc(int sock)
int sock;
{ {
if (sock >= SOPEN_MAX) { if (sock >= SOPEN_MAX) {
errno = EBADF; errno = EBADF;
@ -289,8 +272,7 @@ socktodesc(sock)
} }
int int
netif_open(machdep_hint) netif_open(void *machdep_hint)
void *machdep_hint;
{ {
int fd; int fd;
struct iodesc *s; struct iodesc *s;
@ -313,23 +295,22 @@ fnd:
printf("netboot: couldn't probe %s%d\n", printf("netboot: couldn't probe %s%d\n",
nif->nif_driver->netif_bname, nif->nif_unit); nif->nif_driver->netif_bname, nif->nif_unit);
errno = EINVAL; errno = EINVAL;
return(-1); return (-1);
} }
netif_attach(nif, s, machdep_hint); netif_attach(nif, s, machdep_hint);
return(fd); return (fd);
} }
int int
netif_close(sock) netif_close(int sock)
int sock;
{ {
if (sock >= SOPEN_MAX) { if (sock >= SOPEN_MAX) {
errno = EBADF; errno = EBADF;
return(-1); return (-1);
} }
netif_detach(sockets[sock].io_netif); netif_detach(sockets[sock].io_netif);
sockets[sock].io_netif = (struct netif *)0; sockets[sock].io_netif = (struct netif *)0;
return(0); return (0);
} }

View File

@ -6,15 +6,13 @@
#define __SYS_LIBNETBOOT_NETIF_H #define __SYS_LIBNETBOOT_NETIF_H
#include "iodesc.h" #include "iodesc.h"
#define NENTS(x) sizeof(x)/sizeof(x[0])
struct netif_driver { struct netif_driver {
const char *netif_bname; const char *netif_bname;
int (*netif_match)(struct netif *, void *); int (*netif_match)(struct netif *, void *);
int (*netif_probe)(struct netif *, void *); int (*netif_probe)(struct netif *, void *);
void (*netif_init)(struct iodesc *, void *); void (*netif_init)(struct iodesc *, void *);
int (*netif_get)(struct iodesc *, void *, size_t, time_t); ssize_t (*netif_get)(struct iodesc *, void **, time_t);
int (*netif_put)(struct iodesc *, void *, size_t); ssize_t (*netif_put)(struct iodesc *, void *, size_t);
void (*netif_end)(struct netif *); void (*netif_end)(struct netif *);
struct netif_dif *netif_ifs; struct netif_dif *netif_ifs;
int netif_nifs; int netif_nifs;
@ -56,7 +54,7 @@ struct netif *netif_select(void *);
int netif_probe(struct netif *, void *); int netif_probe(struct netif *, void *);
void netif_attach(struct netif *, struct iodesc *, void *); void netif_attach(struct netif *, struct iodesc *, void *);
void netif_detach(struct netif *); 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); ssize_t netif_put(struct iodesc *, void *, size_t);
int netif_open(void *); int netif_open(void *);

View File

@ -185,6 +185,7 @@ set_nfs_read_size(void)
int int
nfs_getrootfh(struct iodesc *d, char *path, uint32_t *fhlenp, u_char *fhp) nfs_getrootfh(struct iodesc *d, char *path, uint32_t *fhlenp, u_char *fhp)
{ {
void *pkt = NULL;
int len; int len;
struct args { struct args {
uint32_t len; 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]; uint32_t h[RPC_HEADER_WORDS];
struct args d; struct args d;
} sdata; } sdata;
struct {
uint32_t h[RPC_HEADER_WORDS];
struct repl d;
} rdata;
size_t cc; size_t cc;
#ifdef NFS_DEBUG #ifdef NFS_DEBUG
@ -213,7 +210,6 @@ nfs_getrootfh(struct iodesc *d, char *path, uint32_t *fhlenp, u_char *fhp)
#endif #endif
args = &sdata.d; args = &sdata.d;
repl = &rdata.d;
bzero(args, sizeof(*args)); bzero(args, sizeof(*args));
len = strlen(path); 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)); len = sizeof(uint32_t) + roundup(len, sizeof(uint32_t));
cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER3, RPCMNT_MOUNT, cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER3, RPCMNT_MOUNT,
args, len, repl, sizeof(*repl)); args, len, (void **)&repl, &pkt);
if (cc == -1) if (cc == -1) {
free(pkt);
/* errno was set by rpc_call */ /* errno was set by rpc_call */
return (errno); return (errno);
if (cc < 2 * sizeof (uint32_t)) }
if (cc < 2 * sizeof (uint32_t)) {
free(pkt);
return (EBADRPC); return (EBADRPC);
if (repl->errno != 0) }
if (repl->errno != 0) {
free(pkt);
return (ntohl(repl->errno)); return (ntohl(repl->errno));
}
*fhlenp = ntohl(repl->fhsize); *fhlenp = ntohl(repl->fhsize);
bcopy(repl->fh, fhp, *fhlenp); bcopy(repl->fh, fhp, *fhlenp);
set_nfs_read_size(); set_nfs_read_size();
free(pkt);
return (0); return (0);
} }
@ -246,6 +249,7 @@ nfs_getrootfh(struct iodesc *d, char *path, uint32_t *fhlenp, u_char *fhp)
int int
nfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd) nfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd)
{ {
void *pkt = NULL;
int len, rlen, pos; int len, rlen, pos;
struct args { struct args {
uint32_t fhsize; 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]; uint32_t h[RPC_HEADER_WORDS];
struct args d; struct args d;
} sdata; } sdata;
struct {
uint32_t h[RPC_HEADER_WORDS];
struct repl d;
} rdata;
ssize_t cc; ssize_t cc;
#ifdef NFS_DEBUG #ifdef NFS_DEBUG
@ -275,7 +275,6 @@ nfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd)
#endif #endif
args = &sdata.d; args = &sdata.d;
repl = &rdata.d;
bzero(args, sizeof(*args)); bzero(args, sizeof(*args));
args->fhsize = htonl(d->fhsize); 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) + len = sizeof(uint32_t) + pos * sizeof(uint32_t) +
roundup(len, sizeof(uint32_t)); roundup(len, sizeof(uint32_t));
rlen = sizeof(*repl);
cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_LOOKUP, cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_LOOKUP,
args, len, repl, rlen); args, len, (void **)&repl, &pkt);
if (cc == -1) if (cc == -1) {
free(pkt);
return (errno); /* XXX - from rpc_call */ return (errno); /* XXX - from rpc_call */
if (cc < 2 * sizeof(uint32_t)) }
if (cc < 2 * sizeof(uint32_t)) {
free(pkt);
return (EIO); return (EIO);
if (repl->errno != 0) }
if (repl->errno != 0) {
free(pkt);
/* saerrno.h now matches NFS error numbers. */ /* saerrno.h now matches NFS error numbers. */
return (ntohl(repl->errno)); return (ntohl(repl->errno));
}
newfd->fhsize = ntohl(repl->fhsize); newfd->fhsize = ntohl(repl->fhsize);
bcopy(repl->fhplusattr, &newfd->fh, newfd->fhsize); bcopy(repl->fhplusattr, &newfd->fh, newfd->fhsize);
pos = roundup(newfd->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); pos = roundup(newfd->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
if (repl->fhplusattr[pos++] == 0) if (repl->fhplusattr[pos++] == 0) {
free(pkt);
return (EIO); return (EIO);
}
bcopy(&repl->fhplusattr[pos], &newfd->fa, sizeof(newfd->fa)); bcopy(&repl->fhplusattr[pos], &newfd->fa, sizeof(newfd->fa));
free(pkt);
return (0); return (0);
} }
@ -316,6 +322,7 @@ nfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd)
int int
nfs_readlink(struct nfs_iodesc *d, char *buf) nfs_readlink(struct nfs_iodesc *d, char *buf)
{ {
void *pkt = NULL;
struct args { struct args {
uint32_t fhsize; uint32_t fhsize;
u_char fh[NFS_V3MAXFHSIZE]; u_char fh[NFS_V3MAXFHSIZE];
@ -331,11 +338,8 @@ nfs_readlink(struct nfs_iodesc *d, char *buf)
uint32_t h[RPC_HEADER_WORDS]; uint32_t h[RPC_HEADER_WORDS];
struct args d; struct args d;
} sdata; } sdata;
struct {
uint32_t h[RPC_HEADER_WORDS];
struct repl d;
} rdata;
ssize_t cc; ssize_t cc;
int rc = 0;
#ifdef NFS_DEBUG #ifdef NFS_DEBUG
if (debug) if (debug)
@ -343,32 +347,41 @@ nfs_readlink(struct nfs_iodesc *d, char *buf)
#endif #endif
args = &sdata.d; args = &sdata.d;
repl = &rdata.d;
bzero(args, sizeof(*args)); bzero(args, sizeof(*args));
args->fhsize = htonl(d->fhsize); args->fhsize = htonl(d->fhsize);
bcopy(d->fh, args->fh, d->fhsize); bcopy(d->fh, args->fh, d->fhsize);
cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READLINK, cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READLINK,
args, sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)), args, sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)),
repl, sizeof(*repl)); (void **)&repl, &pkt);
if (cc == -1) if (cc == -1)
return (errno); return (errno);
if (cc < 2 * sizeof(uint32_t)) if (cc < 2 * sizeof(uint32_t)) {
return (EIO); rc = EIO;
goto done;
}
if (repl->errno != 0) if (repl->errno != 0) {
return (ntohl(repl->errno)); rc = ntohl(repl->errno);
goto done;
}
if (repl->ok == 0) if (repl->ok == 0) {
return (EIO); rc = EIO;
goto done;
}
repl->len = ntohl(repl->len); repl->len = ntohl(repl->len);
if (repl->len > NFS_MAXPATHLEN) if (repl->len > NFS_MAXPATHLEN) {
return (ENAMETOOLONG); rc = ENAMETOOLONG;
goto done;
}
bcopy(repl->path, buf, repl->len); bcopy(repl->path, buf, repl->len);
buf[repl->len] = 0; buf[repl->len] = 0;
done:
free(pkt);
return (0); return (0);
} }
#endif #endif
@ -380,6 +393,7 @@ nfs_readlink(struct nfs_iodesc *d, char *buf)
ssize_t ssize_t
nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len) nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len)
{ {
void *pkt = NULL;
struct args { struct args {
uint32_t fhsize; uint32_t fhsize;
uint32_t fhoffcnt[NFS_V3MAXFHSIZE / sizeof(uint32_t) + 3]; 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]; uint32_t h[RPC_HEADER_WORDS];
struct args d; struct args d;
} sdata; } sdata;
struct {
uint32_t h[RPC_HEADER_WORDS];
struct repl d;
} rdata;
size_t cc; size_t cc;
long x; long x;
int hlen, rlen, pos; int hlen, rlen, pos;
args = &sdata.d; args = &sdata.d;
repl = &rdata.d;
bzero(args, sizeof(*args)); bzero(args, sizeof(*args));
args->fhsize = htonl(d->fhsize); 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, cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READ,
args, 4 * sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)), args, 4 * sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)),
repl, sizeof(*repl)); (void **)&repl, &pkt);
if (cc == -1) if (cc == -1) {
/* errno was already set by rpc_call */ /* errno was already set by rpc_call */
return (-1); return (-1);
}
if (cc < hlen) { if (cc < hlen) {
errno = EBADRPC; errno = EBADRPC;
free(pkt);
return (-1); return (-1);
} }
if (repl->errno != 0) { if (repl->errno != 0) {
errno = ntohl(repl->errno); errno = ntohl(repl->errno);
free(pkt);
return (-1); return (-1);
} }
rlen = cc - hlen; rlen = cc - hlen;
@ -438,9 +450,11 @@ nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len)
if (rlen < x) { if (rlen < x) {
printf("nfsread: short packet, %d < %ld\n", rlen, x); printf("nfsread: short packet, %d < %ld\n", rlen, x);
errno = EBADRPC; errno = EBADRPC;
free(pkt);
return (-1); return (-1);
} }
bcopy(repl->data, addr, x); bcopy(repl->data, addr, x);
free(pkt);
return (x); return (x);
} }
@ -481,17 +495,8 @@ nfs_open(const char *upath, struct open_file *f)
return (ENXIO); return (ENXIO);
} }
/* if (f->f_dev->dv_type != DEVT_NET)
* 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)
return (EINVAL); return (EINVAL);
#else
if (strcmp(f->f_dev->dv_name, "pxe") != 0)
return (EINVAL);
#endif
if (!(desc = socktodesc(*(int *)(f->f_devdata)))) if (!(desc = socktodesc(*(int *)(f->f_devdata))))
return (EINVAL); return (EINVAL);
@ -660,9 +665,8 @@ nfs_close(struct open_file *f)
printf("nfs_close: fp=0x%lx\n", (u_long)fp); printf("nfs_close: fp=0x%lx\n", (u_long)fp);
#endif #endif
if (fp) free(fp);
free(fp); f->f_fsdata = NULL;
f->f_fsdata = (void *)0;
return (0); 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 nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
struct nfsv3_readdir_repl *repl; struct nfsv3_readdir_repl *repl;
struct nfsv3_readdir_entry *rent; struct nfsv3_readdir_entry *rent;
static void *pkt = NULL;
static char *buf; static char *buf;
static struct nfs_iodesc *pfp = NULL; static struct nfs_iodesc *pfp = NULL;
static uint64_t cookie = 0; static uint64_t cookie = 0;
size_t cc; size_t cc;
int pos; int pos, rc;
struct args { struct args {
uint32_t fhsize; uint32_t fhsize;
@ -787,14 +792,12 @@ nfs_readdir(struct open_file *f, struct dirent *d)
uint32_t h[RPC_HEADER_WORDS]; uint32_t h[RPC_HEADER_WORDS];
struct args d; struct args d;
} sdata; } sdata;
static struct {
uint32_t h[RPC_HEADER_WORDS];
u_char d[NFS_READDIRSIZE];
} rdata;
if (fp != pfp || fp->off != cookie) { if (fp != pfp || fp->off != cookie) {
pfp = NULL; pfp = NULL;
refill: refill:
free(pkt);
pkt = NULL;
args = &sdata.d; args = &sdata.d;
bzero(args, sizeof(*args)); 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, cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READDIR,
args, 6 * sizeof(uint32_t) + args, 6 * sizeof(uint32_t) +
roundup(fp->fhsize, sizeof(uint32_t)), roundup(fp->fhsize, sizeof(uint32_t)),
rdata.d, sizeof(rdata.d)); (void **)&buf, &pkt);
buf = rdata.d; if (cc == -1) {
rc = errno;
goto err;
}
repl = (struct nfsv3_readdir_repl *)buf; repl = (struct nfsv3_readdir_repl *)buf;
if (repl->errno != 0) if (repl->errno != 0) {
return (ntohl(repl->errno)); rc = ntohl(repl->errno);
goto err;
}
pfp = fp; pfp = fp;
cookie = fp->off; cookie = fp->off;
fp->cookie = ((uint64_t)ntohl(repl->cookiev0) << 32) | 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) { if (rent->follows == 0) {
/* fid0 is actually eof */ /* fid0 is actually eof */
if (rent->fid0 != 0) { if (rent->fid0 != 0) {
cookie = 0; rc = ENOENT;
return (ENOENT); goto err;
} }
goto refill; goto refill;
} }
@ -842,4 +850,11 @@ nfs_readdir(struct open_file *f, struct dirent *d)
pos += 2; pos += 2;
buf = (u_char *)&rent->nameplus[pos]; buf = (u_char *)&rent->nameplus[pos];
return (0); return (0);
err:
free(pkt);
pkt = NULL;
pfp = NULL;
cookie = 0;
return (rc);
} }

View File

@ -54,17 +54,17 @@ __FBSDID("$FreeBSD$");
static ssize_t rarpsend(struct iodesc *, void *, size_t); 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). * Ethernet (Reverse) Address Resolution Protocol (see RFC 903, and 826).
*/ */
int int
rarp_getipaddress(sock) rarp_getipaddress(int sock)
int sock;
{ {
struct iodesc *d; struct iodesc *d;
struct ether_arp *ap; struct ether_arp *ap;
void *pkt;
struct { struct {
u_char header[ETHER_SIZE]; u_char header[ETHER_SIZE];
struct { struct {
@ -72,13 +72,6 @@ rarp_getipaddress(sock)
u_char pad[18]; /* 60 - sizeof(arp) */ u_char pad[18]; /* 60 - sizeof(arp) */
} data; } data;
} wbuf; } wbuf;
struct {
u_char header[ETHER_SIZE];
struct {
struct ether_arp arp;
u_char pad[24]; /* extra space */
} data;
} rbuf;
#ifdef RARP_DEBUG #ifdef RARP_DEBUG
if (debug) if (debug)
@ -102,21 +95,21 @@ rarp_getipaddress(sock)
ap->arp_op = htons(ARPOP_REVREQUEST); ap->arp_op = htons(ARPOP_REVREQUEST);
bcopy(d->myea, ap->arp_sha, 6); bcopy(d->myea, ap->arp_sha, 6);
bcopy(d->myea, ap->arp_tha, 6); bcopy(d->myea, ap->arp_tha, 6);
pkt = NULL;
if (sendrecv(d, if (sendrecv(d,
rarpsend, &wbuf.data, sizeof(wbuf.data), 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"); printf("No response for RARP request\n");
return (-1); return (-1);
} }
ap = &rbuf.data.arp;
bcopy(ap->arp_tpa, (char *)&myip, sizeof(myip)); bcopy(ap->arp_tpa, (char *)&myip, sizeof(myip));
#if 0 #if 0
/* XXX - Can NOT assume this is our root server! */ /* XXX - Can NOT assume this is our root server! */
bcopy(ap->arp_spa, (char *)&rootip, sizeof(rootip)); bcopy(ap->arp_spa, (char *)&rootip, sizeof(rootip));
#endif #endif
free(pkt);
/* Compute our "natural" netmask. */ /* Compute our "natural" netmask. */
if (IN_CLASSA(myip.s_addr)) if (IN_CLASSA(myip.s_addr))
@ -134,10 +127,7 @@ rarp_getipaddress(sock)
* Broadcast a RARP request (i.e. who knows who I am) * Broadcast a RARP request (i.e. who knows who I am)
*/ */
static ssize_t static ssize_t
rarpsend(d, pkt, len) rarpsend(struct iodesc *d, void *pkt, size_t len)
struct iodesc *d;
void *pkt;
size_t len;
{ {
#ifdef RARP_DEBUG #ifdef RARP_DEBUG
@ -153,28 +143,26 @@ rarpsend(d, pkt, len)
* else -1 (and errno == 0) * else -1 (and errno == 0)
*/ */
static ssize_t static ssize_t
rarprecv(d, pkt, len, tleft) rarprecv(struct iodesc *d, void **pkt, void **payload, time_t tleft)
struct iodesc *d;
void *pkt;
size_t len;
time_t tleft;
{ {
ssize_t n; ssize_t n;
struct ether_arp *ap; struct ether_arp *ap;
u_int16_t etype; /* host order */ void *ptr = NULL;
uint16_t etype; /* host order */
#ifdef RARP_DEBUG #ifdef RARP_DEBUG
if (debug) if (debug)
printf("rarprecv: "); printf("rarprecv: ");
#endif #endif
n = readether(d, pkt, len, tleft, &etype); n = readether(d, ptr, (void **)&ap, tleft, &etype);
errno = 0; /* XXX */ errno = 0; /* XXX */
if (n == -1 || n < sizeof(struct ether_arp)) { if (n == -1 || n < sizeof(struct ether_arp)) {
#ifdef RARP_DEBUG #ifdef RARP_DEBUG
if (debug) if (debug)
printf("bad len=%d\n", n); printf("bad len=%d\n", n);
#endif #endif
free(ptr);
return (-1); return (-1);
} }
@ -183,10 +171,10 @@ rarprecv(d, pkt, len, tleft)
if (debug) if (debug)
printf("bad type=0x%x\n", etype); printf("bad type=0x%x\n", etype);
#endif #endif
free(ptr);
return (-1); return (-1);
} }
ap = (struct ether_arp *)pkt;
if (ap->arp_hrd != htons(ARPHRD_ETHER) || if (ap->arp_hrd != htons(ARPHRD_ETHER) ||
ap->arp_pro != htons(ETHERTYPE_IP) || ap->arp_pro != htons(ETHERTYPE_IP) ||
ap->arp_hln != sizeof(ap->arp_sha) || ap->arp_hln != sizeof(ap->arp_sha) ||
@ -196,6 +184,7 @@ rarprecv(d, pkt, len, tleft)
if (debug) if (debug)
printf("bad hrd/pro/hln/pln\n"); printf("bad hrd/pro/hln/pln\n");
#endif #endif
free(ptr);
return (-1); return (-1);
} }
@ -204,6 +193,7 @@ rarprecv(d, pkt, len, tleft)
if (debug) if (debug)
printf("bad op=0x%x\n", ntohs(ap->arp_op)); printf("bad op=0x%x\n", ntohs(ap->arp_op));
#endif #endif
free(ptr);
return (-1); return (-1);
} }
@ -213,6 +203,7 @@ rarprecv(d, pkt, len, tleft)
if (debug) if (debug)
printf("unwanted address\n"); printf("unwanted address\n");
#endif #endif
free(ptr);
return (-1); return (-1);
} }
@ -221,5 +212,7 @@ rarprecv(d, pkt, len, tleft)
if (debug) if (debug)
printf("got it\n"); printf("got it\n");
#endif #endif
*pkt = ptr;
*payload = ap;
return (n); return (n);
} }

View File

@ -97,7 +97,7 @@ struct rpc_reply {
}; };
/* Local forwards */ /* 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); static int rpc_getport(struct iodesc *, n_long, n_long);
int rpc_xid; int rpc_xid;
@ -109,14 +109,14 @@ int rpc_port = 0x400; /* predecrement */
*/ */
ssize_t ssize_t
rpc_call(struct iodesc *d, n_long prog, n_long vers, n_long proc, 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 auth_info *auth;
struct rpc_call *call; struct rpc_call *call;
struct rpc_reply *reply; struct rpc_reply *reply;
char *send_head, *send_tail; char *send_head, *send_tail;
char *recv_head, *recv_tail; void *ptr;
n_long x; n_long x;
int port; /* host order */ 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->authtype = htonl(RPCAUTH_NULL);
auth->authlen = 0; auth->authlen = 0;
#if 1
/* Auth credentials: always auth unix (as root) */ /* Auth credentials: always auth unix (as root) */
send_head -= sizeof(struct auth_unix); send_head -= sizeof(struct auth_unix);
bzero(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 = (struct auth_info *)send_head;
auth->authtype = htonl(RPCAUTH_UNIX); auth->authtype = htonl(RPCAUTH_UNIX);
auth->authlen = htonl(sizeof(struct auth_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. */ /* RPC call structure. */
send_head -= sizeof(*call); 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_vers = htonl(vers);
call->rp_proc = htonl(proc); call->rp_proc = htonl(proc);
/* Make room for the rpc_reply header. */ ptr = NULL;
recv_head = rdata;
recv_tail = (char *)rdata + rlen;
recv_head -= sizeof(*reply);
cc = sendrecv(d, cc = sendrecv(d,
sendudp, send_head, send_tail - send_head, sendudp, send_head, send_tail - send_head,
recvrpc, recv_head, recv_tail - recv_head); recvrpc, &ptr, (void **)&reply);
#ifdef RPC_DEBUG #ifdef RPC_DEBUG
if (debug) if (debug)
printf("callrpc: cc=%ld rlen=%lu\n", (long)cc, (u_long)rlen); printf("callrpc: cc=%zd\n", cc);
#endif #endif
if (cc == -1) if (cc == -1)
return (-1); return (-1);
if (cc <= sizeof(*reply)) { if (cc <= sizeof(*reply)) {
errno = EBADRPC; errno = EBADRPC;
free(ptr);
return (-1); return (-1);
} }
recv_tail = recv_head + cc;
/* /*
* Check the RPC reply status. * Check the RPC reply status.
* The xid, dir, astatus were already checked. * The xid, dir, astatus were already checked.
*/ */
reply = (struct rpc_reply *)recv_head;
auth = &reply->rp_u.rpu_rok.rok_auth; auth = &reply->rp_u.rpu_rok.rok_auth;
x = ntohl(auth->authlen); x = ntohl(auth->authlen);
if (x != 0) { 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"); printf("callrpc: reply auth != NULL\n");
#endif #endif
errno = EBADRPC; errno = EBADRPC;
return(-1); free(ptr);
return (-1);
} }
x = ntohl(reply->rp_u.rpu_rok.rok_status); x = ntohl(reply->rp_u.rpu_rok.rok_status);
if (x != 0) { if (x != 0) {
printf("callrpc: error = %ld\n", (long)x); printf("callrpc: error = %ld\n", (long)x);
errno = EBADRPC; 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 * Remaining checks are done by callrpc
*/ */
static ssize_t 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; struct rpc_reply *reply;
ssize_t n; ssize_t n;
int x; int x;
@ -236,14 +227,15 @@ recvrpc(struct iodesc *d, void *pkt, size_t len, time_t tleft)
errno = 0; errno = 0;
#ifdef RPC_DEBUG #ifdef RPC_DEBUG
if (debug) if (debug)
printf("recvrpc: called len=%lu\n", (u_long)len); printf("recvrpc: called\n");
#endif #endif
n = readudp(d, pkt, len, tleft); ptr = NULL;
if (n <= (4 * 4)) n = readudp(d, &ptr, (void **)&reply, tleft);
return -1; if (n <= (4 * 4)) {
free(ptr);
reply = (struct rpc_reply *)pkt; return (-1);
}
x = ntohl(reply->rp_xid); x = ntohl(reply->rp_xid);
if (x != rpc_xid) { if (x != rpc_xid) {
@ -251,7 +243,8 @@ recvrpc(struct iodesc *d, void *pkt, size_t len, time_t tleft)
if (debug) if (debug)
printf("recvrpc: rp_xid %d != xid %d\n", x, rpc_xid); printf("recvrpc: rp_xid %d != xid %d\n", x, rpc_xid);
#endif #endif
return -1; free(ptr);
return (-1);
} }
x = ntohl(reply->rp_direction); x = ntohl(reply->rp_direction);
@ -260,16 +253,20 @@ recvrpc(struct iodesc *d, void *pkt, size_t len, time_t tleft)
if (debug) if (debug)
printf("recvrpc: rp_direction %d != REPLY\n", x); printf("recvrpc: rp_direction %d != REPLY\n", x);
#endif #endif
return -1; free(ptr);
return (-1);
} }
x = ntohl(reply->rp_astatus); x = ntohl(reply->rp_astatus);
if (x != RPC_MSGACCEPTED) { if (x != RPC_MSGACCEPTED) {
errno = ntohl(reply->rp_u.rpu_errno); errno = ntohl(reply->rp_u.rpu_errno);
printf("recvrpc: reject, astat=%d, errno=%d\n", x, 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 data count (thus indicating success) */
return (n); return (n);
} }
@ -387,11 +384,7 @@ rpc_getport(struct iodesc *d, n_long prog, n_long vers)
n_long h[RPC_HEADER_WORDS]; n_long h[RPC_HEADER_WORDS];
struct args d; struct args d;
} sdata; } sdata;
struct { void *pkt;
n_long h[RPC_HEADER_WORDS];
struct res d;
n_long pad;
} rdata;
ssize_t cc; ssize_t cc;
int port; int port;
@ -416,16 +409,18 @@ rpc_getport(struct iodesc *d, n_long prog, n_long vers)
args->vers = htonl(vers); args->vers = htonl(vers);
args->proto = htonl(IPPROTO_UDP); args->proto = htonl(IPPROTO_UDP);
args->port = 0; args->port = 0;
res = &rdata.d; pkt = NULL;
cc = rpc_call(d, PMAPPROG, PMAPVERS, PMAPPROC_GETPORT, cc = rpc_call(d, PMAPPROG, PMAPVERS, PMAPPROC_GETPORT,
args, sizeof(*args), res, sizeof(*res)); args, sizeof(*args), (void **)&res, &pkt);
if (cc < sizeof(*res)) { if (cc < sizeof(*res)) {
printf("getport: %s", strerror(errno)); printf("getport: %s", strerror(errno));
errno = EBADRPC; errno = EBADRPC;
free(pkt);
return (-1); return (-1);
} }
port = (int)ntohl(res->port); port = (int)ntohl(res->port);
free(pkt);
rpc_pmap_putcache(d->destip, prog, vers, port); rpc_pmap_putcache(d->destip, prog, vers, port);

View File

@ -48,7 +48,7 @@
/* RPC functions: */ /* RPC functions: */
ssize_t rpc_call(struct iodesc *, n_long, n_long, n_long, 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 *); void rpc_fromaddr(void *, struct in_addr *, u_short *);
int rpc_pmap_getcache(struct in_addr, u_int, u_int); int rpc_pmap_getcache(struct in_addr, u_int, u_int);
void rpc_pmap_putcache(struct in_addr, u_int, u_int, int); void rpc_pmap_putcache(struct in_addr, u_int, u_int, int);

View File

@ -73,8 +73,8 @@ static int tftp_stat(struct open_file *f, struct stat *sb);
static ssize_t sendrecv_tftp(struct tftp_handle *h, static ssize_t sendrecv_tftp(struct tftp_handle *h,
ssize_t (*sproc)(struct iodesc *, void *, size_t), ssize_t (*sproc)(struct iodesc *, void *, size_t),
void *sbuf, size_t ssize, void *sbuf, size_t ssize,
ssize_t (*rproc)(struct tftp_handle *h, void *, ssize_t, time_t, unsigned short *), ssize_t (*rproc)(struct tftp_handle *h, void **, void **, time_t, unsigned short *),
void *rbuf, size_t rsize, unsigned short *rtype); void **, void **, unsigned short *rtype);
struct fs_ops tftp_fsops = { struct fs_ops tftp_fsops = {
"tftp", "tftp",
@ -114,11 +114,8 @@ struct tftp_handle {
char *path; /* saved for re-requests */ char *path; /* saved for re-requests */
unsigned int tftp_blksize; unsigned int tftp_blksize;
unsigned long tftp_tsize; unsigned long tftp_tsize;
struct { void *pkt;
u_char header[HEADER_SIZE]; struct tftphdr *tftp_hdr;
struct tftphdr t;
u_char space[TFTP_MAX_BLKSIZE];
} __packed __aligned(4) lastdata;
}; };
#define TFTP_MAX_ERRCODE EOPTNEG #define TFTP_MAX_ERRCODE EOPTNEG
@ -181,20 +178,23 @@ tftp_sendack(struct tftp_handle *h)
} }
static ssize_t static ssize_t
recvtftp(struct tftp_handle *h, void *pkt, ssize_t len, time_t tleft, recvtftp(struct tftp_handle *h, void **pkt, void **payload, time_t tleft,
unsigned short *rtype) unsigned short *rtype)
{ {
struct iodesc *d = h->iodesc; struct iodesc *d = h->iodesc;
struct tftphdr *t; struct tftphdr *t;
void *ptr = NULL;
ssize_t len;
errno = 0; 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); return (-1);
}
t = (struct tftphdr *) pkt;
*rtype = ntohs(t->th_opcode); *rtype = ntohs(t->th_opcode);
switch (ntohs(t->th_opcode)) { switch (ntohs(t->th_opcode)) {
case DATA: { case DATA: {
@ -204,6 +204,7 @@ recvtftp(struct tftp_handle *h, void *pkt, ssize_t len, time_t tleft,
/* /*
* Expected block? * Expected block?
*/ */
free(ptr);
return (-1); return (-1);
} }
if (d->xid == 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. * First data packet from new port.
*/ */
struct udphdr *uh; struct udphdr *uh;
uh = (struct udphdr *) pkt - 1; uh = (struct udphdr *) t - 1;
d->destport = uh->uh_sport; d->destport = uh->uh_sport;
} /* else check uh_sport has not changed??? */ } /* else check uh_sport has not changed??? */
got = len - (t->th_data - (char *) t); got = len - (t->th_data - (char *)t);
return got; *pkt = ptr;
*payload = t;
return (got);
} }
case ERROR: case ERROR:
if ((unsigned) ntohs(t->th_code) > TFTP_MAX_ERRCODE) { 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 #endif
errno = tftperrors[ntohs(t->th_code)]; errno = tftperrors[ntohs(t->th_code)];
} }
free(ptr);
return (-1); return (-1);
case OACK: { case OACK: {
struct udphdr *uh; struct udphdr *uh;
@ -237,6 +241,7 @@ recvtftp(struct tftp_handle *h, void *pkt, ssize_t len, time_t tleft,
* Drop the pkt. * Drop the pkt.
*/ */
if (d->xid != 1) { if (d->xid != 1) {
free(ptr);
return (-1); 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 * Remember which port this OACK came from, because we need
* to send the ACK or errors back to it. * to send the ACK or errors back to it.
*/ */
uh = (struct udphdr *) pkt - 1; uh = (struct udphdr *) t - 1;
d->destport = uh->uh_sport; d->destport = uh->uh_sport;
/* Parse options ACK-ed by the server. */ /* 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) { if (tftp_parse_oack(h, t->th_u.tu_stuff, tftp_oack_len) != 0) {
tftp_senderr(h, EOPTNEG, "Malformed OACK"); tftp_senderr(h, EOPTNEG, "Malformed OACK");
errno = EIO; errno = EIO;
free(ptr);
return (-1); return (-1);
} }
*pkt = ptr;
*payload = t;
return (0); return (0);
} }
default: default:
#ifdef TFTP_DEBUG #ifdef TFTP_DEBUG
printf("tftp type %d not handled\n", ntohs(t->th_opcode)); printf("tftp type %d not handled\n", ntohs(t->th_opcode));
#endif #endif
free(ptr);
return (-1); return (-1);
} }
} }
@ -276,6 +285,7 @@ tftp_makereq(struct tftp_handle *h)
char *wtail; char *wtail;
int l; int l;
ssize_t res; ssize_t res;
void *pkt;
struct tftphdr *t; struct tftphdr *t;
char *tftp_blksize = NULL; char *tftp_blksize = NULL;
int blksize_l; int blksize_l;
@ -314,8 +324,6 @@ tftp_makereq(struct tftp_handle *h)
bcopy("0", wtail, 2); bcopy("0", wtail, 2);
wtail += 2; wtail += 2;
t = &h->lastdata.t;
/* h->iodesc->myport = htons(--tftpport); */ /* h->iodesc->myport = htons(--tftpport); */
h->iodesc->myport = htons(tftpport + (getsecs() & 0x3ff)); h->iodesc->myport = htons(tftpport + (getsecs() & 0x3ff));
h->iodesc->destport = htons(IPPORT_TFTP); h->iodesc->destport = htons(IPPORT_TFTP);
@ -325,8 +333,17 @@ tftp_makereq(struct tftp_handle *h)
h->islastblock = 0; h->islastblock = 0;
h->validsize = 0; h->validsize = 0;
pkt = NULL;
res = sendrecv_tftp(h, &sendudp, &wbuf.t, wtail - (char *) &wbuf.t, 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) if (rtype == OACK)
return (tftp_getnextblock(h)); return (tftp_getnextblock(h));
@ -362,6 +379,7 @@ tftp_getnextblock(struct tftp_handle *h)
} __packed __aligned(4) wbuf; } __packed __aligned(4) wbuf;
char *wtail; char *wtail;
int res; int res;
void *pkt;
struct tftphdr *t; struct tftphdr *t;
unsigned short rtype = 0; unsigned short rtype = 0;
wbuf.t.th_opcode = htons((u_short) ACK); 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); wbuf.t.th_block = htons((u_short) h->currblock);
wtail += 2; wtail += 2;
t = &h->lastdata.t;
h->iodesc->xid = h->currblock + 1; /* expected block */ h->iodesc->xid = h->currblock + 1; /* expected block */
pkt = NULL;
res = sendrecv_tftp(h, &sendudp, &wbuf.t, wtail - (char *) &wbuf.t, 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); return (errno);
}
free(h->pkt);
h->pkt = pkt;
h->tftp_hdr = t;
h->currblock++; h->currblock++;
h->validsize = res; h->validsize = res;
if (res < h->tftp_blksize) if (res < h->tftp_blksize)
@ -405,14 +427,8 @@ tftp_open(const char *path, struct open_file *f)
if (netproto != NET_TFTP) if (netproto != NET_TFTP)
return (EINVAL); return (EINVAL);
if (strcmp(f->f_dev->dv_name, "net") != 0) { if (f->f_dev->dv_type != DEVT_NET)
#ifdef __i386__
if (strcmp(f->f_dev->dv_name, "pxe") != 0)
return (EINVAL);
#else
return (EINVAL); return (EINVAL);
#endif
}
if (is_open) if (is_open)
return (EBUSY); return (EBUSY);
@ -507,7 +523,7 @@ tftp_read(struct open_file *f, void *addr, size_t size,
return (EINVAL); return (EINVAL);
} }
count = (size < inbuffer ? size : inbuffer); count = (size < inbuffer ? size : inbuffer);
bcopy(tftpfile->lastdata.t.th_data + offinblock, bcopy(tftpfile->tftp_hdr->th_data + offinblock,
addr, count); addr, count);
addr = (char *)addr + count; addr = (char *)addr + count;
@ -540,6 +556,7 @@ tftp_close(struct open_file *f)
if (tftpfile) { if (tftpfile) {
free(tftpfile->path); free(tftpfile->path);
free(tftpfile->pkt);
free(tftpfile); free(tftpfile);
} }
is_open = 0; is_open = 0;
@ -591,8 +608,9 @@ static ssize_t
sendrecv_tftp(struct tftp_handle *h, sendrecv_tftp(struct tftp_handle *h,
ssize_t (*sproc)(struct iodesc *, void *, size_t), ssize_t (*sproc)(struct iodesc *, void *, size_t),
void *sbuf, size_t ssize, void *sbuf, size_t ssize,
ssize_t (*rproc)(struct tftp_handle *, void *, ssize_t, time_t, unsigned short *), ssize_t (*rproc)(struct tftp_handle *, void **, void **, time_t,
void *rbuf, size_t rsize, unsigned short *rtype) unsigned short *),
void **pkt, void **payload, unsigned short *rtype)
{ {
struct iodesc *d = h->iodesc; struct iodesc *d = h->iodesc;
ssize_t cc; ssize_t cc;
@ -624,7 +642,7 @@ sendrecv_tftp(struct tftp_handle *h,
recvnext: recvnext:
/* Try to get a packet and process it. */ /* 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. */ /* Return on data, EOF or real error. */
if (cc != -1 || errno != 0) if (cc != -1 || errno != 0)
return (cc); return (cc);

View File

@ -59,10 +59,7 @@ __FBSDID("$FreeBSD$");
/* Caller must leave room for ethernet, ip and udp headers in front!! */ /* Caller must leave room for ethernet, ip and udp headers in front!! */
ssize_t ssize_t
sendudp(d, pkt, len) sendudp(struct iodesc *d, void *pkt, size_t len)
struct iodesc *d;
void *pkt;
size_t len;
{ {
ssize_t cc; ssize_t cc;
struct ip *ip; struct ip *ip;
@ -131,32 +128,29 @@ sendudp(d, pkt, len)
/* /*
* Receive a UDP packet and validate it is for us. * Receive a UDP packet and validate it is for us.
* Caller leaves room for the headers (Ether, IP, UDP)
*/ */
ssize_t ssize_t
readudp(d, pkt, len, tleft) readudp(struct iodesc *d, void **pkt, void **payload, time_t tleft)
struct iodesc *d;
void *pkt;
size_t len;
time_t tleft;
{ {
ssize_t n; ssize_t n;
size_t hlen; size_t hlen;
struct ip *ip; struct ip *ip;
struct udphdr *uh; struct udphdr *uh;
u_int16_t etype; /* host order */ uint16_t etype; /* host order */
void *ptr;
#ifdef NET_DEBUG #ifdef NET_DEBUG
if (debug) if (debug)
printf("readudp: called\n"); printf("readudp: called\n");
#endif #endif
uh = (struct udphdr *)pkt - 1; ip = NULL;
ip = (struct ip *)uh - 1; ptr = NULL;
n = readether(d, &ptr, (void **)&ip, tleft, &etype);
n = readether(d, ip, len + sizeof(*ip) + sizeof(*uh), tleft, &etype); if (n == -1 || n < sizeof(*ip) + sizeof(*uh)) {
if (n == -1 || n < sizeof(*ip) + sizeof(*uh)) free(ptr);
return -1; return (-1);
}
/* Ethernet address checks now in readether() */ /* Ethernet address checks now in readether() */
@ -167,7 +161,8 @@ readudp(d, pkt, len, tleft)
/* Send ARP reply */ /* Send ARP reply */
arp_reply(d, ah); arp_reply(d, ah);
} }
return -1; free(ptr);
return (-1);
} }
if (etype != ETHERTYPE_IP) { if (etype != ETHERTYPE_IP) {
@ -175,7 +170,8 @@ readudp(d, pkt, len, tleft)
if (debug) if (debug)
printf("readudp: not IP. ether_type=%x\n", etype); printf("readudp: not IP. ether_type=%x\n", etype);
#endif #endif
return -1; free(ptr);
return (-1);
} }
/* Check ip header */ /* Check ip header */
@ -185,7 +181,8 @@ readudp(d, pkt, len, tleft)
if (debug) if (debug)
printf("readudp: IP version or not UDP. ip_v=%d ip_p=%d\n", ip->ip_v, ip->ip_p); printf("readudp: IP version or not UDP. ip_v=%d ip_p=%d\n", ip->ip_v, ip->ip_p);
#endif #endif
return -1; free(ptr);
return (-1);
} }
hlen = ip->ip_hl << 2; hlen = ip->ip_hl << 2;
@ -195,7 +192,8 @@ readudp(d, pkt, len, tleft)
if (debug) if (debug)
printf("readudp: short hdr or bad cksum.\n"); printf("readudp: short hdr or bad cksum.\n");
#endif #endif
return -1; free(ptr);
return (-1);
} }
if (n < ntohs(ip->ip_len)) { if (n < ntohs(ip->ip_len)) {
#ifdef NET_DEBUG #ifdef NET_DEBUG
@ -203,7 +201,8 @@ readudp(d, pkt, len, tleft)
printf("readudp: bad length %d < %d.\n", printf("readudp: bad length %d < %d.\n",
(int)n, ntohs(ip->ip_len)); (int)n, ntohs(ip->ip_len));
#endif #endif
return -1; free(ptr);
return (-1);
} }
if (d->myip.s_addr && ip->ip_dst.s_addr != d->myip.s_addr) { if (d->myip.s_addr && ip->ip_dst.s_addr != d->myip.s_addr) {
#ifdef NET_DEBUG #ifdef NET_DEBUG
@ -212,12 +211,14 @@ readudp(d, pkt, len, tleft)
printf("%s\n", inet_ntoa(ip->ip_dst)); printf("%s\n", inet_ntoa(ip->ip_dst));
} }
#endif #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 there were ip options, make them go away */
if (hlen != sizeof(*ip)) { 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)); ip->ip_len = htons(sizeof(*ip));
n -= hlen - sizeof(*ip); n -= hlen - sizeof(*ip);
} }
@ -227,7 +228,8 @@ readudp(d, pkt, len, tleft)
printf("readudp: bad dport %d != %d\n", printf("readudp: bad dport %d != %d\n",
d->myport, ntohs(uh->uh_dport)); d->myport, ntohs(uh->uh_dport));
#endif #endif
return -1; free(ptr);
return (-1);
} }
#ifndef UDP_NO_CKSUM #ifndef UDP_NO_CKSUM
@ -238,7 +240,8 @@ readudp(d, pkt, len, tleft)
n = ntohs(uh->uh_ulen) + sizeof(*ip); n = ntohs(uh->uh_ulen) + sizeof(*ip);
if (n > RECV_SIZE - ETHER_SIZE) { if (n > RECV_SIZE - ETHER_SIZE) {
printf("readudp: huge packet, udp len %d\n", (int)n); printf("readudp: huge packet, udp len %d\n", (int)n);
return -1; free(ptr);
return (-1);
} }
/* Check checksum (must save and restore ip header) */ /* Check checksum (must save and restore ip header) */
@ -251,8 +254,8 @@ readudp(d, pkt, len, tleft)
if (debug) if (debug)
printf("readudp: bad cksum\n"); printf("readudp: bad cksum\n");
#endif #endif
*ip = tip; free(ptr);
return -1; return (-1);
} }
*ip = tip; *ip = tip;
} }
@ -263,10 +266,13 @@ readudp(d, pkt, len, tleft)
printf("readudp: bad udp len %d < %d\n", printf("readudp: bad udp len %d < %d\n",
ntohs(uh->uh_ulen), (int)sizeof(*uh)); ntohs(uh->uh_ulen), (int)sizeof(*uh));
#endif #endif
return -1; free(ptr);
return (-1);
} }
n = (n > (ntohs(uh->uh_ulen) - sizeof(*uh))) ? n = (n > (ntohs(uh->uh_ulen) - sizeof(*uh))) ?
ntohs(uh->uh_ulen) - sizeof(*uh) : n; ntohs(uh->uh_ulen) - sizeof(*uh) : n;
*pkt = ptr;
*payload = (void *)((uintptr_t)uh + sizeof(*uh));
return (n); return (n);
} }

View File

@ -58,6 +58,7 @@ __FBSDID("$FreeBSD$");
#include <netinet/in_systm.h> #include <netinet/in_systm.h>
#include <stand.h> #include <stand.h>
#include <stddef.h>
#include <string.h> #include <string.h>
#include <net.h> #include <net.h>
#include <netif.h> #include <netif.h>
@ -79,7 +80,7 @@ static int net_init(void);
static int net_open(struct open_file *, ...); static int net_open(struct open_file *, ...);
static int net_close(struct open_file *); static int net_close(struct open_file *);
static void net_cleanup(void); 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_print(int);
static int net_getparams(int sock); static int net_getparams(int sock);
@ -216,7 +217,8 @@ net_cleanup(void)
} }
static int static int
net_strategy() net_strategy(void *devdata, int rw, daddr_t blk, size_t size, char *buf,
size_t *rsize)
{ {
return (EIO); return (EIO);
@ -246,6 +248,8 @@ net_getparams(int sock)
{ {
char buf[MAXHOSTNAMELEN]; char buf[MAXHOSTNAMELEN];
n_long rootaddr, smask; n_long rootaddr, smask;
struct iodesc *d = socktodesc(sock);
extern struct in_addr servip;
#ifdef SUPPORT_BOOTP #ifdef SUPPORT_BOOTP
/* /*
@ -254,8 +258,26 @@ net_getparams(int sock)
* be initialized. If any remain uninitialized, we will * be initialized. If any remain uninitialized, we will
* use RARP and RPC/bootparam (the Sun way) to get them. * use RARP and RPC/bootparam (the Sun way) to get them.
*/ */
if (try_bootp) if (try_bootp) {
bootp(sock, BOOTP_NONE); 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) if (myip.s_addr != 0)
goto exit; goto exit;
#ifdef NETIF_DEBUG #ifdef NETIF_DEBUG

View File

@ -29,6 +29,7 @@
__FBSDID("$FreeBSD$"); __FBSDID("$FreeBSD$");
#include <sys/param.h> #include <sys/param.h>
#include <net/ethernet.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <netinet/in_systm.h> #include <netinet/in_systm.h>
@ -36,19 +37,17 @@ __FBSDID("$FreeBSD$");
#include <net.h> #include <net.h>
#include <netif.h> #include <netif.h>
#include <dev_net.c>
#include <efi.h> #include <efi.h>
#include <efilib.h> #include <efilib.h>
static EFI_GUID sn_guid = EFI_SIMPLE_NETWORK_PROTOCOL; static EFI_GUID sn_guid = EFI_SIMPLE_NETWORK_PROTOCOL;
static void efinet_end(struct netif *); 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 void efinet_init(struct iodesc *, void *);
static int efinet_match(struct netif *, void *); static int efinet_match(struct netif *, void *);
static int efinet_probe(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 = { struct netif_driver efinetif = {
.netif_bname = "efinet", .netif_bname = "efinet",
@ -113,7 +112,7 @@ efinet_probe(struct netif *nif, void *machdep_hint)
return (0); return (0);
} }
static int static ssize_t
efinet_put(struct iodesc *desc, void *pkt, size_t len) efinet_put(struct iodesc *desc, void *pkt, size_t len)
{ {
struct netif *nif = desc->io_netif; struct netif *nif = desc->io_netif;
@ -125,14 +124,14 @@ efinet_put(struct iodesc *desc, void *pkt, size_t len)
if (net == NULL) if (net == NULL)
return (-1); 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) if (status != EFI_SUCCESS)
return (-1); return (-1);
/* Wait for the buffer to be transmitted */ /* Wait for the buffer to be transmitted */
do { do {
buf = NULL; /* XXX Is this needed? */ 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 * XXX EFI1.1 and the E1000 card returns a different
* address than we gave. Sigh. * 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); return ((status == EFI_SUCCESS) ? len : -1);
} }
static int static ssize_t
efinet_get(struct iodesc *desc, void *pkt, size_t len, time_t timeout) efinet_get(struct iodesc *desc, void **pkt, time_t timeout)
{ {
struct netif *nif = desc->io_netif; struct netif *nif = desc->io_netif;
EFI_SIMPLE_NETWORK *net; EFI_SIMPLE_NETWORK *net;
EFI_STATUS status; EFI_STATUS status;
UINTN bufsz; UINTN bufsz;
time_t t; time_t t;
char buf[2048]; char *buf, *ptr;
ssize_t ret = -1;
net = nif->nif_devdata; net = nif->nif_devdata;
if (net == NULL) if (net == NULL)
return (0); return (ret);
t = time(0); bufsz = net->Mode->MaxPacketSize + ETHER_HDR_LEN + ETHER_CRC_LEN;
while ((time(0) - t) < timeout) { buf = malloc(bufsz + ETHER_ALIGN);
bufsz = sizeof(buf); if (buf == NULL)
status = net->Receive(net, 0, &bufsz, buf, 0, 0, 0); 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) { if (status == EFI_SUCCESS) {
/* *pkt = buf;
* XXX EFI1.1 and the E1000 card trash our ret = (ssize_t)bufsz;
* workspace if we do not do this silly copy. break;
* 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);
} }
if (status != EFI_NOT_READY) if (status != EFI_NOT_READY)
return (0); break;
} }
return (0); if (ret == -1)
free(buf);
return (ret);
} }
static void static void
@ -205,8 +205,8 @@ efinet_init(struct iodesc *desc, void *machdep_hint)
if (net->Mode->State == EfiSimpleNetworkStopped) { if (net->Mode->State == EfiSimpleNetworkStopped) {
status = net->Start(net); status = net->Start(net);
if (status != EFI_SUCCESS) { if (status != EFI_SUCCESS) {
printf("net%d: cannot start interface (status=%ld)\n", printf("net%d: cannot start interface (status=%lu)\n",
nif->nif_unit, (long)status); nif->nif_unit, EFI_ERROR_CODE(status));
return; return;
} }
} }
@ -214,8 +214,8 @@ efinet_init(struct iodesc *desc, void *machdep_hint)
if (net->Mode->State != EfiSimpleNetworkInitialized) { if (net->Mode->State != EfiSimpleNetworkInitialized) {
status = net->Initialize(net, 0, 0); status = net->Initialize(net, 0, 0);
if (status != EFI_SUCCESS) { if (status != EFI_SUCCESS) {
printf("net%d: cannot init. interface (status=%ld)\n", printf("net%d: cannot init. interface (status=%lu)\n",
nif->nif_unit, (long)status); nif->nif_unit, EFI_ERROR_CODE(status));
return; return;
} }
} }
@ -224,10 +224,10 @@ efinet_init(struct iodesc *desc, void *machdep_hint)
UINT32 mask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST | UINT32 mask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |
EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST; 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) { if (status != EFI_SUCCESS) {
printf("net%d: cannot set rx. filters (status=%ld)\n", printf("net%d: cannot set rx. filters (status=%lu)\n",
nif->nif_unit, (long)status); nif->nif_unit, EFI_ERROR_CODE(status));
return; return;
} }
} }
@ -258,9 +258,9 @@ struct devsw efinet_dev = {
.dv_name = "net", .dv_name = "net",
.dv_type = DEVT_NET, .dv_type = DEVT_NET,
.dv_init = efinet_dev_init, .dv_init = efinet_dev_init,
.dv_strategy = net_strategy, .dv_strategy = NULL, /* Will be set in efinet_dev_init */
.dv_open = net_open, .dv_open = NULL, /* Will be set in efinet_dev_init */
.dv_close = net_close, .dv_close = NULL, /* Will be set in efinet_dev_init */
.dv_ioctl = noioctl, .dv_ioctl = noioctl,
.dv_print = efinet_dev_print, .dv_print = efinet_dev_print,
.dv_cleanup = NULL .dv_cleanup = NULL
@ -277,13 +277,14 @@ efinet_dev_init()
EFI_STATUS status; EFI_STATUS status;
UINTN sz; UINTN sz;
int err, i, nifs; int err, i, nifs;
extern struct devsw netdev;
sz = 0; sz = 0;
handles = NULL; 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) { if (status == EFI_BUFFER_TOO_SMALL) {
handles = (EFI_HANDLE *)malloc(sz); handles = (EFI_HANDLE *)malloc(sz);
status = BS->LocateHandle(ByProtocol, &sn_guid, 0, &sz, status = BS->LocateHandle(ByProtocol, &sn_guid, NULL, &sz,
handles); handles);
if (EFI_ERROR(status)) if (EFI_ERROR(status))
free(handles); free(handles);
@ -313,10 +314,11 @@ efinet_dev_init()
* pull packets off the network leading to lost packets. * pull packets off the network leading to lost packets.
*/ */
status = BS->OpenProtocol(handles[i], &sn_guid, (void **)&net, 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) { if (status != EFI_SUCCESS) {
printf("Unable to open network interface %d for " 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]; handles2[nifs] = handles[i];
@ -351,6 +353,11 @@ efinet_dev_init()
dif->dif_stats = &stats[i]; dif->dif_stats = &stats[i];
dif->dif_private = handles2[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: done:
free(handles2); free(handles2);
return (err); return (err);

View File

@ -230,5 +230,5 @@ time(time_t *tloc)
time_t time_t
getsecs(void) getsecs(void)
{ {
return time(0); return time(NULL);
} }

View File

@ -9,6 +9,7 @@ MK_SSP= no
PROG= loader.sym PROG= loader.sym
INTERNALPROG= INTERNALPROG=
WARNS?= 3 WARNS?= 3
LOADER_NET_SUPPORT?= yes
# architecture-specific loader code # architecture-specific loader code
SRCS= autoload.c \ SRCS= autoload.c \
@ -35,6 +36,10 @@ CWARNFLAGS.zfs.c+= -Wno-array-bounds
CWARNFLAGS.zfs.c+= -Wno-missing-prototypes CWARNFLAGS.zfs.c+= -Wno-missing-prototypes
.endif .endif
.if defined(LOADER_NET_SUPPORT)
CFLAGS+= -I${.CURDIR}/../../../../lib/libstand
.endif
.if ${COMPILER_TYPE} == "gcc" && ${COMPILER_VERSION} > 40201 .if ${COMPILER_TYPE} == "gcc" && ${COMPILER_VERSION} > 40201
CWARNFLAGS.self_reloc.c+= -Wno-error=maybe-uninitialized CWARNFLAGS.self_reloc.c+= -Wno-error=maybe-uninitialized
.endif .endif

View File

@ -30,11 +30,15 @@
__FBSDID("$FreeBSD$"); __FBSDID("$FreeBSD$");
#include <stand.h> #include <stand.h>
#include <stddef.h>
#include <string.h> #include <string.h>
#include <stdarg.h> #include <stdarg.h>
#include <sys/param.h>
#include <net/ethernet.h>
#include <netinet/in_systm.h> #include <netinet/in_systm.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/udp.h> #include <netinet/udp.h>
#include <net.h> #include <net.h>
@ -53,17 +57,15 @@ __FBSDID("$FreeBSD$");
* the PXE BIOS, and the data buffer is used to receive data from the PXE BIOS. * the PXE BIOS, and the data buffer is used to receive data from the PXE BIOS.
*/ */
#define PXE_BUFFER_SIZE 0x2000 #define PXE_BUFFER_SIZE 0x2000
#define PXE_TFTP_BUFFER_SIZE 512
static char scratch_buffer[PXE_BUFFER_SIZE]; static char scratch_buffer[PXE_BUFFER_SIZE];
static char data_buffer[PXE_BUFFER_SIZE]; static char data_buffer[PXE_BUFFER_SIZE];
static pxenv_t *pxenv_p = NULL; /* PXENV+ */ static pxenv_t *pxenv_p = NULL; /* PXENV+ */
static pxe_t *pxe_p = NULL; /* !PXE */ static pxe_t *pxe_p = NULL; /* !PXE */
static BOOTPLAYER bootplayer; /* PXE Cached information. */
#ifdef PXE_DEBUG
static int pxe_debug = 0; static int pxe_debug = 0;
static int pxe_sock = -1; #endif
static int pxe_opens = 0;
void pxe_enable(void *pxeinfo); void pxe_enable(void *pxeinfo);
static void (*pxe_call)(int func); static void (*pxe_call)(int func);
@ -71,25 +73,17 @@ static void pxenv_call(int func);
static void bangpxe_call(int func); static void bangpxe_call(int func);
static int pxe_init(void); 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 int pxe_print(int verbose);
static void pxe_cleanup(void); static void pxe_cleanup(void);
static void pxe_setnfshandle(char *rootpath);
static void pxe_perror(int error); static void pxe_perror(int error);
static int pxe_netif_match(struct netif *nif, void *machdep_hint); static int pxe_netif_match(struct netif *nif, void *machdep_hint);
static int pxe_netif_probe(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 void pxe_netif_init(struct iodesc *desc, void *machdep_hint);
static int pxe_netif_get(struct iodesc *desc, void *pkt, size_t len, static ssize_t pxe_netif_get(struct iodesc *, void **, time_t);
time_t timeout); static ssize_t pxe_netif_put(struct iodesc *desc, void *pkt, size_t len);
static int pxe_netif_put(struct iodesc *desc, void *pkt, size_t len);
static void pxe_netif_end(struct netif *nif); 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 struct netif_stats pxe_st[];
extern u_int16_t __bangpxeseg; extern u_int16_t __bangpxeseg;
extern u_int16_t __bangpxeoff; extern u_int16_t __bangpxeoff;
@ -97,25 +91,24 @@ extern void __bangpxeentry(void);
extern u_int16_t __pxenvseg; extern u_int16_t __pxenvseg;
extern u_int16_t __pxenvoff; extern u_int16_t __pxenvoff;
extern void __pxenventry(void); extern void __pxenventry(void);
extern struct in_addr servip;
struct netif_dif pxe_ifs[] = { struct netif_dif pxe_ifs[] = {
/* dif_unit dif_nsel dif_stats dif_private */ /* dif_unit dif_nsel dif_stats dif_private */
{0, 1, &pxe_st[0], 0} {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 = { struct netif_driver pxenetif = {
"pxenet", .netif_bname = "pxenet",
pxe_netif_match, .netif_match = pxe_netif_match,
pxe_netif_probe, .netif_probe = pxe_netif_probe,
pxe_netif_init, .netif_init = pxe_netif_init,
pxe_netif_get, .netif_get = pxe_netif_get,
pxe_netif_put, .netif_put = pxe_netif_put,
pxe_netif_end, .netif_end = pxe_netif_end,
pxe_ifs, .netif_ifs = pxe_ifs,
NENTS(pxe_ifs) .netif_nifs = nitems(pxe_ifs)
}; };
struct netif_driver *netif_drivers[] = { struct netif_driver *netif_drivers[] = {
@ -124,15 +117,15 @@ struct netif_driver *netif_drivers[] = {
}; };
struct devsw pxedisk = { struct devsw pxedisk = {
"pxe", .dv_name = "net",
DEVT_NET, .dv_type = DEVT_NET,
pxe_init, .dv_init = pxe_init,
pxe_strategy, .dv_strategy = NULL, /* Will be set in pxe_init */
pxe_open, .dv_open = NULL, /* Will be set in pxe_init */
pxe_close, .dv_close = NULL, /* Will be set in pxe_init */
noioctl, .dv_ioctl = noioctl,
pxe_print, .dv_print = pxe_print,
pxe_cleanup .dv_cleanup = pxe_cleanup
}; };
/* /*
@ -160,6 +153,7 @@ pxe_init(void)
int counter; int counter;
uint8_t checksum; uint8_t checksum;
uint8_t *checkptr; uint8_t *checkptr;
extern struct devsw netdev;
if (pxenv_p == NULL) if (pxenv_p == NULL)
return (0); return (0);
@ -215,7 +209,11 @@ pxe_init(void)
break; 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 ", printf("\nPXE version %d.%d, real mode entry point ",
(uint8_t) (pxenv_p->Version >> 8), (uint8_t) (pxenv_p->Version >> 8),
(uint8_t) (pxenv_p->Version & 0xFF)); (uint8_t) (pxenv_p->Version & 0xFF));
@ -236,190 +234,29 @@ pxe_init(void)
pxe_p = NULL; pxe_p = NULL;
return (0); return (0);
} }
bcopy(PTOV((gci_p->Buffer.segment << 4) + gci_p->Buffer.offset), free(bootp_response);
&bootplayer, gci_p->BufferSize); 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); 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 static int
pxe_print(int verbose) pxe_print(int verbose)
{ {
char line[255];
if (pxe_call == NULL) if (pxe_call == NULL)
return (0); return (0);
printf("%s devices:", pxedisk.dv_name); printf("%s devices:", pxedisk.dv_name);
if (pager_output("\n") != 0) if (pager_output("\n") != 0)
return (1); return (1);
printf(" %s0:", pxedisk.dv_name);
if (verbose) { if (verbose) {
snprintf(line, sizeof(line), " pxe0: %s:%s\n", printf(" %s:%s", inet_ntoa(rootip), rootpath);
inet_ntoa(rootip), rootpath);
} else {
snprintf(line, sizeof(line), " pxe0:\n");
} }
return (pager_output(line)); return (pager_output("\n"));
} }
static void static void
@ -458,66 +295,6 @@ pxe_perror(int err)
return; 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 void
pxenv_call(int func) pxenv_call(int func)
{ {
@ -568,121 +345,196 @@ bangpxe_call(int func)
static int static int
pxe_netif_match(struct netif *nif, void *machdep_hint) pxe_netif_match(struct netif *nif, void *machdep_hint)
{ {
return 1; return (1);
} }
static int static int
pxe_netif_probe(struct netif *nif, void *machdep_hint) 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) if (pxe_call == NULL)
return -1; return (-1);
bzero(udpopen_p, sizeof(*udpopen_p)); return (0);
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;
} }
static void static void
pxe_netif_end(struct netif *nif) pxe_netif_end(struct netif *nif)
{ {
t_PXENV_UDP_CLOSE *udpclose_p = (t_PXENV_UDP_CLOSE *)scratch_buffer; t_PXENV_UNDI_CLOSE *undi_close_p;
bzero(udpclose_p, sizeof(*udpclose_p));
pxe_call(PXENV_UDP_CLOSE); undi_close_p = (t_PXENV_UNDI_CLOSE *)scratch_buffer;
if (udpclose_p->status != 0) bzero(undi_close_p, sizeof(*undi_close_p));
printf("pxe_end failed %x\n", udpclose_p->status); pxe_call(PXENV_UNDI_CLOSE);
if (undi_close_p->Status != 0)
printf("undi close failed: %x\n", undi_close_p->Status);
} }
static void static void
pxe_netif_init(struct iodesc *desc, void *machdep_hint) pxe_netif_init(struct iodesc *desc, void *machdep_hint)
{ {
int i; t_PXENV_UNDI_GET_INFORMATION *undi_info_p;
for (i = 0; i < 6; ++i) t_PXENV_UNDI_OPEN *undi_open_p;
desc->myea[i] = bootplayer.CAddr[i]; uint8_t *mac;
desc->xid = bootplayer.ident; 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 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) 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 trans_p = (t_PXENV_UNDI_TRANSMIT *)scratch_buffer;
sendudp(struct iodesc *h, void *pkt, size_t len) bzero(trans_p, sizeof(*trans_p));
{ tbd_p = (t_PXENV_UNDI_TBD *)(scratch_buffer + sizeof(*trans_p));
t_PXENV_UDP_WRITE *udpwrite_p = (t_PXENV_UDP_WRITE *)scratch_buffer; bzero(tbd_p, sizeof(*tbd_p));
bzero(udpwrite_p, sizeof(*udpwrite_p));
udpwrite_p->ip = h->destip.s_addr; data = scratch_buffer + sizeof(*trans_p) + sizeof(*tbd_p);
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);
if (netmask == 0 || SAMENET(myip, h->destip, netmask)) trans_p->TBD.segment = VTOPSEG(tbd_p);
udpwrite_p->gw = 0; trans_p->TBD.offset = VTOPOFF(tbd_p);
else
udpwrite_p->gw = gateip.s_addr;
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 pxe_call(PXENV_UNDI_TRANSMIT);
/* XXX - I dont know why we need this. */ if (trans_p->Status != 0) {
delay(1000); return (-1);
#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;
} }
return len;
} 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;
} }

View File

@ -349,7 +349,7 @@ typedef struct {
*/ */
# define PXENV_UNDI_ISR_OUT_DONE 0 # define PXENV_UNDI_ISR_OUT_DONE 0
# define PXENV_UNDI_ISR_OUT_TRANSMIT 2 # 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 # define PXENV_UNDI_ISR_OUT_BUSY 4
} PACKED t_PXENV_UNDI_ISR; } PACKED t_PXENV_UNDI_ISR;

View File

@ -9,6 +9,7 @@ MAN=
INTERNALPROG= INTERNALPROG=
NEWVERSWHAT?= "bootstrap loader" x86 NEWVERSWHAT?= "bootstrap loader" x86
VERSION_FILE= ${.CURDIR}/../loader/version VERSION_FILE= ${.CURDIR}/../loader/version
LOADER_NET_SUPPORT?= yes
# architecture-specific loader code # architecture-specific loader code
SRCS= main.c conf.c vers.c SRCS= main.c conf.c vers.c
@ -25,6 +26,10 @@ CFLAGS+= -DLOADER_ZFS_SUPPORT
LIBZFSBOOT= ${.OBJDIR}/../../zfs/libzfsboot.a LIBZFSBOOT= ${.OBJDIR}/../../zfs/libzfsboot.a
.endif .endif
.if defined(LOADER_NET_SUPPORT)
CFLAGS+= -I${.CURDIR}/../../../../lib/libstand
.endif
# Enable PXE TFTP or NFS support, not both. # Enable PXE TFTP or NFS support, not both.
.if defined(LOADER_TFTP_SUPPORT) .if defined(LOADER_TFTP_SUPPORT)
CFLAGS+= -DLOADER_TFTP_SUPPORT CFLAGS+= -DLOADER_TFTP_SUPPORT

View File

@ -46,8 +46,8 @@ __FBSDID("$FreeBSD$");
static int ofwn_probe(struct netif *, void *); static int ofwn_probe(struct netif *, void *);
static int ofwn_match(struct netif *, void *); static int ofwn_match(struct netif *, void *);
static void ofwn_init(struct iodesc *, void *); static void ofwn_init(struct iodesc *, void *);
static int ofwn_get(struct iodesc *, void *, size_t, time_t); static ssize_t ofwn_get(struct iodesc *, void **, time_t);
static int ofwn_put(struct iodesc *, void *, size_t); static ssize_t ofwn_put(struct iodesc *, void *, size_t);
static void ofwn_end(struct netif *); static void ofwn_end(struct netif *);
extern struct netif_stats ofwn_stats[]; extern struct netif_stats ofwn_stats[];
@ -57,7 +57,7 @@ struct netif_dif ofwn_ifs[] = {
{ 0, 1, &ofwn_stats[0], 0, }, { 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 = { struct netif_driver ofwnet = {
"net", /* netif_bname */ "net", /* netif_bname */
@ -68,7 +68,7 @@ struct netif_driver ofwnet = {
ofwn_put, /* netif_put */ ofwn_put, /* netif_put */
ofwn_end, /* netif_end */ ofwn_end, /* netif_end */
ofwn_ifs, /* netif_ifs */ ofwn_ifs, /* netif_ifs */
NENTS(ofwn_ifs) /* netif_nifs */ nitems(ofwn_ifs) /* netif_nifs */
}; };
static ihandle_t netinstance; static ihandle_t netinstance;
@ -87,7 +87,7 @@ ofwn_probe(struct netif *nif, void *machdep_hint)
return 0; return 0;
} }
static int static ssize_t
ofwn_put(struct iodesc *desc, void *pkt, size_t len) ofwn_put(struct iodesc *desc, void *pkt, size_t len)
{ {
size_t sendlen; size_t sendlen;
@ -124,20 +124,32 @@ ofwn_put(struct iodesc *desc, void *pkt, size_t len)
return rv; return rv;
} }
static int static ssize_t
ofwn_get(struct iodesc *desc, void *pkt, size_t len, time_t timeout) ofwn_get(struct iodesc *desc, void **pkt, time_t timeout)
{ {
time_t t; time_t t;
int length; ssize_t length;
size_t len;
char *buf, *ptr;
#if defined(NETIF_DEBUG) #if defined(NETIF_DEBUG)
printf("netif_get: pkt=%p, maxlen=%d, timeout=%d\n", pkt, len, printf("netif_get: pkt=%p, timeout=%d\n", pkt, timeout);
timeout);
#endif #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(); t = getsecs();
do { do {
length = OF_read(netinstance, pkt, len); length = OF_read(netinstance, ptr, len);
} while ((length == -2 || length == 0) && } while ((length == -2 || length == 0) &&
(getsecs() - t < timeout)); (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); printf("netif_get: received length=%d (%x)\n", length, length);
#endif #endif
if (length < 12) if (length < 12) {
return -1; free(buf);
return (-1);
}
#if defined(NETIF_VERBOSE_DEBUG) #if defined(NETIF_VERBOSE_DEBUG)
{ {
char *ch = pkt; char *ch = ptr;
int i; int i;
for(i = 0; i < 96; i += 4) { 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) #if defined(NETIF_DEBUG)
{ {
struct ether_header *eh = pkt; struct ether_header *eh = ptr;
printf("dst: %s ", ether_sprintf(eh->ether_dhost)); printf("dst: %s ", ether_sprintf(eh->ether_dhost));
printf("src: %s ", ether_sprintf(eh->ether_shost)); 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 #endif
return length; *pkt = buf;
return (length);
} }
extern char *strchr(); extern char *strchr();

View File

@ -50,8 +50,8 @@ __FBSDID("$FreeBSD$");
static int net_probe(struct netif *, void *); static int net_probe(struct netif *, void *);
static int net_match(struct netif *, void *); static int net_match(struct netif *, void *);
static void net_init(struct iodesc *, void *); static void net_init(struct iodesc *, void *);
static int net_get(struct iodesc *, void *, size_t, time_t); static ssize_t net_get(struct iodesc *, void **, time_t);
static int net_put(struct iodesc *, void *, size_t); static ssize_t net_put(struct iodesc *, void *, size_t);
static void net_end(struct netif *); static void net_end(struct netif *);
extern struct netif_stats net_stats[]; extern struct netif_stats net_stats[];
@ -61,7 +61,7 @@ struct netif_dif net_ifs[] = {
{ 0, 1, &net_stats[0], 0, }, { 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 = { struct netif_driver uboot_net = {
"uboot_eth", /* netif_bname */ "uboot_eth", /* netif_bname */
@ -72,7 +72,7 @@ struct netif_driver uboot_net = {
net_put, /* netif_put */ net_put, /* netif_put */
net_end, /* netif_end */ net_end, /* netif_end */
net_ifs, /* netif_ifs */ net_ifs, /* netif_ifs */
NENTS(net_ifs) /* netif_nifs */ nitems(net_ifs) /* netif_nifs */
}; };
struct uboot_softc { struct uboot_softc {
@ -232,7 +232,7 @@ net_probe(struct netif *nif, void *machdep_hint)
return (0); return (0);
} }
static int static ssize_t
net_put(struct iodesc *desc, void *pkt, size_t len) net_put(struct iodesc *desc, void *pkt, size_t len)
{ {
struct netif *nif = desc->io_netif; struct netif *nif = desc->io_netif;
@ -271,18 +271,21 @@ net_put(struct iodesc *desc, void *pkt, size_t len)
return (rv); return (rv);
} }
static int static ssize_t
net_get(struct iodesc *desc, void *pkt, size_t len, time_t timeout) net_get(struct iodesc *desc, void **pkt, time_t timeout)
{ {
struct netif *nif = desc->io_netif; struct netif *nif = desc->io_netif;
struct uboot_softc *sc = nif->nif_devdata; struct uboot_softc *sc = nif->nif_devdata;
time_t t; time_t t;
int err, rlen; int err, rlen;
size_t len;
char *buf;
#if defined(NETIF_DEBUG) #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 #endif
t = getsecs(); t = getsecs();
len = sizeof(sc->sc_rxbuf);
do { do {
err = ub_dev_recv(sc->sc_handle, sc->sc_rxbuf, len, &rlen); 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 #endif
if (rlen > 0) { if (rlen > 0) {
memcpy(pkt, sc->sc_rxbuf, MIN(len, rlen)); buf = malloc(rlen + ETHER_ALIGN);
if (rlen != len) { if (buf == NULL)
#if defined(NETIF_DEBUG) return (-1);
printf("net_get: len %x, rlen %x\n", len, rlen); memcpy(buf + ETHER_ALIGN, sc->sc_rxbuf, rlen);
#endif *pkt = buf;
} return ((ssize_t)rlen);
return (rlen);
} }
return (-1); return (-1);