mirror of
https://git.FreeBSD.org/src.git
synced 2024-11-28 08:02:54 +00:00
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:
parent
a872bf12f8
commit
da8fb057e5
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=317887
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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_ */
|
||||
|
@ -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;
|
||||
|
@ -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];
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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 @@ netif_open(machdep_hint)
|
||||
printf("netboot: couldn't probe %s%d\n",
|
||||
nif->nif_driver->netif_bname, nif->nif_unit);
|
||||
errno = EINVAL;
|
||||
return(-1);
|
||||
return (-1);
|
||||
}
|
||||
netif_attach(nif, s, machdep_hint);
|
||||
|
||||
return(fd);
|
||||
return (fd);
|
||||
}
|
||||
|
||||
int
|
||||
netif_close(sock)
|
||||
int sock;
|
||||
netif_close(int sock)
|
||||
{
|
||||
if (sock >= SOPEN_MAX) {
|
||||
errno = EBADF;
|
||||
return(-1);
|
||||
return (-1);
|
||||
}
|
||||
netif_detach(sockets[sock].io_netif);
|
||||
sockets[sock].io_netif = (struct netif *)0;
|
||||
|
||||
return(0);
|
||||
return (0);
|
||||
}
|
||||
|
@ -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 *);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -230,5 +230,5 @@ time(time_t *tloc)
|
||||
time_t
|
||||
getsecs(void)
|
||||
{
|
||||
return time(0);
|
||||
return time(NULL);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user