Page MenuHomeFreeBSD

D10232.id26924.diff
No OneTemporary

D10232.id26924.diff

Index: lib/libstand/arp.c
===================================================================
--- lib/libstand/arp.c
+++ lib/libstand/arp.c
@@ -65,17 +65,16 @@
/* Local forwards */
static ssize_t arpsend(struct iodesc *, void *, size_t);
-static ssize_t arprecv(struct iodesc *, void *, size_t, time_t);
+static ssize_t arprecv(struct iodesc *, void **, void **, time_t);
/* Broadcast an ARP packet, asking who has addr on interface d */
u_char *
-arpwhohas(d, addr)
- struct iodesc *d;
- struct in_addr addr;
+arpwhohas(struct iodesc *d, struct in_addr addr)
{
int i;
struct ether_arp *ah;
struct arp_list *al;
+ void *pkt;
struct {
struct ether_header eh;
struct {
@@ -83,13 +82,6 @@
u_char pad[18]; /* 60 - sizeof(...) */
} data;
} wbuf;
- struct {
- struct ether_header eh;
- struct {
- struct ether_arp arp;
- u_char pad[24]; /* extra space */
- } data;
- } rbuf;
/* Try for cached answer first */
for (i = 0, al = arp_list; i < arp_num; ++i, ++al)
@@ -122,20 +114,24 @@
/* Store ip address in cache (incomplete entry). */
al->addr = addr;
+ pkt = NULL;
+ ah = NULL;
i = sendrecv(d,
arpsend, &wbuf.data, sizeof(wbuf.data),
- arprecv, &rbuf.data, sizeof(rbuf.data));
+ arprecv, &pkt, (void **)&ah);
if (i == -1) {
panic("arp: no response for %s\n",
inet_ntoa(addr));
}
/* Store ethernet address in cache */
- ah = &rbuf.data.arp;
#ifdef ARP_DEBUG
if (debug) {
+ struct ether_header *eh;
+
+ eh = (struct ether_header *)((uintptr_t)pkt + 2);
printf("arp: response from %s\n",
- ether_sprintf(rbuf.eh.ether_shost));
+ ether_sprintf(eh->ether_shost));
printf("arp: cacheing %s --> %s\n",
inet_ntoa(addr), ether_sprintf(ah->arp_sha));
}
@@ -143,14 +139,12 @@
MACPY(ah->arp_sha, al->ea);
++arp_num;
+ free(pkt);
return (al->ea);
}
static ssize_t
-arpsend(d, pkt, len)
- struct iodesc *d;
- void *pkt;
- size_t len;
+arpsend(struct iodesc *d, void *pkt, size_t len)
{
#ifdef ARP_DEBUG
@@ -166,28 +160,27 @@
* else -1 (and errno == 0)
*/
static ssize_t
-arprecv(d, pkt, len, tleft)
- struct iodesc *d;
- void *pkt;
- size_t len;
- time_t tleft;
+arprecv(struct iodesc *d, void **pkt, void **payload, time_t tleft)
{
ssize_t n;
struct ether_arp *ah;
u_int16_t etype; /* host order */
+ void *ptr;
#ifdef ARP_DEBUG
if (debug)
printf("arprecv: ");
#endif
- n = readether(d, pkt, len, tleft, &etype);
+ ptr = NULL;
+ n = readether(d, &ptr, (void **)&ah, tleft, &etype);
errno = 0; /* XXX */
if (n == -1 || n < sizeof(struct ether_arp)) {
#ifdef ARP_DEBUG
if (debug)
printf("bad len=%d\n", n);
#endif
+ free(ptr);
return (-1);
}
@@ -196,12 +189,11 @@
if (debug)
printf("not arp type=%d\n", etype);
#endif
+ free(ptr);
return (-1);
}
/* Ethernet address now checked in readether() */
-
- ah = (struct ether_arp *)pkt;
if (ah->arp_hrd != htons(ARPHRD_ETHER) ||
ah->arp_pro != htons(ETHERTYPE_IP) ||
ah->arp_hln != sizeof(ah->arp_sha) ||
@@ -211,6 +203,7 @@
if (debug)
printf("bad hrd/pro/hln/pln\n");
#endif
+ free(ptr);
return (-1);
}
@@ -220,6 +213,7 @@
printf("is request\n");
#endif
arp_reply(d, ah);
+ free(ptr);
return (-1);
}
@@ -228,6 +222,7 @@
if (debug)
printf("not ARP reply\n");
#endif
+ free(ptr);
return (-1);
}
@@ -239,6 +234,7 @@
if (debug)
printf("unwanted address\n");
#endif
+ free(ptr);
return (-1);
}
/* We don't care who the reply was sent to. */
@@ -248,6 +244,8 @@
if (debug)
printf("got it\n");
#endif
+ *pkt = ptr;
+ *payload = ah;
return (n);
}
@@ -256,9 +254,7 @@
* Notes: Re-uses buffer. Pad to length = 46.
*/
void
-arp_reply(d, pkt)
- struct iodesc *d;
- void *pkt; /* the request */
+arp_reply(struct iodesc *d, void *pkt)
{
struct ether_arp *arp = pkt;
Index: lib/libstand/bootp.h
===================================================================
--- lib/libstand/bootp.h
+++ lib/libstand/bootp.h
@@ -148,6 +148,10 @@
/* v_flags values */
#define VF_SMASK 1 /* Subnet mask field contains valid data */
+/* cached bootp response/dhcp ack */
+extern struct bootp *bootp_response;
+extern size_t bootp_response_size;
+
int dhcp_try_rfc1048(u_char *cp, u_int len);
#endif /* _BOOTP_H_ */
Index: lib/libstand/bootp.c
===================================================================
--- lib/libstand/bootp.c
+++ lib/libstand/bootp.c
@@ -38,6 +38,7 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include <stddef.h>
#include <sys/types.h>
#include <sys/limits.h>
#include <sys/endian.h>
@@ -72,7 +73,7 @@
/* Local forwards */
static ssize_t bootpsend(struct iodesc *, void *, size_t);
-static ssize_t bootprecv(struct iodesc *, void *, size_t, time_t);
+static ssize_t bootprecv(struct iodesc *, void **, void **, time_t);
static int vend_rfc1048(u_char *, u_int);
#ifdef BOOTP_VEND_CMU
static void vend_cmu(u_char *);
@@ -89,23 +90,21 @@
static char expected_dhcpmsgtype = -1, dhcp_ok;
struct in_addr dhcp_serverip;
#endif
+struct bootp *bootp_response;
+size_t bootp_response_size;
/* Fetch required bootp infomation */
void
-bootp(sock, flag)
- int sock;
- int flag;
+bootp(int sock, int flag)
{
+ void *pkt;
struct iodesc *d;
struct bootp *bp;
struct {
u_char header[HEADER_SIZE];
struct bootp wbootp;
} wbuf;
- struct {
- u_char header[HEADER_SIZE];
- struct bootp rbootp;
- } rbuf;
+ struct bootp *rbootp;
#ifdef BOOTP_DEBUG
if (debug)
@@ -176,8 +175,7 @@
if(sendrecv(d,
bootpsend, bp, sizeof(*bp),
- bootprecv, &rbuf.rbootp, sizeof(rbuf.rbootp))
- == -1) {
+ bootprecv, &pkt, (void **)&rbootp) == -1) {
printf("bootp: no reply\n");
return;
}
@@ -188,7 +186,7 @@
bp->bp_vend[6] = DHCPREQUEST;
bp->bp_vend[7] = TAG_REQ_ADDR;
bp->bp_vend[8] = 4;
- bcopy(&rbuf.rbootp.bp_yiaddr, &bp->bp_vend[9], 4);
+ bcopy(&rbootp->bp_yiaddr, &bp->bp_vend[9], 4);
bp->bp_vend[13] = TAG_SERVERID;
bp->bp_vend[14] = 4;
bcopy(&dhcp_serverip.s_addr, &bp->bp_vend[15], 4);
@@ -206,20 +204,21 @@
expected_dhcpmsgtype = DHCPACK;
+ free(pkt);
if(sendrecv(d,
bootpsend, bp, sizeof(*bp),
- bootprecv, &rbuf.rbootp, sizeof(rbuf.rbootp))
- == -1) {
+ bootprecv, &pkt, (void **)&rbootp) == -1) {
printf("DHCPREQUEST failed\n");
return;
}
}
#endif
- myip = d->myip = rbuf.rbootp.bp_yiaddr;
- servip = rbuf.rbootp.bp_siaddr;
- if(rootip.s_addr == INADDR_ANY) rootip = servip;
- bcopy(rbuf.rbootp.bp_file, bootfile, sizeof(bootfile));
+ myip = d->myip = rbootp->bp_yiaddr;
+ servip = rbootp->bp_siaddr;
+ if (rootip.s_addr == INADDR_ANY)
+ rootip = servip;
+ bcopy(rbootp->bp_file, bootfile, sizeof(bootfile));
bootfile[sizeof(bootfile) - 1] = '\0';
if (!netmask) {
@@ -259,14 +258,12 @@
/* Bump xid so next request will be unique. */
++d->xid;
+ free(pkt);
}
/* Transmit a bootp request */
static ssize_t
-bootpsend(d, pkt, len)
- struct iodesc *d;
- void *pkt;
- size_t len;
+bootpsend(struct iodesc *d, void *pkt, size_t len)
{
struct bootp *bp;
@@ -287,30 +284,26 @@
}
static ssize_t
-bootprecv(d, pkt, len, tleft)
-struct iodesc *d;
-void *pkt;
-size_t len;
-time_t tleft;
+bootprecv(struct iodesc *d, void **pkt, void **payload, time_t tleft)
{
ssize_t n;
struct bootp *bp;
+ void *ptr;
-#ifdef BOOTP_DEBUGx
+#ifdef BOOTP_DEBUG
if (debug)
printf("bootp_recvoffer: called\n");
#endif
- n = readudp(d, pkt, len, tleft);
+ ptr = NULL;
+ n = readudp(d, &ptr, (void **)&bp, tleft);
if (n == -1 || n < sizeof(struct bootp) - BOOTP_VENDSIZE)
goto bad;
- bp = (struct bootp *)pkt;
-
#ifdef BOOTP_DEBUG
if (debug)
- printf("bootprecv: checked. bp = 0x%lx, n = %d\n",
- (long)bp, (int)n);
+ printf("bootprecv: checked. bp = 0x%p, n = %d\n",
+ (void *)bp, (int)n);
#endif
if (bp->bp_xid != htonl(d->xid)) {
#ifdef BOOTP_DEBUG
@@ -329,8 +322,21 @@
/* Suck out vendor info */
if (bcmp(vm_rfc1048, bp->bp_vend, sizeof(vm_rfc1048)) == 0) {
- if(vend_rfc1048(bp->bp_vend, sizeof(bp->bp_vend)) != 0)
+ int vsize = n - offsetof(struct bootp, bp_vend);
+ if (vend_rfc1048(bp->bp_vend, vsize) != 0)
goto bad;
+
+ /* Save copy of bootp reply or DHCP ACK message */
+ if (bp->bp_op == BOOTREPLY &&
+ ((dhcp_ok == 1 && expected_dhcpmsgtype == DHCPACK) ||
+ dhcp_ok == 0)) {
+ free(bootp_response);
+ bootp_response = malloc(n);
+ if (bootp_response != NULL) {
+ bootp_response_size = n;
+ bcopy(bp, bootp_response, bootp_response_size);
+ }
+ }
}
#ifdef BOOTP_VEND_CMU
else if (bcmp(vm_cmu, bp->bp_vend, sizeof(vm_cmu)) == 0)
@@ -339,8 +345,11 @@
else
printf("bootprecv: unknown vendor 0x%lx\n", (long)bp->bp_vend);
- return(n);
+ *pkt = ptr;
+ *payload = bp;
+ return (n);
bad:
+ free(ptr);
errno = 0;
return (-1);
}
@@ -357,9 +366,7 @@
}
static int
-vend_rfc1048(cp, len)
- u_char *cp;
- u_int len;
+vend_rfc1048(u_char *cp, u_int len)
{
u_char *ep;
int size;
@@ -450,8 +457,7 @@
#ifdef BOOTP_VEND_CMU
static void
-vend_cmu(cp)
- u_char *cp;
+vend_cmu(u_char *cp)
{
struct cmu_vend *vp;
Index: lib/libstand/bootparam.c
===================================================================
--- lib/libstand/bootparam.c
+++ lib/libstand/bootparam.c
@@ -104,8 +104,7 @@
* know about us (don't want to broadcast a getport call).
*/
int
-bp_whoami(sockfd)
- int sockfd;
+bp_whoami(int sockfd)
{
/* RPC structures for PMAPPROC_CALLIT */
struct args {
@@ -126,13 +125,10 @@
n_long h[RPC_HEADER_WORDS];
struct args d;
} sdata;
- struct {
- n_long h[RPC_HEADER_WORDS];
- struct repl d;
- } rdata;
char *send_tail, *recv_head;
struct iodesc *d;
- int len, x;
+ void *pkt;
+ int len, x, rc = -1;
RPC_PRINTF(("bp_whoami: myip=%s\n", inet_ntoa(myip)));
@@ -141,7 +137,6 @@
return (-1);
}
args = &sdata.d;
- repl = &rdata.d;
/*
* Build request args for PMAPPROC_CALLIT.
@@ -163,12 +158,12 @@
d->destip.s_addr = INADDR_BROADCAST; /* XXX: subnet bcast? */
/* rpc_call will set d->destport */
+ pkt = NULL;
len = rpc_call(d, PMAPPROG, PMAPVERS, PMAPPROC_CALLIT,
- args, send_tail - (char*)args,
- repl, sizeof(*repl));
+ args, send_tail - (char*)args, (void **)&repl, &pkt);
if (len < 8) {
printf("bootparamd: 'whoami' call failed\n");
- return (-1);
+ goto done;
}
/* Save bootparam server address (from IP header). */
@@ -196,7 +191,7 @@
x = ntohl(repl->encap_len);
if (len < x) {
printf("bp_whoami: short reply, %d < %d\n", len, x);
- return (-1);
+ goto done;
}
recv_head = (char*) repl->capsule;
@@ -204,24 +199,27 @@
hostnamelen = MAXHOSTNAMELEN-1;
if (xdr_string_decode(&recv_head, hostname, &hostnamelen)) {
RPC_PRINTF(("bp_whoami: bad hostname\n"));
- return (-1);
+ goto done;
}
/* domain name */
domainnamelen = MAXHOSTNAMELEN-1;
if (xdr_string_decode(&recv_head, domainname, &domainnamelen)) {
RPC_PRINTF(("bp_whoami: bad domainname\n"));
- return (-1);
+ goto done;
}
/* gateway address */
if (xdr_inaddr_decode(&recv_head, &gateip)) {
RPC_PRINTF(("bp_whoami: bad gateway\n"));
- return (-1);
+ goto done;
}
/* success */
- return(0);
+ rc = 0;
+done:
+ free(pkt);
+ return (rc);
}
@@ -233,25 +231,18 @@
* server pathname
*/
int
-bp_getfile(sockfd, key, serv_addr, pathname)
- int sockfd;
- char *key;
- char *pathname;
- struct in_addr *serv_addr;
+bp_getfile(int sockfd, char *key, struct in_addr *serv_addr, char *pathname)
{
struct {
n_long h[RPC_HEADER_WORDS];
n_long d[64];
} sdata;
- struct {
- n_long h[RPC_HEADER_WORDS];
- n_long d[128];
- } rdata;
+ void *pkt;
char serv_name[FNAME_SIZE];
- char *send_tail, *recv_head;
+ char *rdata, *send_tail;
/* misc... */
struct iodesc *d;
- int sn_len, path_len, rlen;
+ int rc = -1, sn_len, path_len, rlen;
if (!(d = socktodesc(sockfd))) {
RPC_PRINTF(("bp_getfile: bad socket. %d\n", sockfd));
@@ -259,7 +250,6 @@
}
send_tail = (char*) sdata.d;
- recv_head = (char*) rdata.d;
/*
* Build request message.
@@ -281,17 +271,16 @@
d->myport = htons(--rpc_port);
d->destip = bp_server_addr;
/* rpc_call will set d->destport */
-
+ pkt = NULL;
rlen = rpc_call(d,
BOOTPARAM_PROG, BOOTPARAM_VERS, BOOTPARAM_GETFILE,
sdata.d, send_tail - (char*)sdata.d,
- rdata.d, sizeof(rdata.d));
+ (void **)&rdata, &pkt);
if (rlen < 4) {
RPC_PRINTF(("bp_getfile: short reply\n"));
errno = EBADRPC;
- return (-1);
+ goto done;
}
- recv_head = (char*) rdata.d;
/*
* Parse result message.
@@ -299,26 +288,29 @@
/* server name */
sn_len = FNAME_SIZE-1;
- if (xdr_string_decode(&recv_head, serv_name, &sn_len)) {
+ if (xdr_string_decode(&rdata, serv_name, &sn_len)) {
RPC_PRINTF(("bp_getfile: bad server name\n"));
- return (-1);
+ goto done;
}
/* server IP address (mountd/NFS) */
- if (xdr_inaddr_decode(&recv_head, serv_addr)) {
+ if (xdr_inaddr_decode(&rdata, serv_addr)) {
RPC_PRINTF(("bp_getfile: bad server addr\n"));
- return (-1);
+ goto done;
}
/* server pathname */
path_len = MAXPATHLEN-1;
- if (xdr_string_decode(&recv_head, pathname, &path_len)) {
+ if (xdr_string_decode(&rdata, pathname, &path_len)) {
RPC_PRINTF(("bp_getfile: bad server path\n"));
- return (-1);
+ goto done;
}
/* success */
- return(0);
+ rc = 0;
+done:
+ free(pkt);
+ return (rc);
}
@@ -329,17 +321,14 @@
int
-xdr_string_encode(pkt, str, len)
- char **pkt;
- char *str;
- int len;
+xdr_string_encode(char **pkt, char *str, int len)
{
u_int32_t *lenp;
char *datap;
int padlen = (len + 3) & ~3; /* padded length */
/* The data will be int aligned. */
- lenp = (u_int32_t*) *pkt;
+ lenp = (uint32_t *) *pkt;
*pkt += sizeof(*lenp);
*lenp = htonl(len);
@@ -351,10 +340,7 @@
}
int
-xdr_string_decode(pkt, str, len_p)
- char **pkt;
- char *str;
- int *len_p; /* bufsize - 1 */
+xdr_string_decode(char **pkt, char *str, int *len_p)
{
u_int32_t *lenp;
char *datap;
@@ -362,7 +348,7 @@
int plen; /* padded length */
/* The data will be int aligned. */
- lenp = (u_int32_t*) *pkt;
+ lenp = (uint32_t *) *pkt;
*pkt += sizeof(*lenp);
slen = ntohl(*lenp);
plen = (slen + 3) & ~3;
@@ -381,9 +367,7 @@
int
-xdr_inaddr_encode(pkt, ia)
- char **pkt;
- struct in_addr ia; /* network order */
+xdr_inaddr_encode(char **pkt, struct in_addr ia)
{
struct xdr_inaddr *xi;
u_char *cp;
@@ -414,9 +398,7 @@
}
int
-xdr_inaddr_decode(pkt, ia)
- char **pkt;
- struct in_addr *ia; /* network order */
+xdr_inaddr_decode(char **pkt, struct in_addr *ia)
{
struct xdr_inaddr *xi;
u_char *cp;
Index: lib/libstand/ether.c
===================================================================
--- lib/libstand/ether.c
+++ lib/libstand/ether.c
@@ -54,12 +54,7 @@
/* Caller must leave room for ethernet header in front!! */
ssize_t
-sendether(d, pkt, len, dea, etype)
- struct iodesc *d;
- void *pkt;
- size_t len;
- u_char *dea;
- int etype;
+sendether(struct iodesc *d, void *pkt, size_t len, uint8_t *dea, int etype)
{
ssize_t n;
struct ether_header *eh;
@@ -86,32 +81,31 @@
/*
* Get a packet of any Ethernet type, with our address or
- * the broadcast address. Save the Ether type in arg 5.
- * NOTE: Caller must leave room for the Ether header.
+ * the broadcast address. Save the Ether type in etype.
+ * Unless there is an error, we pass the whole packet and the unencapsulated
+ * data.
*/
ssize_t
-readether(d, pkt, len, tleft, etype)
- struct iodesc *d;
- void *pkt;
- size_t len;
- time_t tleft;
- u_int16_t *etype;
+readether(struct iodesc *d, void **pkt, void **payload, time_t tleft,
+ uint16_t *etype)
{
ssize_t n;
struct ether_header *eh;
+ void *ptr;
#ifdef ETHER_DEBUG
if (debug)
printf("readether: called\n");
#endif
- eh = (struct ether_header *)pkt - 1;
- len += sizeof(*eh);
-
- n = netif_get(d, eh, len, tleft);
- if (n == -1 || n < sizeof(*eh))
+ ptr = NULL;
+ n = netif_get(d, &ptr, tleft);
+ if (n == -1 || n < sizeof(*eh)) {
+ free(ptr);
return (-1);
+ }
+ eh = (struct ether_header *)((uintptr_t)ptr + 2);
/* Validate Ethernet address. */
if (bcmp(d->myea, eh->ether_dhost, 6) != 0 &&
bcmp(bcea, eh->ether_dhost, 6) != 0) {
@@ -120,8 +114,12 @@
printf("readether: not ours (ea=%s)\n",
ether_sprintf(eh->ether_dhost));
#endif
+ free(ptr);
return (-1);
}
+
+ *pkt = ptr;
+ *payload = (void *)((uintptr_t)eh + sizeof(*eh));
*etype = ntohs(eh->ether_type);
n -= sizeof(*eh);
@@ -133,8 +131,7 @@
*/
static char digits[] = "0123456789abcdef";
char *
-ether_sprintf(ap)
- u_char *ap;
+ether_sprintf(u_char *ap)
{
int i;
static char etherbuf[18];
Index: lib/libstand/net.h
===================================================================
--- lib/libstand/net.h
+++ lib/libstand/net.h
@@ -107,16 +107,15 @@
/* Link functions: */
ssize_t sendether(struct iodesc *d, void *pkt, size_t len,
u_char *dea, int etype);
-ssize_t readether(struct iodesc *d, void *pkt, size_t len,
- time_t tleft, u_int16_t *etype);
+ssize_t readether(struct iodesc *, void **, void **, time_t, uint16_t *);
ssize_t sendudp(struct iodesc *, void *, size_t);
-ssize_t readudp(struct iodesc *, void *, size_t, time_t);
+ssize_t readudp(struct iodesc *, void **, void **, time_t);
ssize_t sendrecv(struct iodesc *,
- ssize_t (*)(struct iodesc *, void *, size_t),
+ ssize_t (*)(struct iodesc *, void *, size_t),
void *, size_t,
- ssize_t (*)(struct iodesc *, void *, size_t, time_t),
- void *, size_t);
+ ssize_t (*)(struct iodesc *, void **, void **, time_t),
+ void **, void **);
/* bootp/DHCP */
void bootp(int, int);
Index: lib/libstand/net.c
===================================================================
--- lib/libstand/net.c
+++ lib/libstand/net.c
@@ -70,10 +70,10 @@
*/
ssize_t
sendrecv(struct iodesc *d,
- ssize_t (*sproc)(struct iodesc *, void *, size_t),
- void *sbuf, size_t ssize,
- ssize_t (*rproc)(struct iodesc *, void *, size_t, time_t),
- void *rbuf, size_t rsize)
+ ssize_t (*sproc)(struct iodesc *, void *, size_t),
+ void *sbuf, size_t ssize,
+ ssize_t (*rproc)(struct iodesc *, void **, void **, time_t),
+ void **pkt, void **payload)
{
ssize_t cc;
time_t t, tmo, tlast;
@@ -116,7 +116,7 @@
}
/* Try to get a packet and process it. */
- cc = (*rproc)(d, rbuf, rsize, tleft);
+ cc = (*rproc)(d, pkt, payload, tleft);
/* Return on data, EOF or real error. */
if (cc != -1 || errno != 0)
return (cc);
Index: lib/libstand/netif.h
===================================================================
--- lib/libstand/netif.h
+++ lib/libstand/netif.h
@@ -6,15 +6,13 @@
#define __SYS_LIBNETBOOT_NETIF_H
#include "iodesc.h"
-#define NENTS(x) sizeof(x)/sizeof(x[0])
-
struct netif_driver {
const char *netif_bname;
int (*netif_match)(struct netif *, void *);
int (*netif_probe)(struct netif *, void *);
void (*netif_init)(struct iodesc *, void *);
- int (*netif_get)(struct iodesc *, void *, size_t, time_t);
- int (*netif_put)(struct iodesc *, void *, size_t);
+ ssize_t (*netif_get)(struct iodesc *, void **, time_t);
+ ssize_t (*netif_put)(struct iodesc *, void *, size_t);
void (*netif_end)(struct netif *);
struct netif_dif *netif_ifs;
int netif_nifs;
@@ -56,7 +54,7 @@
int netif_probe(struct netif *, void *);
void netif_attach(struct netif *, struct iodesc *, void *);
void netif_detach(struct netif *);
-ssize_t netif_get(struct iodesc *, void *, size_t, time_t);
+ssize_t netif_get(struct iodesc *, void **, time_t);
ssize_t netif_put(struct iodesc *, void *, size_t);
int netif_open(void *);
Index: lib/libstand/netif.c
===================================================================
--- lib/libstand/netif.c
+++ lib/libstand/netif.c
@@ -59,7 +59,7 @@
*/
void
-netif_init()
+netif_init(void)
{
struct netif_driver *drv;
int d, i;
@@ -76,13 +76,11 @@
}
int
-netif_match(nif, machdep_hint)
- struct netif *nif;
- void *machdep_hint;
+netif_match(struct netif *nif, void *machdep_hint)
{
struct netif_driver *drv = nif->nif_driver;
-#if 0
+#if NETIF_DEBUG
if (netif_debug)
printf("%s%d: netif_match (%d)\n", drv->netif_bname,
nif->nif_unit, nif->nif_sel);
@@ -91,8 +89,7 @@
}
struct netif *
-netif_select(machdep_hint)
- void *machdep_hint;
+netif_select(void *machdep_hint)
{
int d, u, unit_done, s;
struct netif_driver *drv;
@@ -162,9 +159,7 @@
}
int
-netif_probe(nif, machdep_hint)
- struct netif *nif;
- void *machdep_hint;
+netif_probe(struct netif *nif, void *machdep_hint)
{
struct netif_driver *drv = nif->nif_driver;
@@ -176,10 +171,7 @@
}
void
-netif_attach(nif, desc, machdep_hint)
- struct netif *nif;
- struct iodesc *desc;
- void *machdep_hint;
+netif_attach(struct netif *nif, struct iodesc *desc, void *machdep_hint)
{
struct netif_driver *drv = nif->nif_driver;
@@ -199,8 +191,7 @@
}
void
-netif_detach(nif)
- struct netif *nif;
+netif_detach(struct netif *nif)
{
struct netif_driver *drv = nif->nif_driver;
@@ -217,11 +208,7 @@
}
ssize_t
-netif_get(desc, pkt, len, timo)
- struct iodesc *desc;
- void *pkt;
- size_t len;
- time_t timo;
+netif_get(struct iodesc *desc, void **pkt, time_t timo)
{
#ifdef NETIF_DEBUG
struct netif *nif = desc->io_netif;
@@ -238,20 +225,17 @@
panic("%s%d: no netif_get support\n", drv->netif_bname,
nif->nif_unit);
#endif
- rv = drv->netif_get(desc, pkt, len, timo);
+ rv = drv->netif_get(desc, pkt, timo);
#ifdef NETIF_DEBUG
if (netif_debug)
printf("%s%d: netif_get returning %d\n", drv->netif_bname,
nif->nif_unit, (int)rv);
#endif
- return rv;
+ return (rv);
}
ssize_t
-netif_put(desc, pkt, len)
- struct iodesc *desc;
- void *pkt;
- size_t len;
+netif_put(struct iodesc *desc, void *pkt, size_t len)
{
#ifdef NETIF_DEBUG
struct netif *nif = desc->io_netif;
@@ -274,12 +258,11 @@
printf("%s%d: netif_put returning %d\n", drv->netif_bname,
nif->nif_unit, (int)rv);
#endif
- return rv;
+ return (rv);
}
struct iodesc *
-socktodesc(sock)
- int sock;
+socktodesc(int sock)
{
if (sock >= SOPEN_MAX) {
errno = EBADF;
@@ -289,8 +272,7 @@
}
int
-netif_open(machdep_hint)
- void *machdep_hint;
+netif_open(void *machdep_hint)
{
int fd;
struct iodesc *s;
@@ -313,23 +295,22 @@
printf("netboot: couldn't probe %s%d\n",
nif->nif_driver->netif_bname, nif->nif_unit);
errno = EINVAL;
- return(-1);
+ return (-1);
}
netif_attach(nif, s, machdep_hint);
- return(fd);
+ return (fd);
}
int
-netif_close(sock)
- int sock;
+netif_close(int sock)
{
if (sock >= SOPEN_MAX) {
errno = EBADF;
- return(-1);
+ return (-1);
}
netif_detach(sockets[sock].io_netif);
sockets[sock].io_netif = (struct netif *)0;
- return(0);
+ return (0);
}
Index: lib/libstand/nfs.c
===================================================================
--- lib/libstand/nfs.c
+++ lib/libstand/nfs.c
@@ -185,6 +185,7 @@
int
nfs_getrootfh(struct iodesc *d, char *path, uint32_t *fhlenp, u_char *fhp)
{
+ void *pkt = NULL;
int len;
struct args {
uint32_t len;
@@ -201,10 +202,6 @@
uint32_t h[RPC_HEADER_WORDS];
struct args d;
} sdata;
- struct {
- uint32_t h[RPC_HEADER_WORDS];
- struct repl d;
- } rdata;
size_t cc;
#ifdef NFS_DEBUG
@@ -213,7 +210,6 @@
#endif
args = &sdata.d;
- repl = &rdata.d;
bzero(args, sizeof(*args));
len = strlen(path);
@@ -224,18 +220,25 @@
len = sizeof(uint32_t) + roundup(len, sizeof(uint32_t));
cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER3, RPCMNT_MOUNT,
- args, len, repl, sizeof(*repl));
- if (cc == -1)
+ args, len, (void **)&repl, &pkt);
+ if (cc == -1) {
+ free(pkt);
/* errno was set by rpc_call */
return (errno);
- if (cc < 2 * sizeof (uint32_t))
+ }
+ if (cc < 2 * sizeof (uint32_t)) {
+ free(pkt);
return (EBADRPC);
- if (repl->errno != 0)
+ }
+ if (repl->errno != 0) {
+ free(pkt);
return (ntohl(repl->errno));
+ }
*fhlenp = ntohl(repl->fhsize);
bcopy(repl->fh, fhp, *fhlenp);
set_nfs_read_size();
+ free(pkt);
return (0);
}
@@ -246,6 +249,7 @@
int
nfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd)
{
+ void *pkt = NULL;
int len, rlen, pos;
struct args {
uint32_t fhsize;
@@ -263,10 +267,6 @@
uint32_t h[RPC_HEADER_WORDS];
struct args d;
} sdata;
- struct {
- uint32_t h[RPC_HEADER_WORDS];
- struct repl d;
- } rdata;
ssize_t cc;
#ifdef NFS_DEBUG
@@ -275,7 +275,6 @@
#endif
args = &sdata.d;
- repl = &rdata.d;
bzero(args, sizeof(*args));
args->fhsize = htonl(d->fhsize);
@@ -289,23 +288,30 @@
len = sizeof(uint32_t) + pos * sizeof(uint32_t) +
roundup(len, sizeof(uint32_t));
- rlen = sizeof(*repl);
-
cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_LOOKUP,
- args, len, repl, rlen);
- if (cc == -1)
+ args, len, (void **)&repl, &pkt);
+ if (cc == -1) {
+ free(pkt);
return (errno); /* XXX - from rpc_call */
- if (cc < 2 * sizeof(uint32_t))
+ }
+ if (cc < 2 * sizeof(uint32_t)) {
+ free(pkt);
return (EIO);
- if (repl->errno != 0)
+ }
+ if (repl->errno != 0) {
+ free(pkt);
/* saerrno.h now matches NFS error numbers. */
return (ntohl(repl->errno));
+ }
newfd->fhsize = ntohl(repl->fhsize);
bcopy(repl->fhplusattr, &newfd->fh, newfd->fhsize);
pos = roundup(newfd->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
- if (repl->fhplusattr[pos++] == 0)
+ if (repl->fhplusattr[pos++] == 0) {
+ free(pkt);
return (EIO);
+ }
bcopy(&repl->fhplusattr[pos], &newfd->fa, sizeof(newfd->fa));
+ free(pkt);
return (0);
}
@@ -316,6 +322,7 @@
int
nfs_readlink(struct nfs_iodesc *d, char *buf)
{
+ void *pkt = NULL;
struct args {
uint32_t fhsize;
u_char fh[NFS_V3MAXFHSIZE];
@@ -331,11 +338,8 @@
uint32_t h[RPC_HEADER_WORDS];
struct args d;
} sdata;
- struct {
- uint32_t h[RPC_HEADER_WORDS];
- struct repl d;
- } rdata;
ssize_t cc;
+ int rc = 0;
#ifdef NFS_DEBUG
if (debug)
@@ -343,32 +347,41 @@
#endif
args = &sdata.d;
- repl = &rdata.d;
bzero(args, sizeof(*args));
args->fhsize = htonl(d->fhsize);
bcopy(d->fh, args->fh, d->fhsize);
cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READLINK,
args, sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)),
- repl, sizeof(*repl));
+ (void **)&repl, &pkt);
if (cc == -1)
return (errno);
- if (cc < 2 * sizeof(uint32_t))
- return (EIO);
+ if (cc < 2 * sizeof(uint32_t)) {
+ rc = EIO;
+ goto done;
+ }
- if (repl->errno != 0)
- return (ntohl(repl->errno));
+ if (repl->errno != 0) {
+ rc = ntohl(repl->errno);
+ goto done;
+ }
- if (repl->ok == 0)
- return (EIO);
+ if (repl->ok == 0) {
+ rc = EIO;
+ goto done;
+ }
repl->len = ntohl(repl->len);
- if (repl->len > NFS_MAXPATHLEN)
- return (ENAMETOOLONG);
+ if (repl->len > NFS_MAXPATHLEN) {
+ rc = ENAMETOOLONG;
+ goto done;
+ }
bcopy(repl->path, buf, repl->len);
buf[repl->len] = 0;
+done:
+ free(pkt);
return (0);
}
#endif
@@ -380,6 +393,7 @@
ssize_t
nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len)
{
+ void *pkt = NULL;
struct args {
uint32_t fhsize;
uint32_t fhoffcnt[NFS_V3MAXFHSIZE / sizeof(uint32_t) + 3];
@@ -397,16 +411,11 @@
uint32_t h[RPC_HEADER_WORDS];
struct args d;
} sdata;
- struct {
- uint32_t h[RPC_HEADER_WORDS];
- struct repl d;
- } rdata;
size_t cc;
long x;
int hlen, rlen, pos;
args = &sdata.d;
- repl = &rdata.d;
bzero(args, sizeof(*args));
args->fhsize = htonl(d->fhsize);
@@ -421,16 +430,19 @@
cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READ,
args, 4 * sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)),
- repl, sizeof(*repl));
- if (cc == -1)
+ (void **)&repl, &pkt);
+ if (cc == -1) {
/* errno was already set by rpc_call */
return (-1);
+ }
if (cc < hlen) {
errno = EBADRPC;
+ free(pkt);
return (-1);
}
if (repl->errno != 0) {
errno = ntohl(repl->errno);
+ free(pkt);
return (-1);
}
rlen = cc - hlen;
@@ -438,9 +450,11 @@
if (rlen < x) {
printf("nfsread: short packet, %d < %ld\n", rlen, x);
errno = EBADRPC;
+ free(pkt);
return (-1);
}
bcopy(repl->data, addr, x);
+ free(pkt);
return (x);
}
@@ -481,17 +495,8 @@
return (ENXIO);
}
- /*
- * This is silly - we should look at dv_type but that value is
- * arch dependant and we can't use it here.
- */
-#ifndef __i386__
- if (strcmp(f->f_dev->dv_name, "net") != 0)
+ if (f->f_dev->dv_type != DEVT_NET)
return (EINVAL);
-#else
- if (strcmp(f->f_dev->dv_name, "pxe") != 0)
- return (EINVAL);
-#endif
if (!(desc = socktodesc(*(int *)(f->f_devdata))))
return (EINVAL);
@@ -660,9 +665,8 @@
printf("nfs_close: fp=0x%lx\n", (u_long)fp);
#endif
- if (fp)
- free(fp);
- f->f_fsdata = (void *)0;
+ free(fp);
+ f->f_fsdata = NULL;
return (0);
}
@@ -773,6 +777,7 @@
struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
struct nfsv3_readdir_repl *repl;
struct nfsv3_readdir_entry *rent;
+ static void *pkt = NULL;
static char *buf;
static struct nfs_iodesc *pfp = NULL;
static uint64_t cookie = 0;
@@ -787,14 +792,12 @@
uint32_t h[RPC_HEADER_WORDS];
struct args d;
} sdata;
- static struct {
- uint32_t h[RPC_HEADER_WORDS];
- u_char d[NFS_READDIRSIZE];
- } rdata;
if (fp != pfp || fp->off != cookie) {
pfp = NULL;
refill:
+ free(pkt);
+ pkt = NULL;
args = &sdata.d;
bzero(args, sizeof(*args));
@@ -810,11 +813,23 @@
cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READDIR,
args, 6 * sizeof(uint32_t) +
roundup(fp->fhsize, sizeof(uint32_t)),
- rdata.d, sizeof(rdata.d));
- buf = rdata.d;
+ (void **)&buf, &pkt);
+ if (cc == -1) {
+ free(pkt);
+ pkt = NULL;
+ pfp = NULL;
+ cookie = 0;
+ return (errno);
+ }
repl = (struct nfsv3_readdir_repl *)buf;
- if (repl->errno != 0)
- return (ntohl(repl->errno));
+ if (repl->errno != 0) {
+ int rc = ntohl(repl->errno);
+ free(pkt);
+ pkt = NULL;
+ pfp = NULL;
+ cookie = 0;
+ return (rc);
+ }
pfp = fp;
cookie = fp->off;
fp->cookie = ((uint64_t)ntohl(repl->cookiev0) << 32) |
@@ -826,6 +841,9 @@
if (rent->follows == 0) {
/* fid0 is actually eof */
if (rent->fid0 != 0) {
+ free(pkt);
+ pkt = NULL;
+ pfp = NULL;
cookie = 0;
return (ENOENT);
}
Index: lib/libstand/rarp.c
===================================================================
--- lib/libstand/rarp.c
+++ lib/libstand/rarp.c
@@ -54,17 +54,17 @@
static ssize_t rarpsend(struct iodesc *, void *, size_t);
-static ssize_t rarprecv(struct iodesc *, void *, size_t, time_t);
+static ssize_t rarprecv(struct iodesc *, void **, void **, time_t);
/*
* Ethernet (Reverse) Address Resolution Protocol (see RFC 903, and 826).
*/
int
-rarp_getipaddress(sock)
- int sock;
+rarp_getipaddress(int sock)
{
struct iodesc *d;
struct ether_arp *ap;
+ void *pkt;
struct {
u_char header[ETHER_SIZE];
struct {
@@ -72,13 +72,6 @@
u_char pad[18]; /* 60 - sizeof(arp) */
} data;
} wbuf;
- struct {
- u_char header[ETHER_SIZE];
- struct {
- struct ether_arp arp;
- u_char pad[24]; /* extra space */
- } data;
- } rbuf;
#ifdef RARP_DEBUG
if (debug)
@@ -102,21 +95,21 @@
ap->arp_op = htons(ARPOP_REVREQUEST);
bcopy(d->myea, ap->arp_sha, 6);
bcopy(d->myea, ap->arp_tha, 6);
+ pkt = NULL;
if (sendrecv(d,
rarpsend, &wbuf.data, sizeof(wbuf.data),
- rarprecv, &rbuf.data, sizeof(rbuf.data)) < 0)
- {
+ rarprecv, &pkt, (void *)&ap) < 0) {
printf("No response for RARP request\n");
return (-1);
}
- ap = &rbuf.data.arp;
bcopy(ap->arp_tpa, (char *)&myip, sizeof(myip));
#if 0
/* XXX - Can NOT assume this is our root server! */
bcopy(ap->arp_spa, (char *)&rootip, sizeof(rootip));
#endif
+ free(pkt);
/* Compute our "natural" netmask. */
if (IN_CLASSA(myip.s_addr))
@@ -134,10 +127,7 @@
* Broadcast a RARP request (i.e. who knows who I am)
*/
static ssize_t
-rarpsend(d, pkt, len)
- struct iodesc *d;
- void *pkt;
- size_t len;
+rarpsend(struct iodesc *d, void *pkt, size_t len)
{
#ifdef RARP_DEBUG
@@ -153,28 +143,26 @@
* else -1 (and errno == 0)
*/
static ssize_t
-rarprecv(d, pkt, len, tleft)
- struct iodesc *d;
- void *pkt;
- size_t len;
- time_t tleft;
+rarprecv(struct iodesc *d, void **pkt, void **payload, time_t tleft)
{
ssize_t n;
struct ether_arp *ap;
- u_int16_t etype; /* host order */
+ void *ptr = NULL;
+ uint16_t etype; /* host order */
#ifdef RARP_DEBUG
if (debug)
printf("rarprecv: ");
#endif
- n = readether(d, pkt, len, tleft, &etype);
+ n = readether(d, ptr, (void **)&ap, tleft, &etype);
errno = 0; /* XXX */
if (n == -1 || n < sizeof(struct ether_arp)) {
#ifdef RARP_DEBUG
if (debug)
printf("bad len=%d\n", n);
#endif
+ free(ptr);
return (-1);
}
@@ -183,10 +171,10 @@
if (debug)
printf("bad type=0x%x\n", etype);
#endif
+ free(ptr);
return (-1);
}
- ap = (struct ether_arp *)pkt;
if (ap->arp_hrd != htons(ARPHRD_ETHER) ||
ap->arp_pro != htons(ETHERTYPE_IP) ||
ap->arp_hln != sizeof(ap->arp_sha) ||
@@ -196,6 +184,7 @@
if (debug)
printf("bad hrd/pro/hln/pln\n");
#endif
+ free(ptr);
return (-1);
}
@@ -204,6 +193,7 @@
if (debug)
printf("bad op=0x%x\n", ntohs(ap->arp_op));
#endif
+ free(ptr);
return (-1);
}
@@ -213,6 +203,7 @@
if (debug)
printf("unwanted address\n");
#endif
+ free(ptr);
return (-1);
}
@@ -221,5 +212,7 @@
if (debug)
printf("got it\n");
#endif
+ *pkt = ptr;
+ *payload = ap;
return (n);
}
Index: lib/libstand/rpc.h
===================================================================
--- lib/libstand/rpc.h
+++ lib/libstand/rpc.h
@@ -48,7 +48,7 @@
/* RPC functions: */
ssize_t rpc_call(struct iodesc *, n_long, n_long, n_long,
- void *, size_t, void *, size_t);
+ void *, size_t, void **, void **);
void rpc_fromaddr(void *, struct in_addr *, u_short *);
int rpc_pmap_getcache(struct in_addr, u_int, u_int);
void rpc_pmap_putcache(struct in_addr, u_int, u_int, int);
Index: lib/libstand/rpc.c
===================================================================
--- lib/libstand/rpc.c
+++ lib/libstand/rpc.c
@@ -97,7 +97,7 @@
};
/* Local forwards */
-static ssize_t recvrpc(struct iodesc *, void *, size_t, time_t);
+static ssize_t recvrpc(struct iodesc *, void **, void **, time_t);
static int rpc_getport(struct iodesc *, n_long, n_long);
int rpc_xid;
@@ -109,14 +109,14 @@
*/
ssize_t
rpc_call(struct iodesc *d, n_long prog, n_long vers, n_long proc,
- void *sdata, size_t slen, void *rdata, size_t rlen)
+ void *sdata, size_t slen, void **rdata, void **pkt)
{
- ssize_t cc;
+ ssize_t cc, rsize;
struct auth_info *auth;
struct rpc_call *call;
struct rpc_reply *reply;
char *send_head, *send_tail;
- char *recv_head, *recv_tail;
+ void *ptr;
n_long x;
int port; /* host order */
@@ -145,7 +145,6 @@
auth->authtype = htonl(RPCAUTH_NULL);
auth->authlen = 0;
-#if 1
/* Auth credentials: always auth unix (as root) */
send_head -= sizeof(struct auth_unix);
bzero(send_head, sizeof(struct auth_unix));
@@ -153,13 +152,6 @@
auth = (struct auth_info *)send_head;
auth->authtype = htonl(RPCAUTH_UNIX);
auth->authlen = htonl(sizeof(struct auth_unix));
-#else
- /* Auth credentials: always auth_null (XXX OK?) */
- send_head -= sizeof(*auth);
- auth = send_head;
- auth->authtype = htonl(RPCAUTH_NULL);
- auth->authlen = 0;
-#endif
/* RPC call structure. */
send_head -= sizeof(*call);
@@ -172,34 +164,28 @@
call->rp_vers = htonl(vers);
call->rp_proc = htonl(proc);
- /* Make room for the rpc_reply header. */
- recv_head = rdata;
- recv_tail = (char *)rdata + rlen;
- recv_head -= sizeof(*reply);
-
+ ptr = NULL;
cc = sendrecv(d,
sendudp, send_head, send_tail - send_head,
- recvrpc, recv_head, recv_tail - recv_head);
+ recvrpc, &ptr, (void **)&reply);
#ifdef RPC_DEBUG
if (debug)
- printf("callrpc: cc=%ld rlen=%lu\n", (long)cc, (u_long)rlen);
+ printf("callrpc: cc=%zd\n", cc);
#endif
if (cc == -1)
return (-1);
if (cc <= sizeof(*reply)) {
errno = EBADRPC;
+ free(ptr);
return (-1);
}
- recv_tail = recv_head + cc;
-
/*
* Check the RPC reply status.
* The xid, dir, astatus were already checked.
*/
- reply = (struct rpc_reply *)recv_head;
auth = &reply->rp_u.rpu_rok.rok_auth;
x = ntohl(auth->authlen);
if (x != 0) {
@@ -208,17 +194,21 @@
printf("callrpc: reply auth != NULL\n");
#endif
errno = EBADRPC;
- return(-1);
+ free(ptr);
+ return (-1);
}
x = ntohl(reply->rp_u.rpu_rok.rok_status);
if (x != 0) {
printf("callrpc: error = %ld\n", (long)x);
errno = EBADRPC;
- return(-1);
+ free(ptr);
+ return (-1);
}
- recv_head += sizeof(*reply);
- return (ssize_t)(recv_tail - recv_head);
+ rsize = cc - sizeof(*reply);
+ *rdata = (void *)((uintptr_t)reply + sizeof(*reply));
+ *pkt = ptr;
+ return (rsize);
}
/*
@@ -227,8 +217,9 @@
* Remaining checks are done by callrpc
*/
static ssize_t
-recvrpc(struct iodesc *d, void *pkt, size_t len, time_t tleft)
+recvrpc(struct iodesc *d, void **pkt, void **payload, time_t tleft)
{
+ void *ptr;
struct rpc_reply *reply;
ssize_t n;
int x;
@@ -236,14 +227,15 @@
errno = 0;
#ifdef RPC_DEBUG
if (debug)
- printf("recvrpc: called len=%lu\n", (u_long)len);
+ printf("recvrpc: called\n");
#endif
- n = readudp(d, pkt, len, tleft);
- if (n <= (4 * 4))
- return -1;
-
- reply = (struct rpc_reply *)pkt;
+ ptr = NULL;
+ n = readudp(d, &ptr, (void **)&reply, tleft);
+ if (n <= (4 * 4)) {
+ free(ptr);
+ return (-1);
+ }
x = ntohl(reply->rp_xid);
if (x != rpc_xid) {
@@ -251,7 +243,8 @@
if (debug)
printf("recvrpc: rp_xid %d != xid %d\n", x, rpc_xid);
#endif
- return -1;
+ free(ptr);
+ return (-1);
}
x = ntohl(reply->rp_direction);
@@ -260,16 +253,20 @@
if (debug)
printf("recvrpc: rp_direction %d != REPLY\n", x);
#endif
- return -1;
+ free(ptr);
+ return (-1);
}
x = ntohl(reply->rp_astatus);
if (x != RPC_MSGACCEPTED) {
errno = ntohl(reply->rp_u.rpu_errno);
printf("recvrpc: reject, astat=%d, errno=%d\n", x, errno);
- return -1;
+ free(ptr);
+ return (-1);
}
+ *pkt = ptr;
+ *payload = reply;
/* Return data count (thus indicating success) */
return (n);
}
@@ -387,11 +384,7 @@
n_long h[RPC_HEADER_WORDS];
struct args d;
} sdata;
- struct {
- n_long h[RPC_HEADER_WORDS];
- struct res d;
- n_long pad;
- } rdata;
+ void *pkt;
ssize_t cc;
int port;
@@ -416,16 +409,18 @@
args->vers = htonl(vers);
args->proto = htonl(IPPROTO_UDP);
args->port = 0;
- res = &rdata.d;
+ pkt = NULL;
cc = rpc_call(d, PMAPPROG, PMAPVERS, PMAPPROC_GETPORT,
- args, sizeof(*args), res, sizeof(*res));
+ args, sizeof(*args), (void **)&res, &pkt);
if (cc < sizeof(*res)) {
printf("getport: %s", strerror(errno));
errno = EBADRPC;
+ free(pkt);
return (-1);
}
port = (int)ntohl(res->port);
+ free(pkt);
rpc_pmap_putcache(d->destip, prog, vers, port);
Index: lib/libstand/tftp.c
===================================================================
--- lib/libstand/tftp.c
+++ lib/libstand/tftp.c
@@ -73,8 +73,8 @@
static ssize_t sendrecv_tftp(struct tftp_handle *h,
ssize_t (*sproc)(struct iodesc *, void *, size_t),
void *sbuf, size_t ssize,
- ssize_t (*rproc)(struct tftp_handle *h, void *, ssize_t, time_t, unsigned short *),
- void *rbuf, size_t rsize, unsigned short *rtype);
+ ssize_t (*rproc)(struct tftp_handle *h, void **, void **, time_t, unsigned short *),
+ void **, void **, unsigned short *rtype);
struct fs_ops tftp_fsops = {
"tftp",
@@ -114,11 +114,8 @@
char *path; /* saved for re-requests */
unsigned int tftp_blksize;
unsigned long tftp_tsize;
- struct {
- u_char header[HEADER_SIZE];
- struct tftphdr t;
- u_char space[TFTP_MAX_BLKSIZE];
- } __packed __aligned(4) lastdata;
+ void *pkt;
+ struct tftphdr *tftp_hdr;
};
#define TFTP_MAX_ERRCODE EOPTNEG
@@ -181,20 +178,23 @@
}
static ssize_t
-recvtftp(struct tftp_handle *h, void *pkt, ssize_t len, time_t tleft,
+recvtftp(struct tftp_handle *h, void **pkt, void **payload, time_t tleft,
unsigned short *rtype)
{
struct iodesc *d = h->iodesc;
struct tftphdr *t;
+ void *ptr = NULL;
+ ssize_t len;
errno = 0;
- len = readudp(d, pkt, len, tleft);
+ len = readudp(d, &ptr, (void **)&t, tleft);
- if (len < 4)
+ if (len < 4) {
+ free(ptr);
return (-1);
+ }
- t = (struct tftphdr *) pkt;
*rtype = ntohs(t->th_opcode);
switch (ntohs(t->th_opcode)) {
case DATA: {
@@ -204,6 +204,7 @@
/*
* Expected block?
*/
+ free(ptr);
return (-1);
}
if (d->xid == 1) {
@@ -211,11 +212,13 @@
* First data packet from new port.
*/
struct udphdr *uh;
- uh = (struct udphdr *) pkt - 1;
+ uh = (struct udphdr *) t - 1;
d->destport = uh->uh_sport;
} /* else check uh_sport has not changed??? */
- got = len - (t->th_data - (char *) t);
- return got;
+ got = len - (t->th_data - (char *)t);
+ *pkt = ptr;
+ *payload = t;
+ return (got);
}
case ERROR:
if ((unsigned) ntohs(t->th_code) > TFTP_MAX_ERRCODE) {
@@ -227,6 +230,7 @@
#endif
errno = tftperrors[ntohs(t->th_code)];
}
+ free(ptr);
return (-1);
case OACK: {
struct udphdr *uh;
@@ -237,6 +241,7 @@
* Drop the pkt.
*/
if (d->xid != 1) {
+ free(ptr);
return (-1);
}
@@ -244,7 +249,7 @@
* Remember which port this OACK came from, because we need
* to send the ACK or errors back to it.
*/
- uh = (struct udphdr *) pkt - 1;
+ uh = (struct udphdr *) t - 1;
d->destport = uh->uh_sport;
/* Parse options ACK-ed by the server. */
@@ -252,14 +257,18 @@
if (tftp_parse_oack(h, t->th_u.tu_stuff, tftp_oack_len) != 0) {
tftp_senderr(h, EOPTNEG, "Malformed OACK");
errno = EIO;
+ free(ptr);
return (-1);
}
+ *pkt = ptr;
+ *payload = t;
return (0);
}
default:
#ifdef TFTP_DEBUG
printf("tftp type %d not handled\n", ntohs(t->th_opcode));
#endif
+ free(ptr);
return (-1);
}
}
@@ -276,6 +285,7 @@
char *wtail;
int l;
ssize_t res;
+ void *pkt;
struct tftphdr *t;
char *tftp_blksize = NULL;
int blksize_l;
@@ -314,8 +324,6 @@
bcopy("0", wtail, 2);
wtail += 2;
- t = &h->lastdata.t;
-
/* h->iodesc->myport = htons(--tftpport); */
h->iodesc->myport = htons(tftpport + (getsecs() & 0x3ff));
h->iodesc->destport = htons(IPPORT_TFTP);
@@ -325,8 +333,17 @@
h->islastblock = 0;
h->validsize = 0;
+ pkt = NULL;
res = sendrecv_tftp(h, &sendudp, &wbuf.t, wtail - (char *) &wbuf.t,
- &recvtftp, t, sizeof(*t) + h->tftp_blksize, &rtype);
+ &recvtftp, &pkt, (void **)&t, &rtype);
+ if (res == -1) {
+ free(pkt);
+ return (errno);
+ }
+
+ free(h->pkt);
+ h->pkt = pkt;
+ h->tftp_hdr = t;
if (rtype == OACK)
return (tftp_getnextblock(h));
@@ -362,6 +379,7 @@
} __packed __aligned(4) wbuf;
char *wtail;
int res;
+ void *pkt;
struct tftphdr *t;
unsigned short rtype = 0;
wbuf.t.th_opcode = htons((u_short) ACK);
@@ -369,16 +387,20 @@
wbuf.t.th_block = htons((u_short) h->currblock);
wtail += 2;
- t = &h->lastdata.t;
-
h->iodesc->xid = h->currblock + 1; /* expected block */
+ pkt = NULL;
res = sendrecv_tftp(h, &sendudp, &wbuf.t, wtail - (char *) &wbuf.t,
- &recvtftp, t, sizeof(*t) + h->tftp_blksize, &rtype);
+ &recvtftp, &pkt, (void **)&t, &rtype);
- if (res == -1) /* 0 is OK! */
+ if (res == -1) { /* 0 is OK! */
+ free(pkt);
return (errno);
+ }
+ free(h->pkt);
+ h->pkt = pkt;
+ h->tftp_hdr = t;
h->currblock++;
h->validsize = res;
if (res < h->tftp_blksize)
@@ -405,14 +427,8 @@
if (netproto != NET_TFTP)
return (EINVAL);
- if (strcmp(f->f_dev->dv_name, "net") != 0) {
-#ifdef __i386__
- if (strcmp(f->f_dev->dv_name, "pxe") != 0)
- return (EINVAL);
-#else
+ if (f->f_dev->dv_type != DEVT_NET)
return (EINVAL);
-#endif
- }
if (is_open)
return (EBUSY);
@@ -507,7 +523,7 @@
return (EINVAL);
}
count = (size < inbuffer ? size : inbuffer);
- bcopy(tftpfile->lastdata.t.th_data + offinblock,
+ bcopy(tftpfile->tftp_hdr->th_data + offinblock,
addr, count);
addr = (char *)addr + count;
@@ -540,6 +556,7 @@
if (tftpfile) {
free(tftpfile->path);
+ free(tftpfile->pkt);
free(tftpfile);
}
is_open = 0;
@@ -591,8 +608,9 @@
sendrecv_tftp(struct tftp_handle *h,
ssize_t (*sproc)(struct iodesc *, void *, size_t),
void *sbuf, size_t ssize,
- ssize_t (*rproc)(struct tftp_handle *, void *, ssize_t, time_t, unsigned short *),
- void *rbuf, size_t rsize, unsigned short *rtype)
+ ssize_t (*rproc)(struct tftp_handle *, void **, void **, time_t,
+ unsigned short *),
+ void **pkt, void **payload, unsigned short *rtype)
{
struct iodesc *d = h->iodesc;
ssize_t cc;
@@ -624,7 +642,7 @@
recvnext:
/* Try to get a packet and process it. */
- cc = (*rproc)(h, rbuf, rsize, tleft, rtype);
+ cc = (*rproc)(h, pkt, payload, tleft, rtype);
/* Return on data, EOF or real error. */
if (cc != -1 || errno != 0)
return (cc);
Index: lib/libstand/udp.c
===================================================================
--- lib/libstand/udp.c
+++ lib/libstand/udp.c
@@ -59,10 +59,7 @@
/* Caller must leave room for ethernet, ip and udp headers in front!! */
ssize_t
-sendudp(d, pkt, len)
- struct iodesc *d;
- void *pkt;
- size_t len;
+sendudp(struct iodesc *d, void *pkt, size_t len)
{
ssize_t cc;
struct ip *ip;
@@ -131,32 +128,29 @@
/*
* Receive a UDP packet and validate it is for us.
- * Caller leaves room for the headers (Ether, IP, UDP)
*/
ssize_t
-readudp(d, pkt, len, tleft)
- struct iodesc *d;
- void *pkt;
- size_t len;
- time_t tleft;
+readudp(struct iodesc *d, void **pkt, void **payload, time_t tleft)
{
ssize_t n;
size_t hlen;
struct ip *ip;
struct udphdr *uh;
- u_int16_t etype; /* host order */
+ uint16_t etype; /* host order */
+ void *ptr;
#ifdef NET_DEBUG
if (debug)
printf("readudp: called\n");
#endif
- uh = (struct udphdr *)pkt - 1;
- ip = (struct ip *)uh - 1;
-
- n = readether(d, ip, len + sizeof(*ip) + sizeof(*uh), tleft, &etype);
- if (n == -1 || n < sizeof(*ip) + sizeof(*uh))
- return -1;
+ ip = NULL;
+ ptr = NULL;
+ n = readether(d, &ptr, (void **)&ip, tleft, &etype);
+ if (n == -1 || n < sizeof(*ip) + sizeof(*uh)) {
+ free(ptr);
+ return (-1);
+ }
/* Ethernet address checks now in readether() */
@@ -167,7 +161,8 @@
/* Send ARP reply */
arp_reply(d, ah);
}
- return -1;
+ free(ptr);
+ return (-1);
}
if (etype != ETHERTYPE_IP) {
@@ -175,7 +170,8 @@
if (debug)
printf("readudp: not IP. ether_type=%x\n", etype);
#endif
- return -1;
+ free(ptr);
+ return (-1);
}
/* Check ip header */
@@ -185,7 +181,8 @@
if (debug)
printf("readudp: IP version or not UDP. ip_v=%d ip_p=%d\n", ip->ip_v, ip->ip_p);
#endif
- return -1;
+ free(ptr);
+ return (-1);
}
hlen = ip->ip_hl << 2;
@@ -195,7 +192,8 @@
if (debug)
printf("readudp: short hdr or bad cksum.\n");
#endif
- return -1;
+ free(ptr);
+ return (-1);
}
if (n < ntohs(ip->ip_len)) {
#ifdef NET_DEBUG
@@ -203,7 +201,8 @@
printf("readudp: bad length %d < %d.\n",
(int)n, ntohs(ip->ip_len));
#endif
- return -1;
+ free(ptr);
+ return (-1);
}
if (d->myip.s_addr && ip->ip_dst.s_addr != d->myip.s_addr) {
#ifdef NET_DEBUG
@@ -212,12 +211,14 @@
printf("%s\n", inet_ntoa(ip->ip_dst));
}
#endif
- return -1;
+ free(ptr);
+ return (-1);
}
+ uh = (struct udphdr *)((uintptr_t)ip + sizeof (*ip));
/* If there were ip options, make them go away */
if (hlen != sizeof(*ip)) {
- bcopy(((u_char *)ip) + hlen, uh, len - hlen);
+ bcopy(((u_char *)ip) + hlen, uh, uh->uh_ulen - hlen);
ip->ip_len = htons(sizeof(*ip));
n -= hlen - sizeof(*ip);
}
@@ -227,7 +228,8 @@
printf("readudp: bad dport %d != %d\n",
d->myport, ntohs(uh->uh_dport));
#endif
- return -1;
+ free(ptr);
+ return (-1);
}
#ifndef UDP_NO_CKSUM
@@ -238,7 +240,8 @@
n = ntohs(uh->uh_ulen) + sizeof(*ip);
if (n > RECV_SIZE - ETHER_SIZE) {
printf("readudp: huge packet, udp len %d\n", (int)n);
- return -1;
+ free(ptr);
+ return (-1);
}
/* Check checksum (must save and restore ip header) */
@@ -252,7 +255,8 @@
printf("readudp: bad cksum\n");
#endif
*ip = tip;
- return -1;
+ free(ptr);
+ return (-1);
}
*ip = tip;
}
@@ -263,10 +267,13 @@
printf("readudp: bad udp len %d < %d\n",
ntohs(uh->uh_ulen), (int)sizeof(*uh));
#endif
- return -1;
+ free(ptr);
+ return (-1);
}
n = (n > (ntohs(uh->uh_ulen) - sizeof(*uh))) ?
ntohs(uh->uh_ulen) - sizeof(*uh) : n;
+ *pkt = ptr;
+ *payload = (void *)((uintptr_t)uh + sizeof(*uh));
return (n);
}
Index: sys/boot/common/dev_net.c
===================================================================
--- sys/boot/common/dev_net.c
+++ sys/boot/common/dev_net.c
@@ -58,6 +58,7 @@
#include <netinet/in_systm.h>
#include <stand.h>
+#include <stddef.h>
#include <string.h>
#include <net.h>
#include <netif.h>
@@ -246,6 +247,8 @@
{
char buf[MAXHOSTNAMELEN];
n_long rootaddr, smask;
+ struct iodesc *d = socktodesc(sock);
+ extern struct in_addr servip;
#ifdef SUPPORT_BOOTP
/*
@@ -254,8 +257,26 @@
* be initialized. If any remain uninitialized, we will
* use RARP and RPC/bootparam (the Sun way) to get them.
*/
- if (try_bootp)
- bootp(sock, BOOTP_NONE);
+ if (try_bootp) {
+ int rc = -1;
+ if (bootp_response != NULL) {
+ rc = dhcp_try_rfc1048(bootp_response->bp_vend,
+ bootp_response_size -
+ offsetof(struct bootp, bp_vend));
+
+ if (servip.s_addr == 0)
+ servip = bootp_response->bp_siaddr;
+ if (rootip.s_addr == 0)
+ rootip = bootp_response->bp_siaddr;
+ if (gateip.s_addr == 0)
+ gateip = bootp_response->bp_giaddr;
+ if (myip.s_addr == 0)
+ myip = bootp_response->bp_yiaddr;
+ d->myip = myip;
+ }
+ if (rc < 0)
+ bootp(sock, BOOTP_NONE);
+ }
if (myip.s_addr != 0)
goto exit;
#ifdef NETIF_DEBUG
Index: sys/boot/efi/libefi/efinet.c
===================================================================
--- sys/boot/efi/libefi/efinet.c
+++ sys/boot/efi/libefi/efinet.c
@@ -44,11 +44,11 @@
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 +113,7 @@
return (0);
}
-static int
+static ssize_t
efinet_put(struct iodesc *desc, void *pkt, size_t len)
{
struct netif *nif = desc->io_netif;
@@ -125,14 +125,14 @@
if (net == NULL)
return (-1);
- status = net->Transmit(net, 0, len, pkt, 0, 0, 0);
+ status = net->Transmit(net, 0, len, pkt, NULL, NULL, NULL);
if (status != EFI_SUCCESS)
return (-1);
/* Wait for the buffer to be transmitted */
do {
buf = NULL; /* XXX Is this needed? */
- status = net->GetStatus(net, 0, &buf);
+ status = net->GetStatus(net, NULL, &buf);
/*
* XXX EFI1.1 and the E1000 card returns a different
* address than we gave. Sigh.
@@ -143,41 +143,42 @@
return ((status == EFI_SUCCESS) ? len : -1);
}
-static int
-efinet_get(struct iodesc *desc, void *pkt, size_t len, time_t timeout)
+static ssize_t
+efinet_get(struct iodesc *desc, void **pkt, time_t timeout)
{
struct netif *nif = desc->io_netif;
EFI_SIMPLE_NETWORK *net;
EFI_STATUS status;
UINTN bufsz;
time_t t;
- char buf[2048];
+ char *buf, *ptr;
+ ssize_t ret = -1;
net = nif->nif_devdata;
if (net == NULL)
- return (0);
+ return (ret);
+
+ bufsz = roundup2(net->Mode->MaxPacketSize, 64) + 256;
+ buf = malloc(bufsz + 2);
+ if (buf == NULL)
+ return (ret);
+ ptr = buf + 2;
t = time(0);
while ((time(0) - t) < timeout) {
- bufsz = sizeof(buf);
- status = net->Receive(net, 0, &bufsz, buf, 0, 0, 0);
+ status = net->Receive(net, 0, &bufsz, ptr, NULL, NULL, NULL);
if (status == EFI_SUCCESS) {
- /*
- * XXX EFI1.1 and the E1000 card trash our
- * workspace if we do not do this silly copy.
- * Either they are not respecting the len
- * value or do not like the alignment.
- */
- if (bufsz > len)
- bufsz = len;
- bcopy(buf, pkt, bufsz);
- return (bufsz);
+ *pkt = buf;
+ ret = (ssize_t)bufsz;
+ break;
}
if (status != EFI_NOT_READY)
- return (0);
+ break;
}
- return (0);
+ if (ret == -1)
+ free(buf);
+ return (ret);
}
static void
@@ -205,8 +206,8 @@
if (net->Mode->State == EfiSimpleNetworkStopped) {
status = net->Start(net);
if (status != EFI_SUCCESS) {
- printf("net%d: cannot start interface (status=%ld)\n",
- nif->nif_unit, (long)status);
+ printf("net%d: cannot start interface (status=%lu)\n",
+ nif->nif_unit, EFI_ERROR_CODE(status));
return;
}
}
@@ -214,8 +215,8 @@
if (net->Mode->State != EfiSimpleNetworkInitialized) {
status = net->Initialize(net, 0, 0);
if (status != EFI_SUCCESS) {
- printf("net%d: cannot init. interface (status=%ld)\n",
- nif->nif_unit, (long)status);
+ printf("net%d: cannot init. interface (status=%lu)\n",
+ nif->nif_unit, EFI_ERROR_CODE(status));
return;
}
}
@@ -224,10 +225,10 @@
UINT32 mask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |
EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;
- status = net->ReceiveFilters(net, mask, 0, FALSE, 0, 0);
+ status = net->ReceiveFilters(net, mask, 0, FALSE, 0, NULL);
if (status != EFI_SUCCESS) {
- printf("net%d: cannot set rx. filters (status=%ld)\n",
- nif->nif_unit, (long)status);
+ printf("net%d: cannot set rx. filters (status=%lu)\n",
+ nif->nif_unit, EFI_ERROR_CODE(status));
return;
}
}
@@ -280,10 +281,10 @@
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 @@
* 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];
Index: sys/boot/i386/libi386/pxe.h
===================================================================
--- sys/boot/i386/libi386/pxe.h
+++ sys/boot/i386/libi386/pxe.h
@@ -349,7 +349,7 @@
*/
# define PXENV_UNDI_ISR_OUT_DONE 0
# define PXENV_UNDI_ISR_OUT_TRANSMIT 2
-# define PXENV_UNDI_ISR_OUT_RECIEVE 3
+# define PXENV_UNDI_ISR_OUT_RECEIVE 3
# define PXENV_UNDI_ISR_OUT_BUSY 4
} PACKED t_PXENV_UNDI_ISR;
Index: sys/boot/i386/libi386/pxe.c
===================================================================
--- sys/boot/i386/libi386/pxe.c
+++ sys/boot/i386/libi386/pxe.c
@@ -30,11 +30,13 @@
__FBSDID("$FreeBSD$");
#include <stand.h>
+#include <stddef.h>
#include <string.h>
#include <stdarg.h>
#include <netinet/in_systm.h>
#include <netinet/in.h>
+#include <netinet/ip.h>
#include <netinet/udp.h>
#include <net.h>
@@ -53,17 +55,15 @@
* the PXE BIOS, and the data buffer is used to receive data from the PXE BIOS.
*/
#define PXE_BUFFER_SIZE 0x2000
-#define PXE_TFTP_BUFFER_SIZE 512
static char scratch_buffer[PXE_BUFFER_SIZE];
static char data_buffer[PXE_BUFFER_SIZE];
static pxenv_t *pxenv_p = NULL; /* PXENV+ */
static pxe_t *pxe_p = NULL; /* !PXE */
-static BOOTPLAYER bootplayer; /* PXE Cached information. */
+#ifdef PXE_DEBUG
static int pxe_debug = 0;
-static int pxe_sock = -1;
-static int pxe_opens = 0;
+#endif
void pxe_enable(void *pxeinfo);
static void (*pxe_call)(int func);
@@ -71,25 +71,17 @@
static void bangpxe_call(int func);
static int pxe_init(void);
-static int pxe_strategy(void *devdata, int flag, daddr_t dblk,
- size_t size, char *buf, size_t *rsize);
-static int pxe_open(struct open_file *f, ...);
-static int pxe_close(struct open_file *f);
static int pxe_print(int verbose);
static void pxe_cleanup(void);
-static void pxe_setnfshandle(char *rootpath);
static void pxe_perror(int error);
static int pxe_netif_match(struct netif *nif, void *machdep_hint);
static int pxe_netif_probe(struct netif *nif, void *machdep_hint);
static void pxe_netif_init(struct iodesc *desc, void *machdep_hint);
-static int pxe_netif_get(struct iodesc *desc, void *pkt, size_t len,
- time_t timeout);
-static int pxe_netif_put(struct iodesc *desc, void *pkt, size_t len);
+static ssize_t pxe_netif_get(struct iodesc *, void **, time_t);
+static ssize_t pxe_netif_put(struct iodesc *desc, void *pkt, size_t len);
static void pxe_netif_end(struct netif *nif);
-int nfs_getrootfh(struct iodesc*, char*, uint32_t*, u_char*);
-
extern struct netif_stats pxe_st[];
extern u_int16_t __bangpxeseg;
extern u_int16_t __bangpxeoff;
@@ -97,25 +89,24 @@
extern u_int16_t __pxenvseg;
extern u_int16_t __pxenvoff;
extern void __pxenventry(void);
-extern struct in_addr servip;
struct netif_dif pxe_ifs[] = {
/* dif_unit dif_nsel dif_stats dif_private */
{0, 1, &pxe_st[0], 0}
};
-struct netif_stats pxe_st[NENTS(pxe_ifs)];
+struct netif_stats pxe_st[nitems(pxe_ifs)];
struct netif_driver pxenetif = {
- "pxenet",
- pxe_netif_match,
- pxe_netif_probe,
- pxe_netif_init,
- pxe_netif_get,
- pxe_netif_put,
- pxe_netif_end,
- pxe_ifs,
- NENTS(pxe_ifs)
+ .netif_bname = "pxenet",
+ .netif_match = pxe_netif_match,
+ .netif_probe = pxe_netif_probe,
+ .netif_init = pxe_netif_init,
+ .netif_get = pxe_netif_get,
+ .netif_put = pxe_netif_put,
+ .netif_end = pxe_netif_end,
+ .netif_ifs = pxe_ifs,
+ .netif_nifs = nitems(pxe_ifs)
};
struct netif_driver *netif_drivers[] = {
@@ -124,15 +115,15 @@
};
struct devsw pxedisk = {
- "pxe",
- DEVT_NET,
- pxe_init,
- pxe_strategy,
- pxe_open,
- pxe_close,
- noioctl,
- pxe_print,
- pxe_cleanup
+ .dv_name = "net",
+ .dv_type = DEVT_NET,
+ .dv_init = pxe_init,
+ .dv_strategy = NULL, /* Will be set in pxe_init */
+ .dv_open = NULL, /* Will be set in pxe_init */
+ .dv_close = NULL, /* Will be set in pxe_init */
+ .dv_ioctl = noioctl,
+ .dv_print = pxe_print,
+ .dv_cleanup = pxe_cleanup
};
/*
@@ -160,6 +151,7 @@
int counter;
uint8_t checksum;
uint8_t *checkptr;
+ extern struct devsw netdev;
if (pxenv_p == NULL)
return (0);
@@ -215,7 +207,11 @@
break;
}
}
-
+
+ pxedisk.dv_open = netdev.dv_open;
+ pxedisk.dv_close = netdev.dv_close;
+ pxedisk.dv_strategy = netdev.dv_strategy;
+
printf("\nPXE version %d.%d, real mode entry point ",
(uint8_t) (pxenv_p->Version >> 8),
(uint8_t) (pxenv_p->Version & 0xFF));
@@ -236,192 +232,29 @@
pxe_p = NULL;
return (0);
}
- bcopy(PTOV((gci_p->Buffer.segment << 4) + gci_p->Buffer.offset),
- &bootplayer, gci_p->BufferSize);
- return (1);
-}
-
-
-static int
-pxe_strategy(void *devdata, int flag, daddr_t dblk, size_t size,
- char *buf, size_t *rsize)
-{
- return (EIO);
-}
-
-static int
-pxe_open(struct open_file *f, ...)
-{
- va_list args;
- char *devname; /* Device part of file name (or NULL). */
- char temp[FNAME_SIZE];
- int error = 0;
- int i;
-
- va_start(args, f);
- devname = va_arg(args, char*);
- va_end(args);
-
- /* On first open, do netif open, mount, etc. */
- if (pxe_opens == 0) {
- /* Find network interface. */
- if (pxe_sock < 0) {
- pxe_sock = netif_open(devname);
- if (pxe_sock < 0) {
- printf("pxe_open: netif_open() failed\n");
- return (ENXIO);
- }
- if (pxe_debug)
- printf("pxe_open: netif_open() succeeded\n");
-
- if (socktodesc(pxe_sock) == NULL) {
- printf("pxe_open: bad socket %d\n", pxe_sock);
- return (ENXIO);
- }
-
- }
- if (rootip.s_addr == 0) {
- /*
- * Try to extract the RFC1048 data from PXE.
- * If fail do a bootp/dhcp request to find out where our
- * NFS/TFTP server is. Even if we dont get back
- * the proper information, fall back to the server
- * which brought us to life and a default rootpath.
- */
-
- if (dhcp_try_rfc1048(bootplayer.vendor.d, BOOTP_DHCPVEND) < 0) {
- if (pxe_debug)
- printf("pxe_open: no RFC1048 data in PXE Cache\n");
- bootp(pxe_sock, BOOTP_PXE);
- } else if (pxe_debug) {
- printf("pxe_open: loaded RFC1048 data from PXE Cache\n");
- }
-
-#ifdef LOADER_TFTP_SUPPORT
- bootp(pxe_sock, BOOTP_PXE);
-#endif
- if (rootip.s_addr == 0)
- rootip.s_addr = bootplayer.sip;
- if (gateip.s_addr == 0)
- gateip.s_addr = bootplayer.gip;
- if (myip.s_addr == 0)
- myip.s_addr = bootplayer.yip;
- if (servip.s_addr == 0)
- servip = rootip;
-
- netproto = NET_NFS;
- if (tftpip.s_addr != 0) {
- netproto = NET_TFTP;
- rootip.s_addr = tftpip.s_addr;
- }
-
- if (netproto == NET_NFS && !rootpath[0])
- strcpy(rootpath, PXENFSROOTPATH);
-
- for (i = 0; rootpath[i] != '\0' && i < FNAME_SIZE; i++)
- if (rootpath[i] == ':')
- break;
- if (i && i != FNAME_SIZE && rootpath[i] == ':') {
- rootpath[i++] = '\0';
- if (inet_addr(&rootpath[0]) != INADDR_NONE)
- rootip.s_addr = inet_addr(&rootpath[0]);
- bcopy(&rootpath[i], &temp[0], strlen(&rootpath[i]) + 1);
- bcopy(&temp[0], &rootpath[0], strlen(&rootpath[i]) + 1);
- }
- setenv("boot.netif.ip", inet_ntoa(myip), 1);
- setenv("boot.netif.netmask", intoa(netmask), 1);
- setenv("boot.netif.gateway", inet_ntoa(gateip), 1);
- setenv("boot.netif.server", inet_ntoa(rootip), 1);
- if (bootplayer.Hardware == ETHER_TYPE) {
- sprintf(temp, "%6D", bootplayer.CAddr, ":");
- setenv("boot.netif.hwaddr", temp, 1);
- }
- if (intf_mtu != 0) {
- char mtu[16];
- snprintf(sizeof(mtu), mtu, "%u", intf_mtu);
- setenv("boot.netif.mtu", mtu, 1);
- }
- printf("pxe_open: server addr: %s\n", inet_ntoa(rootip));
- printf("pxe_open: server path: %s\n", rootpath);
- printf("pxe_open: gateway ip: %s\n", inet_ntoa(gateip));
- printf("pxe_open: my ip: %s\n", inet_ntoa(myip));
- printf("pxe_open: netmask: %s\n", intoa(netmask));
- printf("pxe_open: servip: %s\n", inet_ntoa(servip));
-
- if (netproto == NET_TFTP) {
- setenv("boot.tftproot.server", inet_ntoa(rootip), 1);
- setenv("boot.tftproot.path", rootpath, 1);
- } else if (netproto == NET_NFS) {
- setenv("boot.nfsroot.server", inet_ntoa(rootip), 1);
- setenv("boot.nfsroot.path", rootpath, 1);
- }
- setenv("dhcp.host-name", hostname, 1);
-
- setenv("pxeboot.ip", inet_ntoa(myip), 1);
- if (bootplayer.Hardware == ETHER_TYPE) {
- sprintf(temp, "%6D", bootplayer.CAddr, ":");
- setenv("pxeboot.hwaddr", temp, 1);
- }
- }
- }
- pxe_opens++;
- f->f_devdata = &pxe_sock;
- return (error);
-}
-
-static int
-pxe_close(struct open_file *f)
-{
-
-#ifdef PXE_DEBUG
- if (pxe_debug)
- printf("pxe_close: opens=%d\n", pxe_opens);
-#endif
-
- /* On last close, do netif close, etc. */
- f->f_devdata = NULL;
- /* Extra close call? */
- if (pxe_opens <= 0)
- return (0);
- pxe_opens--;
- /* Not last close? */
- if (pxe_opens > 0)
- return (0);
-
- if (netproto == NET_NFS) {
- /* get an NFS filehandle for our root filesystem */
- pxe_setnfshandle(rootpath);
- }
-
- if (pxe_sock >= 0) {
-
-#ifdef PXE_DEBUG
- if (pxe_debug)
- printf("pxe_close: calling netif_close()\n");
-#endif
- netif_close(pxe_sock);
- pxe_sock = -1;
+ free(bootp_response);
+ if ((bootp_response = malloc(gci_p->BufferSize)) != NULL) {
+ bootp_response_size = gci_p->BufferSize;
+ bcopy(PTOV((gci_p->Buffer.segment << 4) + gci_p->Buffer.offset),
+ bootp_response, bootp_response_size);
}
- return (0);
+ return (1);
}
static int
pxe_print(int verbose)
{
- char line[255];
if (pxe_call == NULL)
return (0);
printf("%s devices:", pxedisk.dv_name);
if (pager_output("\n") != 0)
return (1);
+ printf(" %s0:", pxedisk.dv_name);
if (verbose) {
- snprintf(line, sizeof(line), " pxe0: %s:%s\n",
- inet_ntoa(rootip), rootpath);
- } else {
- snprintf(line, sizeof(line), " pxe0:\n");
+ printf(" %s:%s", inet_ntoa(rootip), rootpath);
}
- return (pager_output(line));
+ return (pager_output("\n"));
}
static void
@@ -460,66 +293,6 @@
return;
}
-/*
- * Reach inside the libstand NFS code and dig out an NFS handle
- * for the root filesystem.
- */
-#define NFS_V3MAXFHSIZE 64
-
-struct nfs_iodesc {
- struct iodesc *iodesc;
- off_t off;
- uint32_t fhsize;
- u_char fh[NFS_V3MAXFHSIZE];
- /* structure truncated */
-};
-extern struct nfs_iodesc nfs_root_node;
-extern int rpc_port;
-
-static void
-pxe_rpcmountcall()
-{
- struct iodesc *d;
- int error;
-
- if (!(d = socktodesc(pxe_sock)))
- return;
- d->myport = htons(--rpc_port);
- d->destip = rootip;
- if ((error = nfs_getrootfh(d, rootpath, &nfs_root_node.fhsize,
- nfs_root_node.fh)) != 0) {
- printf("NFS MOUNT RPC error: %d\n", error);
- nfs_root_node.fhsize = 0;
- }
- nfs_root_node.iodesc = d;
-}
-
-static void
-pxe_setnfshandle(char *rootpath)
-{
- int i;
- u_char *fh;
- char buf[2 * NFS_V3MAXFHSIZE + 3], *cp;
-
- /*
- * If NFS files were never opened, we need to do mount call
- * ourselves. Use nfs_root_node.iodesc as flag indicating
- * previous NFS usage.
- */
- if (nfs_root_node.iodesc == NULL)
- pxe_rpcmountcall();
-
- fh = &nfs_root_node.fh[0];
- buf[0] = 'X';
- cp = &buf[1];
- for (i = 0; i < nfs_root_node.fhsize; i++, cp += 2)
- sprintf(cp, "%02x", fh[i]);
- sprintf(cp, "X");
- setenv("boot.nfsroot.nfshandle", buf, 1);
- sprintf(buf, "%d", nfs_root_node.fhsize);
- setenv("boot.nfsroot.nfshandlelen", buf, 1);
-}
-
void
pxenv_call(int func)
{
@@ -570,121 +343,196 @@
static int
pxe_netif_match(struct netif *nif, void *machdep_hint)
{
- return 1;
+ return (1);
}
static int
pxe_netif_probe(struct netif *nif, void *machdep_hint)
{
- t_PXENV_UDP_OPEN *udpopen_p = (t_PXENV_UDP_OPEN *)scratch_buffer;
-
if (pxe_call == NULL)
- return -1;
-
- bzero(udpopen_p, sizeof(*udpopen_p));
- udpopen_p->src_ip = bootplayer.yip;
- pxe_call(PXENV_UDP_OPEN);
+ return (-1);
- if (udpopen_p->status != 0) {
- printf("pxe_netif_probe: failed %x\n", udpopen_p->status);
- return -1;
- }
- return 0;
+ return (0);
}
static void
pxe_netif_end(struct netif *nif)
{
- t_PXENV_UDP_CLOSE *udpclose_p = (t_PXENV_UDP_CLOSE *)scratch_buffer;
- bzero(udpclose_p, sizeof(*udpclose_p));
+ t_PXENV_UNDI_CLOSE *undi_close_p;
- pxe_call(PXENV_UDP_CLOSE);
- if (udpclose_p->status != 0)
- printf("pxe_end failed %x\n", udpclose_p->status);
+ undi_close_p = (t_PXENV_UNDI_CLOSE *)scratch_buffer;
+ bzero(undi_close_p, sizeof(*undi_close_p));
+ pxe_call(PXENV_UNDI_CLOSE);
+ if (undi_close_p->Status != 0)
+ printf("undi close failed: %x\n", undi_close_p->Status);
}
static void
pxe_netif_init(struct iodesc *desc, void *machdep_hint)
{
- int i;
- for (i = 0; i < 6; ++i)
- desc->myea[i] = bootplayer.CAddr[i];
- desc->xid = bootplayer.ident;
-}
+ t_PXENV_UNDI_GET_INFORMATION *undi_info_p;
+ t_PXENV_UNDI_OPEN *undi_open_p;
+ uint8_t *mac;
+ int i, len;
+
+ undi_info_p = (t_PXENV_UNDI_GET_INFORMATION *)scratch_buffer;
+ bzero(undi_info_p, sizeof(*undi_info_p));
+ pxe_call(PXENV_UNDI_GET_INFORMATION);
+ if (undi_info_p->Status != 0) {
+ printf("undi get info failed: %x\n", undi_info_p->Status);
+ return;
+ }
-static int
-pxe_netif_get(struct iodesc *desc, void *pkt, size_t len, time_t timeout)
-{
- return len;
-}
+ /* Make sure the CurrentNodeAddress is valid. */
+ for (i = 0; i < undi_info_p->HwAddrLen; ++i) {
+ if (undi_info_p->CurrentNodeAddress[i] != 0)
+ break;
+ }
+ if (i < undi_info_p->HwAddrLen) {
+ for (i = 0; i < undi_info_p->HwAddrLen; ++i) {
+ if (undi_info_p->CurrentNodeAddress[i] != 0xff)
+ break;
+ }
+ }
+ if (i < undi_info_p->HwAddrLen)
+ mac = undi_info_p->CurrentNodeAddress;
+ else
+ mac = undi_info_p->PermNodeAddress;
-static int
-pxe_netif_put(struct iodesc *desc, void *pkt, size_t len)
-{
- return len;
+ len = min(sizeof (desc->myea), undi_info_p->HwAddrLen);
+ for (i = 0; i < len; ++i)
+ desc->myea[i] = mac[i];
+
+ if (bootp_response != NULL)
+ desc->xid = bootp_response->bp_xid;
+ else
+ desc->xid = 0;
+
+ undi_open_p = (t_PXENV_UNDI_OPEN *)scratch_buffer;
+ bzero(undi_open_p, sizeof(*undi_open_p));
+ undi_open_p->PktFilter = FLTR_DIRECTED | FLTR_BRDCST;
+ pxe_call(PXENV_UNDI_OPEN);
+ if (undi_open_p->Status != 0)
+ printf("undi open failed: %x\n", undi_open_p->Status);
}
-ssize_t
-sendudp(struct iodesc *h, void *pkt, size_t len)
+static int
+pxe_netif_receive(void **pkt)
{
- t_PXENV_UDP_WRITE *udpwrite_p = (t_PXENV_UDP_WRITE *)scratch_buffer;
- bzero(udpwrite_p, sizeof(*udpwrite_p));
+ t_PXENV_UNDI_ISR *isr = (t_PXENV_UNDI_ISR *)scratch_buffer;
+ char *buf, *ptr, *frame;
+ size_t size, rsize;
+
+ bzero(isr, sizeof(*isr));
+ isr->FuncFlag = PXENV_UNDI_ISR_IN_START;
+ pxe_call(PXENV_UNDI_ISR);
+ if (isr->Status != 0)
+ return (-1);
+
+ bzero(isr, sizeof(*isr));
+ isr->FuncFlag = PXENV_UNDI_ISR_IN_PROCESS;
+ pxe_call(PXENV_UNDI_ISR);
+ if (isr->Status != 0)
+ return (-1);
+
+ while (isr->FuncFlag == PXENV_UNDI_ISR_OUT_TRANSMIT) {
+ /*
+ * Wait till transmit is done.
+ */
+ bzero(isr, sizeof(*isr));
+ isr->FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT;
+ pxe_call(PXENV_UNDI_ISR);
+ if (isr->Status != 0 ||
+ isr->FuncFlag == PXENV_UNDI_ISR_OUT_DONE)
+ return (-1);
+ }
+
+ while (isr->FuncFlag != PXENV_UNDI_ISR_OUT_RECEIVE) {
+ if (isr->Status != 0 ||
+ isr->FuncFlag == PXENV_UNDI_ISR_OUT_DONE) {
+ return (-1);
+ }
+ bzero(isr, sizeof(*isr));
+ isr->FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT;
+ pxe_call(PXENV_UNDI_ISR);
+ }
+
+ size = isr->FrameLength;
+ buf = malloc(size + 2);
+ if (buf == NULL)
+ return (-1);
+ ptr = buf + 2;
+ rsize = 0;
+
+ while (rsize < size) {
+ frame = (char *)((uintptr_t)isr->Frame.segment << 4);
+ frame += isr->Frame.offset;
+ bcopy(PTOV(frame), ptr, isr->BufferLength);
+ ptr += isr->BufferLength;
+ rsize += isr->BufferLength;
+
+ bzero(isr, sizeof(*isr));
+ isr->FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT;
+ pxe_call(PXENV_UNDI_ISR);
+ if (isr->Status != 0) {
+ free(buf);
+ return (-1);
+ }
- udpwrite_p->ip = h->destip.s_addr;
- udpwrite_p->dst_port = h->destport;
- udpwrite_p->src_port = h->myport;
- udpwrite_p->buffer_size = len;
- udpwrite_p->buffer.segment = VTOPSEG(pkt);
- udpwrite_p->buffer.offset = VTOPOFF(pkt);
+ /* Did we got another update? */
+ if (isr->FuncFlag == PXENV_UNDI_ISR_OUT_RECEIVE)
+ continue;
+ break;
+ }
- if (netmask == 0 || SAMENET(myip, h->destip, netmask))
- udpwrite_p->gw = 0;
- else
- udpwrite_p->gw = gateip.s_addr;
+ *pkt = buf;
+ return (rsize);
+}
- pxe_call(PXENV_UDP_WRITE);
+static ssize_t
+pxe_netif_get(struct iodesc *desc, void **pkt, time_t timeout)
+{
+ time_t t;
+ void *ptr;
+ int ret = -1;
-#if 0
- /* XXX - I dont know why we need this. */
- delay(1000);
-#endif
- if (udpwrite_p->status != 0) {
- /* XXX: This happens a lot. It shouldn't. */
- if (udpwrite_p->status != 1)
- printf("sendudp failed %x\n", udpwrite_p->status);
- return -1;
+ t = time(0);
+ while ((time(0) - t) < timeout) {
+ ret = pxe_netif_receive(&ptr);
+ if (ret != -1) {
+ *pkt = ptr;
+ break;
+ }
}
- return len;
+ return (ret);
}
-ssize_t
-readudp(struct iodesc *h, void *pkt, size_t len, time_t timeout)
+static ssize_t
+pxe_netif_put(struct iodesc *desc, void *pkt, size_t len)
{
- t_PXENV_UDP_READ *udpread_p = (t_PXENV_UDP_READ *)scratch_buffer;
- struct udphdr *uh = NULL;
+ t_PXENV_UNDI_TRANSMIT *trans_p;
+ t_PXENV_UNDI_TBD *tbd_p;
+ char *data;
- uh = (struct udphdr *) pkt - 1;
- bzero(udpread_p, sizeof(*udpread_p));
+ trans_p = (t_PXENV_UNDI_TRANSMIT *)scratch_buffer;
+ bzero(trans_p, sizeof(*trans_p));
+ tbd_p = (t_PXENV_UNDI_TBD *)(scratch_buffer + sizeof(*trans_p));
+ bzero(tbd_p, sizeof(*tbd_p));
- udpread_p->dest_ip = h->myip.s_addr;
- udpread_p->d_port = h->myport;
- udpread_p->buffer_size = len;
- udpread_p->buffer.segment = VTOPSEG(data_buffer);
- udpread_p->buffer.offset = VTOPOFF(data_buffer);
+ data = scratch_buffer + sizeof(*trans_p) + sizeof(*tbd_p);
- pxe_call(PXENV_UDP_READ);
+ trans_p->TBD.segment = VTOPSEG(tbd_p);
+ trans_p->TBD.offset = VTOPOFF(tbd_p);
-#if 0
- /* XXX - I dont know why we need this. */
- delay(1000);
-#endif
- if (udpread_p->status != 0) {
- /* XXX: This happens a lot. It shouldn't. */
- if (udpread_p->status != 1)
- printf("readudp failed %x\n", udpread_p->status);
- return -1;
- }
- bcopy(data_buffer, pkt, udpread_p->buffer_size);
- uh->uh_sport = udpread_p->s_port;
- return udpread_p->buffer_size;
+ tbd_p->ImmedLength = len;
+ tbd_p->Xmit.segment = VTOPSEG(data);
+ tbd_p->Xmit.offset = VTOPOFF(data);
+ bcopy(pkt, data, len);
+
+ pxe_call(PXENV_UNDI_TRANSMIT);
+ if (trans_p->Status != 0) {
+ return (-1);
+ }
+
+ return (len);
}
Index: sys/boot/i386/loader/Makefile
===================================================================
--- sys/boot/i386/loader/Makefile
+++ sys/boot/i386/loader/Makefile
@@ -9,6 +9,7 @@
INTERNALPROG=
NEWVERSWHAT?= "bootstrap loader" x86
VERSION_FILE= ${.CURDIR}/../loader/version
+LOADER_NET_SUPPORT?= yes
# architecture-specific loader code
SRCS= main.c conf.c vers.c
@@ -25,6 +26,10 @@
LIBZFSBOOT= ${.OBJDIR}/../../zfs/libzfsboot.a
.endif
+.if defined(LOADER_NET_SUPPORT)
+CFLAGS+= -I${.CURDIR}/../../../../lib/libstand
+.endif
+
# Enable PXE TFTP or NFS support, not both.
.if defined(LOADER_TFTP_SUPPORT)
CFLAGS+= -DLOADER_TFTP_SUPPORT
Index: sys/boot/ofw/libofw/ofw_net.c
===================================================================
--- sys/boot/ofw/libofw/ofw_net.c
+++ sys/boot/ofw/libofw/ofw_net.c
@@ -57,7 +57,7 @@
{ 0, 1, &ofwn_stats[0], 0, },
};
-struct netif_stats ofwn_stats[NENTS(ofwn_ifs)];
+struct netif_stats ofwn_stats[nitems(ofwn_ifs)];
struct netif_driver ofwnet = {
"net", /* netif_bname */
@@ -68,7 +68,7 @@
ofwn_put, /* netif_put */
ofwn_end, /* netif_end */
ofwn_ifs, /* netif_ifs */
- NENTS(ofwn_ifs) /* netif_nifs */
+ nitems(ofwn_ifs) /* netif_nifs */
};
static ihandle_t netinstance;
Index: sys/boot/uboot/lib/net.c
===================================================================
--- sys/boot/uboot/lib/net.c
+++ sys/boot/uboot/lib/net.c
@@ -61,7 +61,7 @@
{ 0, 1, &net_stats[0], 0, },
};
-struct netif_stats net_stats[NENTS(net_ifs)];
+struct netif_stats net_stats[nitems(net_ifs)];
struct netif_driver uboot_net = {
"uboot_eth", /* netif_bname */
@@ -72,7 +72,7 @@
net_put, /* netif_put */
net_end, /* netif_end */
net_ifs, /* netif_ifs */
- NENTS(net_ifs) /* netif_nifs */
+ nitems(net_ifs) /* netif_nifs */
};
struct uboot_softc {

File Metadata

Mime Type
text/plain
Expires
Sun, Jan 12, 2:36 AM (11 h, 48 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
15760144
Default Alt Text
D10232.id26924.diff (73 KB)

Event Timeline