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

View File

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

View File

@ -147,6 +147,10 @@ struct cmu_vend {
/* v_flags values */
#define VF_SMASK 1 /* Subnet mask field contains valid data */
/* cached bootp response/dhcp ack */
extern struct bootp *bootp_response;
extern size_t bootp_response_size;
int dhcp_try_rfc1048(u_char *cp, u_int len);
#endif /* _BOOTP_H_ */

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -48,7 +48,7 @@
/* RPC functions: */
ssize_t rpc_call(struct iodesc *, n_long, n_long, n_long,
void *, size_t, void *, size_t);
void *, size_t, void **, void **);
void rpc_fromaddr(void *, struct in_addr *, u_short *);
int rpc_pmap_getcache(struct in_addr, u_int, u_int);
void rpc_pmap_putcache(struct in_addr, u_int, u_int, int);

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -30,11 +30,15 @@
__FBSDID("$FreeBSD$");
#include <stand.h>
#include <stddef.h>
#include <string.h>
#include <stdarg.h>
#include <sys/param.h>
#include <net/ethernet.h>
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/udp.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.
*/
#define PXE_BUFFER_SIZE 0x2000
#define PXE_TFTP_BUFFER_SIZE 512
static char scratch_buffer[PXE_BUFFER_SIZE];
static char data_buffer[PXE_BUFFER_SIZE];
static pxenv_t *pxenv_p = NULL; /* PXENV+ */
static pxe_t *pxe_p = NULL; /* !PXE */
static BOOTPLAYER bootplayer; /* PXE Cached information. */
#ifdef PXE_DEBUG
static int pxe_debug = 0;
static int pxe_sock = -1;
static int pxe_opens = 0;
#endif
void pxe_enable(void *pxeinfo);
static void (*pxe_call)(int func);
@ -71,25 +73,17 @@ static void pxenv_call(int func);
static void bangpxe_call(int func);
static int pxe_init(void);
static int pxe_strategy(void *devdata, int flag, daddr_t dblk,
size_t size, char *buf, size_t *rsize);
static int pxe_open(struct open_file *f, ...);
static int pxe_close(struct open_file *f);
static int pxe_print(int verbose);
static void pxe_cleanup(void);
static void pxe_setnfshandle(char *rootpath);
static void pxe_perror(int error);
static int pxe_netif_match(struct netif *nif, void *machdep_hint);
static int pxe_netif_probe(struct netif *nif, void *machdep_hint);
static void pxe_netif_init(struct iodesc *desc, void *machdep_hint);
static int pxe_netif_get(struct iodesc *desc, void *pkt, size_t len,
time_t timeout);
static int pxe_netif_put(struct iodesc *desc, void *pkt, size_t len);
static ssize_t pxe_netif_get(struct iodesc *, void **, time_t);
static ssize_t pxe_netif_put(struct iodesc *desc, void *pkt, size_t len);
static void pxe_netif_end(struct netif *nif);
int nfs_getrootfh(struct iodesc*, char*, uint32_t*, u_char*);
extern struct netif_stats pxe_st[];
extern u_int16_t __bangpxeseg;
extern u_int16_t __bangpxeoff;
@ -97,25 +91,24 @@ extern void __bangpxeentry(void);
extern u_int16_t __pxenvseg;
extern u_int16_t __pxenvoff;
extern void __pxenventry(void);
extern struct in_addr servip;
struct netif_dif pxe_ifs[] = {
/* dif_unit dif_nsel dif_stats dif_private */
{0, 1, &pxe_st[0], 0}
};
struct netif_stats pxe_st[NENTS(pxe_ifs)];
struct netif_stats pxe_st[nitems(pxe_ifs)];
struct netif_driver pxenetif = {
"pxenet",
pxe_netif_match,
pxe_netif_probe,
pxe_netif_init,
pxe_netif_get,
pxe_netif_put,
pxe_netif_end,
pxe_ifs,
NENTS(pxe_ifs)
.netif_bname = "pxenet",
.netif_match = pxe_netif_match,
.netif_probe = pxe_netif_probe,
.netif_init = pxe_netif_init,
.netif_get = pxe_netif_get,
.netif_put = pxe_netif_put,
.netif_end = pxe_netif_end,
.netif_ifs = pxe_ifs,
.netif_nifs = nitems(pxe_ifs)
};
struct netif_driver *netif_drivers[] = {
@ -124,15 +117,15 @@ struct netif_driver *netif_drivers[] = {
};
struct devsw pxedisk = {
"pxe",
DEVT_NET,
pxe_init,
pxe_strategy,
pxe_open,
pxe_close,
noioctl,
pxe_print,
pxe_cleanup
.dv_name = "net",
.dv_type = DEVT_NET,
.dv_init = pxe_init,
.dv_strategy = NULL, /* Will be set in pxe_init */
.dv_open = NULL, /* Will be set in pxe_init */
.dv_close = NULL, /* Will be set in pxe_init */
.dv_ioctl = noioctl,
.dv_print = pxe_print,
.dv_cleanup = pxe_cleanup
};
/*
@ -160,6 +153,7 @@ pxe_init(void)
int counter;
uint8_t checksum;
uint8_t *checkptr;
extern struct devsw netdev;
if (pxenv_p == NULL)
return (0);
@ -215,7 +209,11 @@ pxe_init(void)
break;
}
}
pxedisk.dv_open = netdev.dv_open;
pxedisk.dv_close = netdev.dv_close;
pxedisk.dv_strategy = netdev.dv_strategy;
printf("\nPXE version %d.%d, real mode entry point ",
(uint8_t) (pxenv_p->Version >> 8),
(uint8_t) (pxenv_p->Version & 0xFF));
@ -236,190 +234,29 @@ pxe_init(void)
pxe_p = NULL;
return (0);
}
bcopy(PTOV((gci_p->Buffer.segment << 4) + gci_p->Buffer.offset),
&bootplayer, gci_p->BufferSize);
free(bootp_response);
if ((bootp_response = malloc(gci_p->BufferSize)) != NULL) {
bootp_response_size = gci_p->BufferSize;
bcopy(PTOV((gci_p->Buffer.segment << 4) + gci_p->Buffer.offset),
bootp_response, bootp_response_size);
}
return (1);
}
static int
pxe_strategy(void *devdata, int flag, daddr_t dblk, size_t size,
char *buf, size_t *rsize)
{
return (EIO);
}
static int
pxe_open(struct open_file *f, ...)
{
va_list args;
char *devname; /* Device part of file name (or NULL). */
char temp[FNAME_SIZE];
int error = 0;
int i;
va_start(args, f);
devname = va_arg(args, char*);
va_end(args);
/* On first open, do netif open, mount, etc. */
if (pxe_opens == 0) {
/* Find network interface. */
if (pxe_sock < 0) {
pxe_sock = netif_open(devname);
if (pxe_sock < 0) {
printf("pxe_open: netif_open() failed\n");
return (ENXIO);
}
if (pxe_debug)
printf("pxe_open: netif_open() succeeded\n");
if (socktodesc(pxe_sock) == NULL) {
printf("pxe_open: bad socket %d\n", pxe_sock);
return (ENXIO);
}
}
if (rootip.s_addr == 0) {
/*
* Try to extract the RFC1048 data from PXE.
* If fail do a bootp/dhcp request to find out where our
* NFS/TFTP server is. Even if we dont get back
* the proper information, fall back to the server
* which brought us to life and a default rootpath.
*/
if (dhcp_try_rfc1048(bootplayer.vendor.d, BOOTP_DHCPVEND) < 0) {
if (pxe_debug)
printf("pxe_open: no RFC1048 data in PXE Cache\n");
bootp(pxe_sock, BOOTP_PXE);
} else if (pxe_debug) {
printf("pxe_open: loaded RFC1048 data from PXE Cache\n");
}
#ifdef LOADER_TFTP_SUPPORT
bootp(pxe_sock, BOOTP_PXE);
#endif
if (rootip.s_addr == 0)
rootip.s_addr = bootplayer.sip;
if (gateip.s_addr == 0)
gateip.s_addr = bootplayer.gip;
if (myip.s_addr == 0)
myip.s_addr = bootplayer.yip;
if (servip.s_addr == 0)
servip = rootip;
netproto = NET_TFTP;
if (!rootpath[0])
strcpy(rootpath, PXENFSROOTPATH);
for (i = 0; rootpath[i] != '\0' && i < FNAME_SIZE; i++)
if (rootpath[i] == ':')
break;
if (i && i != FNAME_SIZE && rootpath[i] == ':') {
rootpath[i++] = '\0';
if (inet_addr(&rootpath[0]) != INADDR_NONE) {
netproto = NET_NFS;
rootip.s_addr = inet_addr(&rootpath[0]);
}
bcopy(&rootpath[i], &temp[0], strlen(&rootpath[i]) + 1);
bcopy(&temp[0], &rootpath[0], strlen(&rootpath[i]) + 1);
}
setenv("boot.netif.ip", inet_ntoa(myip), 1);
setenv("boot.netif.netmask", intoa(netmask), 1);
setenv("boot.netif.gateway", inet_ntoa(gateip), 1);
setenv("boot.netif.server", inet_ntoa(rootip), 1);
if (bootplayer.Hardware == ETHER_TYPE) {
sprintf(temp, "%6D", bootplayer.CAddr, ":");
setenv("boot.netif.hwaddr", temp, 1);
}
if (intf_mtu != 0) {
char mtu[16];
snprintf(sizeof(mtu), mtu, "%u", intf_mtu);
setenv("boot.netif.mtu", mtu, 1);
}
printf("pxe_open: server addr: %s\n", inet_ntoa(rootip));
printf("pxe_open: server path: %s\n", rootpath);
printf("pxe_open: gateway ip: %s\n", inet_ntoa(gateip));
printf("pxe_open: my ip: %s\n", inet_ntoa(myip));
printf("pxe_open: netmask: %s\n", intoa(netmask));
printf("pxe_open: servip: %s\n", inet_ntoa(servip));
if (netproto == NET_TFTP) {
setenv("boot.tftproot.server", inet_ntoa(rootip), 1);
setenv("boot.tftproot.path", rootpath, 1);
} else if (netproto == NET_NFS) {
setenv("boot.nfsroot.server", inet_ntoa(rootip), 1);
setenv("boot.nfsroot.path", rootpath, 1);
}
setenv("dhcp.host-name", hostname, 1);
setenv("pxeboot.ip", inet_ntoa(myip), 1);
if (bootplayer.Hardware == ETHER_TYPE) {
sprintf(temp, "%6D", bootplayer.CAddr, ":");
setenv("pxeboot.hwaddr", temp, 1);
}
}
}
pxe_opens++;
f->f_devdata = &pxe_sock;
return (error);
}
static int
pxe_close(struct open_file *f)
{
#ifdef PXE_DEBUG
if (pxe_debug)
printf("pxe_close: opens=%d\n", pxe_opens);
#endif
/* On last close, do netif close, etc. */
f->f_devdata = NULL;
/* Extra close call? */
if (pxe_opens <= 0)
return (0);
pxe_opens--;
/* Not last close? */
if (pxe_opens > 0)
return (0);
if (netproto == NET_NFS) {
/* get an NFS filehandle for our root filesystem */
pxe_setnfshandle(rootpath);
}
if (pxe_sock >= 0) {
#ifdef PXE_DEBUG
if (pxe_debug)
printf("pxe_close: calling netif_close()\n");
#endif
netif_close(pxe_sock);
pxe_sock = -1;
}
return (0);
}
static int
pxe_print(int verbose)
{
char line[255];
if (pxe_call == NULL)
return (0);
printf("%s devices:", pxedisk.dv_name);
if (pager_output("\n") != 0)
return (1);
printf(" %s0:", pxedisk.dv_name);
if (verbose) {
snprintf(line, sizeof(line), " pxe0: %s:%s\n",
inet_ntoa(rootip), rootpath);
} else {
snprintf(line, sizeof(line), " pxe0:\n");
printf(" %s:%s", inet_ntoa(rootip), rootpath);
}
return (pager_output(line));
return (pager_output("\n"));
}
static void
@ -458,66 +295,6 @@ pxe_perror(int err)
return;
}
/*
* Reach inside the libstand NFS code and dig out an NFS handle
* for the root filesystem.
*/
#define NFS_V3MAXFHSIZE 64
struct nfs_iodesc {
struct iodesc *iodesc;
off_t off;
uint32_t fhsize;
u_char fh[NFS_V3MAXFHSIZE];
/* structure truncated */
};
extern struct nfs_iodesc nfs_root_node;
extern int rpc_port;
static void
pxe_rpcmountcall()
{
struct iodesc *d;
int error;
if (!(d = socktodesc(pxe_sock)))
return;
d->myport = htons(--rpc_port);
d->destip = rootip;
if ((error = nfs_getrootfh(d, rootpath, &nfs_root_node.fhsize,
nfs_root_node.fh)) != 0) {
printf("NFS MOUNT RPC error: %d\n", error);
nfs_root_node.fhsize = 0;
}
nfs_root_node.iodesc = d;
}
static void
pxe_setnfshandle(char *rootpath)
{
int i;
u_char *fh;
char buf[2 * NFS_V3MAXFHSIZE + 3], *cp;
/*
* If NFS files were never opened, we need to do mount call
* ourselves. Use nfs_root_node.iodesc as flag indicating
* previous NFS usage.
*/
if (nfs_root_node.iodesc == NULL)
pxe_rpcmountcall();
fh = &nfs_root_node.fh[0];
buf[0] = 'X';
cp = &buf[1];
for (i = 0; i < nfs_root_node.fhsize; i++, cp += 2)
sprintf(cp, "%02x", fh[i]);
sprintf(cp, "X");
setenv("boot.nfsroot.nfshandle", buf, 1);
sprintf(buf, "%d", nfs_root_node.fhsize);
setenv("boot.nfsroot.nfshandlelen", buf, 1);
}
void
pxenv_call(int func)
{
@ -568,121 +345,196 @@ bangpxe_call(int func)
static int
pxe_netif_match(struct netif *nif, void *machdep_hint)
{
return 1;
return (1);
}
static int
pxe_netif_probe(struct netif *nif, void *machdep_hint)
{
t_PXENV_UDP_OPEN *udpopen_p = (t_PXENV_UDP_OPEN *)scratch_buffer;
if (pxe_call == NULL)
return -1;
return (-1);
bzero(udpopen_p, sizeof(*udpopen_p));
udpopen_p->src_ip = bootplayer.yip;
pxe_call(PXENV_UDP_OPEN);
if (udpopen_p->status != 0) {
printf("pxe_netif_probe: failed %x\n", udpopen_p->status);
return -1;
}
return 0;
return (0);
}
static void
pxe_netif_end(struct netif *nif)
{
t_PXENV_UDP_CLOSE *udpclose_p = (t_PXENV_UDP_CLOSE *)scratch_buffer;
bzero(udpclose_p, sizeof(*udpclose_p));
t_PXENV_UNDI_CLOSE *undi_close_p;
pxe_call(PXENV_UDP_CLOSE);
if (udpclose_p->status != 0)
printf("pxe_end failed %x\n", udpclose_p->status);
undi_close_p = (t_PXENV_UNDI_CLOSE *)scratch_buffer;
bzero(undi_close_p, sizeof(*undi_close_p));
pxe_call(PXENV_UNDI_CLOSE);
if (undi_close_p->Status != 0)
printf("undi close failed: %x\n", undi_close_p->Status);
}
static void
pxe_netif_init(struct iodesc *desc, void *machdep_hint)
{
int i;
for (i = 0; i < 6; ++i)
desc->myea[i] = bootplayer.CAddr[i];
desc->xid = bootplayer.ident;
t_PXENV_UNDI_GET_INFORMATION *undi_info_p;
t_PXENV_UNDI_OPEN *undi_open_p;
uint8_t *mac;
int i, len;
undi_info_p = (t_PXENV_UNDI_GET_INFORMATION *)scratch_buffer;
bzero(undi_info_p, sizeof(*undi_info_p));
pxe_call(PXENV_UNDI_GET_INFORMATION);
if (undi_info_p->Status != 0) {
printf("undi get info failed: %x\n", undi_info_p->Status);
return;
}
/* Make sure the CurrentNodeAddress is valid. */
for (i = 0; i < undi_info_p->HwAddrLen; ++i) {
if (undi_info_p->CurrentNodeAddress[i] != 0)
break;
}
if (i < undi_info_p->HwAddrLen) {
for (i = 0; i < undi_info_p->HwAddrLen; ++i) {
if (undi_info_p->CurrentNodeAddress[i] != 0xff)
break;
}
}
if (i < undi_info_p->HwAddrLen)
mac = undi_info_p->CurrentNodeAddress;
else
mac = undi_info_p->PermNodeAddress;
len = min(sizeof (desc->myea), undi_info_p->HwAddrLen);
for (i = 0; i < len; ++i)
desc->myea[i] = mac[i];
if (bootp_response != NULL)
desc->xid = bootp_response->bp_xid;
else
desc->xid = 0;
undi_open_p = (t_PXENV_UNDI_OPEN *)scratch_buffer;
bzero(undi_open_p, sizeof(*undi_open_p));
undi_open_p->PktFilter = FLTR_DIRECTED | FLTR_BRDCST;
pxe_call(PXENV_UNDI_OPEN);
if (undi_open_p->Status != 0)
printf("undi open failed: %x\n", undi_open_p->Status);
}
static int
pxe_netif_get(struct iodesc *desc, void *pkt, size_t len, time_t timeout)
pxe_netif_receive(void **pkt)
{
return len;
t_PXENV_UNDI_ISR *isr = (t_PXENV_UNDI_ISR *)scratch_buffer;
char *buf, *ptr, *frame;
size_t size, rsize;
bzero(isr, sizeof(*isr));
isr->FuncFlag = PXENV_UNDI_ISR_IN_START;
pxe_call(PXENV_UNDI_ISR);
if (isr->Status != 0)
return (-1);
bzero(isr, sizeof(*isr));
isr->FuncFlag = PXENV_UNDI_ISR_IN_PROCESS;
pxe_call(PXENV_UNDI_ISR);
if (isr->Status != 0)
return (-1);
while (isr->FuncFlag == PXENV_UNDI_ISR_OUT_TRANSMIT) {
/*
* Wait till transmit is done.
*/
bzero(isr, sizeof(*isr));
isr->FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT;
pxe_call(PXENV_UNDI_ISR);
if (isr->Status != 0 ||
isr->FuncFlag == PXENV_UNDI_ISR_OUT_DONE)
return (-1);
}
while (isr->FuncFlag != PXENV_UNDI_ISR_OUT_RECEIVE) {
if (isr->Status != 0 ||
isr->FuncFlag == PXENV_UNDI_ISR_OUT_DONE) {
return (-1);
}
bzero(isr, sizeof(*isr));
isr->FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT;
pxe_call(PXENV_UNDI_ISR);
}
size = isr->FrameLength;
buf = malloc(size + ETHER_ALIGN);
if (buf == NULL)
return (-1);
ptr = buf + ETHER_ALIGN;
rsize = 0;
while (rsize < size) {
frame = (char *)((uintptr_t)isr->Frame.segment << 4);
frame += isr->Frame.offset;
bcopy(PTOV(frame), ptr, isr->BufferLength);
ptr += isr->BufferLength;
rsize += isr->BufferLength;
bzero(isr, sizeof(*isr));
isr->FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT;
pxe_call(PXENV_UNDI_ISR);
if (isr->Status != 0) {
free(buf);
return (-1);
}
/* Did we got another update? */
if (isr->FuncFlag == PXENV_UNDI_ISR_OUT_RECEIVE)
continue;
break;
}
*pkt = buf;
return (rsize);
}
static int
static ssize_t
pxe_netif_get(struct iodesc *desc, void **pkt, time_t timeout)
{
time_t t;
void *ptr;
int ret = -1;
t = getsecs();
while ((getsecs() - t) < timeout) {
ret = pxe_netif_receive(&ptr);
if (ret != -1) {
*pkt = ptr;
break;
}
}
return (ret);
}
static ssize_t
pxe_netif_put(struct iodesc *desc, void *pkt, size_t len)
{
return len;
}
t_PXENV_UNDI_TRANSMIT *trans_p;
t_PXENV_UNDI_TBD *tbd_p;
char *data;
ssize_t
sendudp(struct iodesc *h, void *pkt, size_t len)
{
t_PXENV_UDP_WRITE *udpwrite_p = (t_PXENV_UDP_WRITE *)scratch_buffer;
bzero(udpwrite_p, sizeof(*udpwrite_p));
trans_p = (t_PXENV_UNDI_TRANSMIT *)scratch_buffer;
bzero(trans_p, sizeof(*trans_p));
tbd_p = (t_PXENV_UNDI_TBD *)(scratch_buffer + sizeof(*trans_p));
bzero(tbd_p, sizeof(*tbd_p));
udpwrite_p->ip = h->destip.s_addr;
udpwrite_p->dst_port = h->destport;
udpwrite_p->src_port = h->myport;
udpwrite_p->buffer_size = len;
udpwrite_p->buffer.segment = VTOPSEG(pkt);
udpwrite_p->buffer.offset = VTOPOFF(pkt);
data = scratch_buffer + sizeof(*trans_p) + sizeof(*tbd_p);
if (netmask == 0 || SAMENET(myip, h->destip, netmask))
udpwrite_p->gw = 0;
else
udpwrite_p->gw = gateip.s_addr;
trans_p->TBD.segment = VTOPSEG(tbd_p);
trans_p->TBD.offset = VTOPOFF(tbd_p);
pxe_call(PXENV_UDP_WRITE);
tbd_p->ImmedLength = len;
tbd_p->Xmit.segment = VTOPSEG(data);
tbd_p->Xmit.offset = VTOPOFF(data);
bcopy(pkt, data, len);
#if 0
/* XXX - I dont know why we need this. */
delay(1000);
#endif
if (udpwrite_p->status != 0) {
/* XXX: This happens a lot. It shouldn't. */
if (udpwrite_p->status != 1)
printf("sendudp failed %x\n", udpwrite_p->status);
return -1;
pxe_call(PXENV_UNDI_TRANSMIT);
if (trans_p->Status != 0) {
return (-1);
}
return len;
}
ssize_t
readudp(struct iodesc *h, void *pkt, size_t len, time_t timeout)
{
t_PXENV_UDP_READ *udpread_p = (t_PXENV_UDP_READ *)scratch_buffer;
struct udphdr *uh = NULL;
uh = (struct udphdr *) pkt - 1;
bzero(udpread_p, sizeof(*udpread_p));
udpread_p->dest_ip = h->myip.s_addr;
udpread_p->d_port = h->myport;
udpread_p->buffer_size = len;
udpread_p->buffer.segment = VTOPSEG(data_buffer);
udpread_p->buffer.offset = VTOPOFF(data_buffer);
pxe_call(PXENV_UDP_READ);
#if 0
/* XXX - I dont know why we need this. */
delay(1000);
#endif
if (udpread_p->status != 0) {
/* XXX: This happens a lot. It shouldn't. */
if (udpread_p->status != 1)
printf("readudp failed %x\n", udpread_p->status);
return -1;
}
bcopy(data_buffer, pkt, udpread_p->buffer_size);
uh->uh_sport = udpread_p->s_port;
return udpread_p->buffer_size;
return (len);
}

View File

@ -349,7 +349,7 @@ typedef struct {
*/
# define PXENV_UNDI_ISR_OUT_DONE 0
# define PXENV_UNDI_ISR_OUT_TRANSMIT 2
# define PXENV_UNDI_ISR_OUT_RECIEVE 3
# define PXENV_UNDI_ISR_OUT_RECEIVE 3
# define PXENV_UNDI_ISR_OUT_BUSY 4
} PACKED t_PXENV_UNDI_ISR;

View File

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

View File

@ -46,8 +46,8 @@ __FBSDID("$FreeBSD$");
static int ofwn_probe(struct netif *, void *);
static int ofwn_match(struct netif *, void *);
static void ofwn_init(struct iodesc *, void *);
static int ofwn_get(struct iodesc *, void *, size_t, time_t);
static int ofwn_put(struct iodesc *, void *, size_t);
static ssize_t ofwn_get(struct iodesc *, void **, time_t);
static ssize_t ofwn_put(struct iodesc *, void *, size_t);
static void ofwn_end(struct netif *);
extern struct netif_stats ofwn_stats[];
@ -57,7 +57,7 @@ struct netif_dif ofwn_ifs[] = {
{ 0, 1, &ofwn_stats[0], 0, },
};
struct netif_stats ofwn_stats[NENTS(ofwn_ifs)];
struct netif_stats ofwn_stats[nitems(ofwn_ifs)];
struct netif_driver ofwnet = {
"net", /* netif_bname */
@ -68,7 +68,7 @@ struct netif_driver ofwnet = {
ofwn_put, /* netif_put */
ofwn_end, /* netif_end */
ofwn_ifs, /* netif_ifs */
NENTS(ofwn_ifs) /* netif_nifs */
nitems(ofwn_ifs) /* netif_nifs */
};
static ihandle_t netinstance;
@ -87,7 +87,7 @@ ofwn_probe(struct netif *nif, void *machdep_hint)
return 0;
}
static int
static ssize_t
ofwn_put(struct iodesc *desc, void *pkt, size_t len)
{
size_t sendlen;
@ -124,20 +124,32 @@ ofwn_put(struct iodesc *desc, void *pkt, size_t len)
return rv;
}
static int
ofwn_get(struct iodesc *desc, void *pkt, size_t len, time_t timeout)
static ssize_t
ofwn_get(struct iodesc *desc, void **pkt, time_t timeout)
{
time_t t;
int length;
ssize_t length;
size_t len;
char *buf, *ptr;
#if defined(NETIF_DEBUG)
printf("netif_get: pkt=%p, maxlen=%d, timeout=%d\n", pkt, len,
timeout);
printf("netif_get: pkt=%p, timeout=%d\n", pkt, timeout);
#endif
/*
* We should read the "max-frame-size" int property instead,
* but at this time the iodesc does not have mtu, so we will take
* a small shortcut here.
*/
len = ETHER_MAX_LEN;
buf = malloc(len + ETHER_ALIGN);
if (buf == NULL)
return (-1);
ptr = buf + ETHER_ALIGN;
t = getsecs();
do {
length = OF_read(netinstance, pkt, len);
length = OF_read(netinstance, ptr, len);
} while ((length == -2 || length == 0) &&
(getsecs() - t < timeout));
@ -145,12 +157,14 @@ ofwn_get(struct iodesc *desc, void *pkt, size_t len, time_t timeout)
printf("netif_get: received length=%d (%x)\n", length, length);
#endif
if (length < 12)
return -1;
if (length < 12) {
free(buf);
return (-1);
}
#if defined(NETIF_VERBOSE_DEBUG)
{
char *ch = pkt;
char *ch = ptr;
int i;
for(i = 0; i < 96; i += 4) {
@ -163,7 +177,7 @@ ofwn_get(struct iodesc *desc, void *pkt, size_t len, time_t timeout)
#if defined(NETIF_DEBUG)
{
struct ether_header *eh = pkt;
struct ether_header *eh = ptr;
printf("dst: %s ", ether_sprintf(eh->ether_dhost));
printf("src: %s ", ether_sprintf(eh->ether_shost));
@ -171,7 +185,8 @@ ofwn_get(struct iodesc *desc, void *pkt, size_t len, time_t timeout)
}
#endif
return length;
*pkt = buf;
return (length);
}
extern char *strchr();

View File

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