summaryrefslogtreecommitdiffstats
path: root/lib/libstand
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libstand')
-rw-r--r--lib/libstand/Makefile2
-rw-r--r--lib/libstand/stand.h6
-rw-r--r--lib/libstand/tftp.c183
-rw-r--r--lib/libstand/zalloc.c22
-rw-r--r--lib/libstand/zalloc_defs.h17
-rw-r--r--lib/libstand/zalloc_malloc.c4
-rw-r--r--lib/libstand/zalloc_mem.h6
-rw-r--r--lib/libstand/zalloc_protos.h6
8 files changed, 159 insertions, 87 deletions
diff --git a/lib/libstand/Makefile b/lib/libstand/Makefile
index 6024350..05f0995 100644
--- a/lib/libstand/Makefile
+++ b/lib/libstand/Makefile
@@ -15,7 +15,7 @@ NO_PIC=
INCS= stand.h
MAN= libstand.3
-WARNS?= 2
+WARNS?= 0
CFLAGS+= -ffreestanding -Wformat
CFLAGS+= -I${.CURDIR}
diff --git a/lib/libstand/stand.h b/lib/libstand/stand.h
index eae1605..db0490f 100644
--- a/lib/libstand/stand.h
+++ b/lib/libstand/stand.h
@@ -65,15 +65,13 @@
#include <sys/cdefs.h>
#include <sys/stat.h>
#include <sys/dirent.h>
+
+/* this header intentionally exports NULL from <string.h> */
#include <string.h>
#define CHK(fmt, args...) printf("%s(%d): " fmt "\n", __func__, __LINE__ , ##args)
#define PCHK(fmt, args...) {printf("%s(%d): " fmt "\n", __func__, __LINE__ , ##args); getchar();}
-#ifndef NULL
-#define NULL 0
-#endif
-
/* Avoid unwanted userlandish components */
#define _KERNEL
#include <sys/errno.h>
diff --git a/lib/libstand/tftp.c b/lib/libstand/tftp.c
index 54e184c..bf92c04 100644
--- a/lib/libstand/tftp.c
+++ b/lib/libstand/tftp.c
@@ -64,13 +64,13 @@ struct tftp_handle;
static int tftp_open(const char *path, struct open_file *f);
static int tftp_close(struct open_file *f);
-static void tftp_parse_oack(struct tftp_handle *h, char *buf, size_t len);
+static int tftp_parse_oack(struct tftp_handle *h, char *buf, size_t len);
static int tftp_read(struct open_file *f, void *buf, size_t size, size_t *resid);
static int tftp_write(struct open_file *f, void *buf, size_t size, size_t *resid);
static off_t tftp_seek(struct open_file *f, off_t offset, int where);
static int tftp_set_blksize(struct tftp_handle *h, const char *str);
static int tftp_stat(struct open_file *f, struct stat *sb);
-static ssize_t sendrecv_tftp(struct tftp_handle *h,
+static ssize_t sendrecv_tftp(struct tftp_handle *h,
ssize_t (*sproc)(struct iodesc *, void *, size_t),
void *sbuf, size_t ssize,
ssize_t (*rproc)(struct tftp_handle *h, void *, ssize_t, time_t, unsigned short *),
@@ -93,7 +93,7 @@ static int tftpport = 2000;
static int is_open = 0;
/*
- * The legacy TFTP_BLKSIZE value was 512.
+ * The legacy TFTP_BLKSIZE value was SEGSIZE(512).
* TFTP_REQUESTED_BLKSIZE of 1428 is (Ethernet MTU, less the TFTP, UDP and
* IP header lengths).
*/
@@ -102,7 +102,7 @@ static int is_open = 0;
/*
* Choose a blksize big enough so we can test with Ethernet
* Jumbo frames in the future.
- */
+ */
#define TFTP_MAX_BLKSIZE 9008
struct tftp_handle {
@@ -113,7 +113,7 @@ struct tftp_handle {
int off;
char *path; /* saved for re-requests */
unsigned int tftp_blksize;
- unsigned long tftp_tsize;
+ unsigned long tftp_tsize;
struct {
u_char header[HEADER_SIZE];
struct tftphdr t;
@@ -121,7 +121,8 @@ struct tftp_handle {
} __packed __aligned(4) lastdata;
};
-static const int tftperrors[8] = {
+#define TFTP_MAX_ERRCODE EOPTNEG
+static const int tftperrors[TFTP_MAX_ERRCODE + 1] = {
0, /* ??? */
ENOENT,
EPERM,
@@ -129,10 +130,57 @@ static const int tftperrors[8] = {
EINVAL, /* ??? */
EINVAL, /* ??? */
EEXIST,
- EINVAL /* ??? */
+ EINVAL, /* ??? */
+ EINVAL, /* Option negotiation failed. */
};
-static ssize_t
+static int tftp_getnextblock(struct tftp_handle *h);
+
+/* send error message back. */
+static void
+tftp_senderr(struct tftp_handle *h, u_short errcode, const char *msg)
+{
+ struct {
+ u_char header[HEADER_SIZE];
+ struct tftphdr t;
+ u_char space[63]; /* +1 from t */
+ } __packed __aligned(4) wbuf;
+ char *wtail;
+ int len;
+
+ len = strlen(msg);
+ if (len > sizeof(wbuf.space))
+ len = sizeof(wbuf.space);
+
+ wbuf.t.th_opcode = htons((u_short) ERROR);
+ wbuf.t.th_code = htons(errcode);
+
+ wtail = wbuf.t.th_msg;
+ bcopy(msg, wtail, len);
+ wtail[len] = '\0';
+ wtail += len + 1;
+
+ sendudp(h->iodesc, &wbuf.t, wtail - (char *) &wbuf.t);
+}
+
+static void
+tftp_sendack(struct tftp_handle *h)
+{
+ struct {
+ u_char header[HEADER_SIZE];
+ struct tftphdr t;
+ } __packed __aligned(4) wbuf;
+ char *wtail;
+
+ wbuf.t.th_opcode = htons((u_short) ACK);
+ wtail = (char *) &wbuf.t.th_block;
+ wbuf.t.th_block = htons((u_short) h->currblock);
+ wtail += 2;
+
+ sendudp(h->iodesc, &wbuf.t, wtail - (char *) &wbuf.t);
+}
+
+static ssize_t
recvtftp(struct tftp_handle *h, void *pkt, ssize_t len, time_t tleft,
unsigned short *rtype)
{
@@ -170,7 +218,7 @@ recvtftp(struct tftp_handle *h, void *pkt, ssize_t len, time_t tleft,
return got;
}
case ERROR:
- if ((unsigned) ntohs(t->th_code) >= 8) {
+ if ((unsigned) ntohs(t->th_code) > TFTP_MAX_ERRCODE) {
printf("illegal tftp error %d\n", ntohs(t->th_code));
errno = EIO;
} else {
@@ -182,14 +230,30 @@ recvtftp(struct tftp_handle *h, void *pkt, ssize_t len, time_t tleft,
return (-1);
case OACK: {
struct udphdr *uh;
- int tftp_oack_len = len - sizeof(t->th_opcode);
- tftp_parse_oack(h, t->th_u.tu_stuff, tftp_oack_len);
+ int tftp_oack_len;
+
+ /*
+ * Unexpected OACK. TFTP transfer already in progress.
+ * Drop the pkt.
+ */
+ if (d->xid != 1) {
+ return (-1);
+ }
+
/*
- * Remember which port this OACK came from,
- * because we need to send the ACK back to it.
+ * Remember which port this OACK came from, because we need
+ * to send the ACK or errors back to it.
*/
uh = (struct udphdr *) pkt - 1;
d->destport = uh->uh_sport;
+
+ /* Parse options ACK-ed by the server. */
+ tftp_oack_len = len - sizeof(t->th_opcode);
+ if (tftp_parse_oack(h, t->th_u.tu_stuff, tftp_oack_len) != 0) {
+ tftp_senderr(h, EOPTNEG, "Malformed OACK");
+ errno = EIO;
+ return (-1);
+ }
return (0);
}
default:
@@ -201,7 +265,7 @@ recvtftp(struct tftp_handle *h, void *pkt, ssize_t len, time_t tleft,
}
/* send request, expect first block (or error) */
-static int
+static int
tftp_makereq(struct tftp_handle *h)
{
struct {
@@ -250,26 +314,28 @@ tftp_makereq(struct tftp_handle *h)
h->iodesc->destport = htons(IPPORT_TFTP);
h->iodesc->xid = 1; /* expected block */
+ h->currblock = 0;
+ h->islastblock = 0;
+ h->validsize = 0;
+
res = sendrecv_tftp(h, &sendudp, &wbuf.t, wtail - (char *) &wbuf.t,
&recvtftp, t, sizeof(*t) + h->tftp_blksize, &rtype);
- if (rtype == OACK) {
- wbuf.t.th_opcode = htons((u_short)ACK);
- wtail = (char *) &wbuf.t.th_block;
- wbuf.t.th_block = htons(0);
- wtail += 2;
- rtype = 0;
- res = sendrecv_tftp(h, &sendudp, &wbuf.t, wtail - (char *) &wbuf.t,
- &recvtftp, t, sizeof(*t) + h->tftp_blksize, &rtype);
- }
+ if (rtype == OACK)
+ return (tftp_getnextblock(h));
+
+ /* Server ignored our blksize request, revert to TFTP default. */
+ h->tftp_blksize = SEGSIZE;
switch (rtype) {
case DATA: {
h->currblock = 1;
h->validsize = res;
h->islastblock = 0;
- if (res < h->tftp_blksize)
+ if (res < h->tftp_blksize) {
h->islastblock = 1; /* very short file */
+ tftp_sendack(h);
+ }
return (0);
}
case ERROR:
@@ -320,7 +386,7 @@ tftp_getnextblock(struct tftp_handle *h)
return (0);
}
-static int
+static int
tftp_open(const char *path, struct open_file *f)
{
struct tftp_handle *tftpfile;
@@ -365,7 +431,7 @@ tftp_open(const char *path, struct open_file *f)
return (0);
}
-static int
+static int
tftp_read(struct open_file *f, void *addr, size_t size,
size_t *resid /* out */)
{
@@ -381,9 +447,11 @@ tftp_read(struct open_file *f, void *addr, size_t size,
needblock = tftpfile->off / tftpfile->tftp_blksize + 1;
- if (tftpfile->currblock > needblock) /* seek backwards */
+ if (tftpfile->currblock > needblock) { /* seek backwards */
+ tftp_senderr(tftpfile, 0, "No error: read aborted");
tftp_makereq(tftpfile); /* no error check, it worked
* for open */
+ }
while (tftpfile->currblock < needblock) {
int res;
@@ -452,7 +520,7 @@ tftp_close(struct open_file *f)
return (0);
}
-static int
+static int
tftp_write(struct open_file *f __unused, void *start __unused, size_t size __unused,
size_t *resid __unused /* out */)
{
@@ -473,7 +541,7 @@ tftp_stat(struct open_file *f, struct stat *sb)
return (0);
}
-static off_t
+static off_t
tftp_seek(struct open_file *f, off_t offset, int where)
{
struct tftp_handle *tftpfile;
@@ -494,7 +562,7 @@ tftp_seek(struct open_file *f, off_t offset, int where)
}
static ssize_t
-sendrecv_tftp(struct tftp_handle *h,
+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 *),
@@ -562,9 +630,9 @@ tftp_set_blksize(struct tftp_handle *h, const char *str)
/*
* Only accept blksize value if it is numeric.
- * RFC2348 specifies that acceptable valuesare 8-65464
- * 8-65464 . Let's choose a limit less than MAXRSPACE
- */
+ * RFC2348 specifies that acceptable values are 8-65464.
+ * Let's choose a limit less than MAXRSPACE.
+ */
if (*endptr == '\0' && new_blksize >= 8
&& new_blksize <= TFTP_MAX_BLKSIZE) {
h->tftp_blksize = new_blksize;
@@ -597,13 +665,12 @@ tftp_set_blksize(struct tftp_handle *h, const char *str)
* optN, valueN
* The final option/value acknowledgment pair.
*/
-static void
+static int
tftp_parse_oack(struct tftp_handle *h, char *buf, size_t len)
{
/*
* We parse the OACK strings into an array
* of name-value pairs.
- *
*/
char *tftp_options[128] = { 0 };
char *val = buf;
@@ -612,18 +679,22 @@ tftp_parse_oack(struct tftp_handle *h, char *buf, size_t len)
int blksize_is_set = 0;
int tsize = 0;
-
- while ( option_idx < 128 && i < len ) {
- if (buf[i] == '\0') {
- if (&buf[i] > val) {
- tftp_options[option_idx] = val;
- val = &buf[i] + 1;
- ++option_idx;
- }
- }
- ++i;
+ unsigned int orig_blksize;
+
+ while (option_idx < 128 && i < len) {
+ if (buf[i] == '\0') {
+ if (&buf[i] > val) {
+ tftp_options[option_idx] = val;
+ val = &buf[i] + 1;
+ ++option_idx;
+ }
+ }
+ ++i;
}
+ /* Save the block size we requested for sanity check later. */
+ orig_blksize = h->tftp_blksize;
+
/*
* Parse individual TFTP options.
* * "blksize" is specified in RFC2348.
@@ -631,27 +702,37 @@ tftp_parse_oack(struct tftp_handle *h, char *buf, size_t len)
*/
for (i = 0; i < option_idx; i += 2) {
if (strcasecmp(tftp_options[i], "blksize") == 0) {
- if (i + 1 < option_idx) {
+ if (i + 1 < option_idx)
blksize_is_set =
tftp_set_blksize(h, tftp_options[i + 1]);
- }
} else if (strcasecmp(tftp_options[i], "tsize") == 0) {
- if (i + 1 < option_idx) {
+ if (i + 1 < option_idx)
tsize = strtol(tftp_options[i + 1], (char **)NULL, 10);
- }
+ } else {
+ /* Do not allow any options we did not expect to be ACKed. */
+ printf("unexpected tftp option '%s'\n", tftp_options[i]);
+ return (-1);
}
}
if (!blksize_is_set) {
/*
* If TFTP blksize was not set, try defaulting
- * to the legacy TFTP blksize of 512
+ * to the legacy TFTP blksize of SEGSIZE(512)
*/
- h->tftp_blksize = 512;
+ h->tftp_blksize = SEGSIZE;
+ } else if (h->tftp_blksize > orig_blksize) {
+ /*
+ * Server should not be proposing block sizes that
+ * exceed what we said we can handle.
+ */
+ printf("unexpected blksize %u\n", h->tftp_blksize);
+ return (-1);
}
#ifdef TFTP_DEBUG
printf("tftp_blksize: %u\n", h->tftp_blksize);
printf("tftp_tsize: %lu\n", h->tftp_tsize);
#endif
+ return 0;
}
diff --git a/lib/libstand/zalloc.c b/lib/libstand/zalloc.c
index 2cd71c4..41aef0d 100644
--- a/lib/libstand/zalloc.c
+++ b/lib/libstand/zalloc.c
@@ -77,7 +77,7 @@ __FBSDID("$FreeBSD$");
*/
void *
-znalloc(MemPool *mp, iaddr_t bytes)
+znalloc(MemPool *mp, uintptr_t bytes)
{
/*
* align according to pool object size (can be 0). This is
@@ -136,7 +136,7 @@ znalloc(MemPool *mp, iaddr_t bytes)
*/
void
-zfree(MemPool *mp, void *ptr, iaddr_t bytes)
+zfree(MemPool *mp, void *ptr, uintptr_t bytes)
{
/*
* align according to pool object size (can be 0). This is
@@ -153,8 +153,8 @@ zfree(MemPool *mp, void *ptr, iaddr_t bytes)
if ((char *)ptr < (char *)mp->mp_Base ||
(char *)ptr + bytes > (char *)mp->mp_End ||
- ((iaddr_t)ptr & MEMNODE_SIZE_MASK) != 0)
- panic("zfree(%p,%ju): wild pointer", ptr, bytes);
+ ((uintptr_t)ptr & MEMNODE_SIZE_MASK) != 0)
+ panic("zfree(%p,%ju): wild pointer", ptr, (uintmax_t)bytes);
/*
* free the segment
@@ -177,8 +177,10 @@ zfree(MemPool *mp, void *ptr, iaddr_t bytes)
/*
* range check
*/
- if ((char *)ptr + bytes > (char *)mn)
- panic("zfree(%p,%ju): corrupt memlist1",ptr, bytes);
+ if ((char *)ptr + bytes > (char *)mn) {
+ panic("zfree(%p,%ju): corrupt memlist1", ptr,
+ (uintmax_t)bytes);
+ }
/*
* merge against next area or create independant area
@@ -208,8 +210,10 @@ zfree(MemPool *mp, void *ptr, iaddr_t bytes)
return;
/* NOT REACHED */
}
- if ((char *)ptr < (char *)mn + mn->mr_Bytes)
- panic("zfree(%p,%ju): corrupt memlist2", ptr, bytes);
+ if ((char *)ptr < (char *)mn + mn->mr_Bytes) {
+ panic("zfree(%p,%ju): corrupt memlist2", ptr,
+ (uintmax_t)bytes);
+ }
}
/*
* We are beyond the last MemNode, append new MemNode. Merge against
@@ -241,7 +245,7 @@ zfree(MemPool *mp, void *ptr, iaddr_t bytes)
*/
void
-zextendPool(MemPool *mp, void *base, iaddr_t bytes)
+zextendPool(MemPool *mp, void *base, uintptr_t bytes)
{
if (mp->mp_Size == 0) {
mp->mp_Base = base;
diff --git a/lib/libstand/zalloc_defs.h b/lib/libstand/zalloc_defs.h
index 2544f59..5331ee0 100644
--- a/lib/libstand/zalloc_defs.h
+++ b/lib/libstand/zalloc_defs.h
@@ -38,20 +38,12 @@
#define DMALLOCDEBUG /* add debugging code to gather stats */
#define ZALLOCDEBUG
-#include <string.h>
+#include <sys/stdint.h>
#include "stand.h"
-
-typedef uintptr_t iaddr_t; /* unsigned int same size as pointer */
-typedef intptr_t saddr_t; /* signed int same size as pointer */
#include "zalloc_mem.h"
-#define Prototype extern
#define Library extern
-#ifndef NULL
-#define NULL ((void *)0)
-#endif
-
/*
* block extension for sbrk()
*/
@@ -60,8 +52,7 @@ typedef intptr_t saddr_t; /* signed int same size as pointer */
#define BLKEXTENDMASK (BLKEXTEND - 1)
/*
- * required malloc alignment. Use sizeof(long double) for architecture
- * independance.
+ * required malloc alignment. Just hardwire to 16.
*
* Note: if we implement a more sophisticated realloc, we should ensure that
* MALLOCALIGN is at least as large as MemNode.
@@ -72,10 +63,8 @@ typedef struct Guard {
size_t ga_Magic; /* must be at least 32 bits */
} Guard;
-#define MATYPE long double
-#define MALLOCALIGN ((sizeof(MATYPE) > sizeof(Guard)) ? sizeof(MATYPE) : sizeof(Guard))
+#define MALLOCALIGN 16
#define GAMAGIC 0x55FF44FD
#define GAFREE 0x5F54F4DF
#include "zalloc_protos.h"
-
diff --git a/lib/libstand/zalloc_malloc.c b/lib/libstand/zalloc_malloc.c
index cdacf13..b9a295f 100644
--- a/lib/libstand/zalloc_malloc.c
+++ b/lib/libstand/zalloc_malloc.c
@@ -110,7 +110,7 @@ Free(void *ptr, const char *file, int line)
return;
}
if (*((signed char *)res + res->ga_Bytes - 1) != -2)
- panic("free: guard2 fail @ %p + %d from %s:%d", ptr, res->ga_Bytes - MALLOCALIGN, file, line);
+ panic("free: guard2 fail @ %p + %zu from %s:%d", ptr, res->ga_Bytes - MALLOCALIGN, file, line);
*((signed char *)res + res->ga_Bytes - 1) = -1;
#endif
@@ -126,7 +126,7 @@ Free(void *ptr, const char *file, int line)
void *
Calloc(size_t n1, size_t n2, const char *file, int line)
{
- iaddr_t bytes = (iaddr_t)n1 * (iaddr_t)n2;
+ uintptr_t bytes = (uintptr_t)n1 * (uintptr_t)n2;
void *res;
if ((res = Malloc(bytes, file, line)) != NULL) {
diff --git a/lib/libstand/zalloc_mem.h b/lib/libstand/zalloc_mem.h
index c872da1..f29c0d7 100644
--- a/lib/libstand/zalloc_mem.h
+++ b/lib/libstand/zalloc_mem.h
@@ -37,15 +37,15 @@
typedef struct MemNode {
struct MemNode *mr_Next;
- iaddr_t mr_Bytes;
+ uintptr_t mr_Bytes;
} MemNode;
typedef struct MemPool {
void *mp_Base;
void *mp_End;
MemNode *mp_First;
- iaddr_t mp_Size;
- iaddr_t mp_Used;
+ uintptr_t mp_Size;
+ uintptr_t mp_Used;
} MemPool;
#define MEMNODE_SIZE_MASK ((sizeof(MemNode) <= 8) ? 7 : 15)
diff --git a/lib/libstand/zalloc_protos.h b/lib/libstand/zalloc_protos.h
index c90bd5a..53a40e4 100644
--- a/lib/libstand/zalloc_protos.h
+++ b/lib/libstand/zalloc_protos.h
@@ -29,7 +29,7 @@
* $FreeBSD$
*/
-Library void *znalloc(struct MemPool *mpool, iaddr_t bytes);
-Library void zfree(struct MemPool *mpool, void *ptr, iaddr_t bytes);
-Library void zextendPool(MemPool *mp, void *base, iaddr_t bytes);
+Library void *znalloc(struct MemPool *mpool, uintptr_t bytes);
+Library void zfree(struct MemPool *mpool, void *ptr, uintptr_t bytes);
+Library void zextendPool(MemPool *mp, void *base, uintptr_t bytes);
Library void zallocstats(struct MemPool *mp);
OpenPOWER on IntegriCloud