aboutsummaryrefslogtreecommitdiffstats
path: root/core/fs/pxe
diff options
context:
space:
mode:
Diffstat (limited to 'core/fs/pxe')
-rw-r--r--core/fs/pxe/dhcp_option.c9
-rw-r--r--core/fs/pxe/dnsresolv.c71
-rw-r--r--core/fs/pxe/http.c98
-rw-r--r--core/fs/pxe/pxe.c240
-rw-r--r--core/fs/pxe/pxe.h39
-rw-r--r--core/fs/pxe/tftp.c24
-rw-r--r--core/fs/pxe/tftp.h48
-rw-r--r--core/fs/pxe/url.h13
-rw-r--r--core/fs/pxe/urlparse.c146
9 files changed, 265 insertions, 423 deletions
diff --git a/core/fs/pxe/dhcp_option.c b/core/fs/pxe/dhcp_option.c
index 50f2de04..47031faf 100644
--- a/core/fs/pxe/dhcp_option.c
+++ b/core/fs/pxe/dhcp_option.c
@@ -48,13 +48,8 @@ static void dns_servers(const void *data, int opt_len)
static void local_domain(const void *data, int opt_len)
{
- char buffer[256];
- char *ld = LocalDomain;
-
- memcpy(buffer, data, opt_len);
- buffer[opt_len] = 0;
-
- dns_mangle(&ld, buffer);
+ memcpy(LocalDomain, data, opt_len);
+ LocalDomain[opt_len] = 0;
}
static void vendor_encaps(const void *data, int opt_len)
diff --git a/core/fs/pxe/dnsresolv.c b/core/fs/pxe/dnsresolv.c
index b827edbb..a4bbf1ff 100644
--- a/core/fs/pxe/dnsresolv.c
+++ b/core/fs/pxe/dnsresolv.c
@@ -50,42 +50,35 @@ struct dnsrr {
uint32_t dns_server[DNS_MAX_SERVERS] = {0, };
-
/*
- * Turn a string in _src_ into a DNS "label set" in _dst_; returns the
- * number of dots encountered. On return, *dst is updated.
+ * parse the ip_str and return the ip address with *res.
+ * return true if the whole string was consumed and the result
+ * was valid.
+ *
*/
-int dns_mangle(char **dst, const char *p)
+static bool parse_dotquad(const char *ip_str, uint32_t *res)
{
- char *q = *dst;
- char *count_ptr;
- char c;
- int dots = 0;
-
- count_ptr = q;
- *q++ = 0;
-
- while (1) {
- c = *p++;
- if (c == 0 || c == ':' || c == '/')
- break;
- if (c == '.') {
- dots++;
- count_ptr = q;
- *q++ = 0;
- continue;
+ const char *p = ip_str;
+ uint8_t part = 0;
+ uint32_t ip = 0;
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ while (is_digit(*p)) {
+ part = part * 10 + *p - '0';
+ p++;
}
+ if (i != 3 && *p != '.')
+ return false;
- *count_ptr += 1;
- *q++ = c;
+ ip = (ip << 8) | part;
+ part = 0;
+ p++;
}
+ p--;
- if (*count_ptr)
- *q++ = 0;
-
- /* update the strings */
- *dst = q;
- return dots;
+ *res = htonl(ip);
+ return *p == '\0';
}
/*
@@ -98,32 +91,22 @@ uint32_t dns_resolv(const char *name)
{
err_t err;
struct ip_addr ip;
- char dns_name[PKTBUF_SIZE];
- const char *src;
- char *dst;
+
+ /* If it is a valid dot quad, just return that value */
+ if (parse_dotquad(name, &ip.addr))
+ return ip.addr;
/* Make sure we have at least one valid DNS server */
if (!dns_getserver(0).addr)
return 0;
- /* Copy the name to look up to ensure it is null terminated */
- for (dst = dns_name, src = name; *src; src++, dst++) {
- int ch = *src;
- if (ch == '\0' || ch == ':' || ch == '/') {
- *dst = '\0';
- break;
- }
- *dst = ch;
- }
-
- err = netconn_gethostbyname(dns_name, &ip);
+ err = netconn_gethostbyname(name, &ip);
if (err)
return 0;
return ip.addr;
}
-
/*
* the one should be called from ASM file
*/
diff --git a/core/fs/pxe/http.c b/core/fs/pxe/http.c
index 6af55d59..2f5a645a 100644
--- a/core/fs/pxe/http.c
+++ b/core/fs/pxe/http.c
@@ -1,7 +1,10 @@
#include <ctype.h>
+#include <lwip/api.h>
#include "pxe.h"
#include "../../../version.h"
-#include <lwip/api.h>
+#include "url.h"
+
+#define HTTP_PORT 80
static void http_close_file(struct inode *inode)
{
@@ -92,16 +95,14 @@ static bool append_ch(char *str, size_t size, size_t *pos, int ch)
return success;
}
-void http_open(struct inode *inode, const char *url)
+void http_open(struct url_info *url, struct inode *inode)
{
struct pxe_pvt_inode *socket = PVT(inode);
- char header_buf[512];
+ char header_buf[4096];
int header_len;
- const char *host, *path, *next;
- size_t host_len;
- uint16_t port;
+ const char *next;
char field_name[20];
- char field_value[256];
+ char field_value[1024];
size_t field_name_len, field_value_len;
err_t err;
enum state {
@@ -116,7 +117,7 @@ void http_open(struct inode *inode, const char *url)
st_eoh,
} state;
struct ip_addr addr;
- char location[256];
+ char location[1024], new_url[1024];
uint32_t content_length; /* same as inode->size */
size_t response_size;
int status;
@@ -130,49 +131,6 @@ void http_open(struct inode *inode, const char *url)
restart:
/* Reset all of the variables */
inode->size = content_length = -1;
- location[0] = '\0';
- field_name[0] = '\0';
- field_value[0] = '\0';
- field_name_len = 0;
- field_value_len = 0;
-
- /* Skip http:// */
- host = url + 7;
-
- /* Find the end of the hostname */
- next = host;
- while (*next && *next != '/' && *next != ':')
- next++;
- host_len = next - host;
-
- /* Obvious url formatting errors */
- if (!*next || (!host_len && *next == ':'))
- goto fail;
-
- /* Compute the dest port */
- port = 80;
- if (*next == ':') {
- port = 0;
- for (next++; (*next >= '0' && *next <= '9'); next++)
- port = (port * 10) * (*next - '0');
- }
-
- /* Ensure I have properly parsed the port */
- if (*next != '/')
- goto fail;
-
- path = next;
-
- /* Resolve the hostname */
- if (!host_len) {
- addr.addr = IPInfo.serverip;
- } else {
- if (parse_dotquad(host, &addr.addr) != (host + host_len)) {
- addr.addr = dns_resolv(host);
- if (!addr.addr)
- goto fail;
- }
- }
/* Start the http connection */
socket->conn = netconn_new(NETCONN_TCP);
@@ -181,23 +139,31 @@ restart:
return;
}
- err = netconn_connect(socket->conn, &addr, port);
+ addr.addr = url->ip;
+ if (!url->port)
+ url->port = HTTP_PORT;
+ err = netconn_connect(socket->conn, &addr, url->port);
if (err) {
printf("netconn_connect error %d\n", err);
goto fail;
}
- header_len = snprintf(header_buf, sizeof header_buf,
- "GET %s HTTP/1.0\r\n"
- "Host: %*.*s\r\n"
- "User-Agent: PXELINUX/%s\r\n"
- "Connection: close\r\n"
- "\r\n",
- path, host_len, host_len, host, VERSION_STR);
-
- /* If we tried to overflow our buffer abort */
+ strcpy(header_buf, "GET /");
+ header_len = 5;
+ header_len += url_escape_unsafe(header_buf+5, url->path,
+ sizeof header_buf - 5);
if (header_len > sizeof header_buf)
- goto fail;
+ goto fail; /* Buffer overflow */
+ header_len += snprintf(header_buf + header_len,
+ sizeof header_buf - header_len,
+ " HTTP/1.0\r\n"
+ "Host: %s\r\n"
+ "User-Agent: PXELINUX/%s\r\n"
+ "Connection: close\r\n"
+ "\r\n",
+ url->host, VERSION_STR);
+ if (header_len > sizeof header_buf)
+ goto fail; /* Buffer overflow */
err = netconn_write(socket->conn, header_buf, header_len, NETCONN_NOCOPY);
if (err) {
@@ -210,6 +176,8 @@ restart:
pos = 0;
status = 0;
response_size = 0;
+ field_value_len = 0;
+ field_name_len = 0;
while (state != st_eoh) {
int ch = pxe_getc(inode);
@@ -360,7 +328,11 @@ restart:
redirect_count++;
if (redirect_count > 5)
goto fail;
- url = location;
+ strlcpy(new_url, location, sizeof new_url);
+ parse_url(url, new_url);
+ url_set_ip(url);
+ http_close_file(inode);
+ /* XXX: This needs to go all the way back to scheme selection */
goto restart;
break;
default:
diff --git a/core/fs/pxe/pxe.c b/core/fs/pxe/pxe.c
index b4ff1f7b..58866afc 100644
--- a/core/fs/pxe/pxe.c
+++ b/core/fs/pxe/pxe.c
@@ -5,11 +5,13 @@
#include <fs.h>
#include <minmax.h>
#include <sys/cpu.h>
-#include "pxe.h"
-#include "thread.h"
#include <lwip/api.h>
#include <lwip/dns.h>
#include <lwip/tcpip.h>
+#include "pxe.h"
+#include "thread.h"
+#include "url.h"
+#include "tftp.h"
static uint16_t real_base_mem; /* Amount of DOS memory after freeing */
@@ -33,10 +35,11 @@ bool have_uuid = false;
/* Common receive buffer */
__lowmem char packet_buf[PKTBUF_SIZE] __aligned(16);
-static struct url_open {
- const char *scheme;
- void (*open)(struct inode *inode, const char *url);
-} url_table[] = {
+static struct url_scheme {
+ const char *name;
+ void (*open)(struct url_info *url, struct inode *inode);
+} url_schemes[] = {
+ { "tftp", tftp_open },
{ "http", http_open },
{ NULL, NULL },
};
@@ -125,18 +128,6 @@ static void uchexbytes(char *dst, const void *src, int count)
}
/*
- * Parse a single hexadecimal byte, which must be complete (two
- * digits). This is used in URL parsing.
- */
-static int hexbyte(const char *p)
-{
- if (!is_hex(p[0]) || !is_hex(p[1]))
- return -1;
- else
- return (hexval(p[0]) << 4) + hexval(p[1]);
-}
-
-/*
* Tests an IP address in _ip_ for validity; return with 0 for bad, 1 for good.
* We used to refuse class E, but class E addresses are likely to become
* assignable unicast addresses in the near future.
@@ -188,36 +179,6 @@ static int gendotquad(char *dst, uint32_t ip)
}
/*
- * parse the ip_str and return the ip address with *res.
- * return the the string address after the ip string
- *
- */
-const char *parse_dotquad(const char *ip_str, uint32_t *res)
-{
- const char *p = ip_str;
- uint8_t part = 0;
- uint32_t ip = 0;
- int i;
-
- for (i = 0; i < 4; i++) {
- while (is_digit(*p)) {
- part = part * 10 + *p - '0';
- p++;
- }
- if (i != 3 && *p != '.')
- return NULL;
-
- ip = (ip << 8) | part;
- part = 0;
- p++;
- }
- p--;
-
- *res = htonl(ip);
- return p;
-}
-
-/*
* the ASM pxenv function wrapper, return 1 if error, or 0
*
*/
@@ -270,59 +231,13 @@ static int pxe_get_cached_info(int type)
return get_cached_info.BufferSize;
}
-
-/*
- * Return the type of pathname passed.
- */
-enum pxe_path_type {
- PXE_RELATIVE, /* No :: or URL */
- PXE_HOMESERVER, /* Starting with :: */
- PXE_TFTP, /* host:: */
- PXE_URL_TFTP, /* tftp:// */
- PXE_URL, /* Absolute URL syntax */
-};
-
-static enum pxe_path_type pxe_path_type(const char *str)
-{
- const char *p;
-
- p = str;
-
- while (1) {
- switch (*p) {
- case ':':
- if (p[1] == ':') {
- if (p == str)
- return PXE_HOMESERVER;
- else
- return PXE_TFTP;
- } else if (p > str && p[1] == '/' && p[2] == '/') {
- if (!strncasecmp(str, "tftp://", 7))
- return PXE_URL_TFTP;
- else
- return PXE_URL;
- }
-
- /* else fall through */
- case '/': case '!': case '@': case '#': case '%':
- case '^': case '&': case '*': case '(': case ')':
- case '[': case ']': case '{': case '}': case '\\':
- case '|': case '=': case '`': case '~': case '\'':
- case '\"': case ';': case '>': case '<': case '?':
- case '\0':
- /* Any of these characters terminate the colon search */
- return PXE_RELATIVE;
- default:
- break;
- }
- p++;
- }
-}
-
/*
* mangle a filename pointed to by _src_ into a buffer pointed
* to by _dst_; ends on encountering any whitespace.
*
+ * This deliberately does not attempt to do any conversion of
+ * pathname separators.
+ *
*/
static void pxe_mangle_name(char *dst, const char *src)
{
@@ -425,6 +340,17 @@ static uint32_t pxe_getfssec(struct file *file, char *buf,
return bytes_read;
}
+/*
+ * Assign an IP address to a URL
+ */
+void url_set_ip(struct url_info *url)
+{
+ url->ip = 0;
+ if (url->host)
+ url->ip = dns_resolv(url->host);
+ if (!url->ip)
+ url->ip = IPInfo.serverip;
+}
/**
* Open the specified connection
@@ -452,119 +378,37 @@ static void __pxe_searchdir(const char *filename, struct file *file)
{
struct fs_info *fs = file->fs;
struct inode *inode;
- const char *np;
- char *buf;
- uint32_t ip = 0;
- enum pxe_path_type path_type;
char fullpath[2*FILENAME_MAX];
- uint16_t server_port = TFTP_PORT; /* TFTP server port */
+ struct url_info url;
+ const struct url_scheme *us;
inode = file->inode = NULL;
- path_type = pxe_path_type(filename);
- if (path_type == PXE_RELATIVE) {
+ strlcpy(fullpath, filename, sizeof fullpath);
+ parse_url(&url, fullpath);
+ if (url.type == URL_SUFFIX) {
snprintf(fullpath, sizeof fullpath, "%s%s", fs->cwd_name, filename);
- path_type = pxe_path_type(filename = fullpath);
- }
-
- switch (path_type) {
- case PXE_RELATIVE: /* Really shouldn't happen... */
- case PXE_URL:
- ip = IPInfo.serverip; /* Default server */
- break;
-
- case PXE_HOMESERVER:
- filename = filename+2;
- ip = IPInfo.serverip;
- break;
-
- case PXE_TFTP:
- np = strchr(filename, ':');
- if (parse_dotquad(filename, &ip) != np)
- ip = dns_resolv(filename);
- filename = np+2;
- break;
-
- case PXE_URL_TFTP:
- np = filename + 7;
- while (*np && *np != '/' && *np != ':')
- np++;
- if (np > filename + 7) {
- if (parse_dotquad(filename + 7, &ip) != np)
- ip = dns_resolv(filename + 7);
- }
- if (*np == ':') {
- np++;
- server_port = 0;
- while (*np >= '0' && *np <= '9')
- server_port = server_port * 10 + *np++ - '0';
- server_port = server_port ? htons(server_port) : TFTP_PORT;
- }
- if (*np == '/')
- np++; /* Do *NOT* eat more than one slash here... */
- /*
- * The ; is because of a quirk in the TFTP URI spec (RFC
- * 3617); it is to be followed by TFTP modes, which we just ignore.
- */
- filename = buf = fullpath;
- while (*np && *np != ';') {
- int v;
- if (*np == '%' && (v = hexbyte(np+1)) > 0) {
- *buf++ = v;
- np += 3;
- } else {
- *buf++ = *np++;
- }
- }
- *buf = '\0';
- break;
+ parse_url(&url, fullpath);
}
inode = allocate_socket(fs);
if (!inode)
return; /* Allocation failure */
- if (path_type == PXE_URL) {
- struct url_open *entry;
- np = strchr(filename, ':');
-
- for (entry = url_table; entry->scheme; entry++) {
- int scheme_len = strlen(entry->scheme);
- if (scheme_len != (np - filename))
- continue;
- if (memcmp(entry->scheme, filename, scheme_len) != 0)
- continue;
- entry->open(inode, filename);
- goto done;
- }
- }
+ url_set_ip(&url);
-#if GPXE
- if (path_type == PXE_URL) {
- if (has_gpxe) {
- gpxe_open(inode, filename);
- goto done;
- } else {
- static bool already = false;
- if (!already) {
- printf("URL syntax, but gPXE extensions not detected, "
- "trying plain TFTP...\n");
- already = true;
- }
+ for (us = url_schemes; us->name; us++) {
+ if (!strcmp(us->name, url.scheme)) {
+ us->open(&url, inode);
+ break;
}
}
-#endif /* GPXE */
- if (!ip)
- goto done; /* No server */
-
- tftp_open(inode, ip, server_port, filename);
-done:
- if (!inode->size) {
+ if (inode->size)
+ file->inode = inode;
+ else
free_socket(inode);
- return;
- }
- file->inode = inode;
+
return;
}
@@ -612,10 +456,8 @@ static void get_prefix(void)
static size_t pxe_realpath(struct fs_info *fs, char *dst, const char *src,
size_t bufsize)
{
- enum pxe_path_type path_type = pxe_path_type(src);
-
return snprintf(dst, bufsize, "%s%s",
- path_type == PXE_RELATIVE ? fs->cwd_name : "", src);
+ url_type(src) == URL_SUFFIX ? fs->cwd_name : "", src);
}
/*
@@ -624,9 +466,7 @@ static size_t pxe_realpath(struct fs_info *fs, char *dst, const char *src,
static int pxe_chdir(struct fs_info *fs, const char *src)
{
/* The cwd for PXE is just a text prefix */
- enum pxe_path_type path_type = pxe_path_type(src);
-
- if (path_type == PXE_RELATIVE)
+ if (url_type(src) == URL_SUFFIX)
strlcat(fs->cwd_name, src, sizeof fs->cwd_name);
else
strlcpy(fs->cwd_name, src, sizeof fs->cwd_name);
diff --git a/core/fs/pxe/pxe.h b/core/fs/pxe/pxe.h
index 0aa3c5a7..bb833d60 100644
--- a/core/fs/pxe/pxe.h
+++ b/core/fs/pxe/pxe.h
@@ -1,7 +1,7 @@
/* -----------------------------------------------------------------------
*
* Copyright 1999-2008 H. Peter Anvin - All Rights Reserved
- * Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
+ * Copyright 2009-2011 Intel Corporation; author: H. Peter Anvin
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -26,7 +26,6 @@
/*
* Some basic defines...
*/
-#define TFTP_PORT htons(69) /* Default TFTP port */
#define TFTP_BLOCKSIZE_LG2 9
#define TFTP_BLOCKSIZE (1 << TFTP_BLOCKSIZE_LG2)
#define PKTBUF_SIZE 2048 /* */
@@ -45,43 +44,16 @@ static inline int hexval(char c)
return (c >= 'A') ? (c & ~0x20) - 'A' + 10 : (c - '0');
}
-/*
- * TFTP operation codes
- */
-#define TFTP_RRQ htons(1) // Read rest
-#define TFTP_WRQ htons(2) // Write rest
-#define TFTP_DATA htons(3) // Data packet
-#define TFTP_ACK htons(4) // ACK packet
-#define TFTP_ERROR htons(5) // ERROR packet
-#define TFTP_OACK htons(6) // OACK packet
-
-/*
- * TFTP error codes
- */
-#define TFTP_EUNDEF htons(0) // Unspecified error
-#define TFTP_ENOTFOUND htons(1) // File not found
-#define TFTP_EACCESS htons(2) // Access violation
-#define TFTP_ENOSPACE htons(3) // Disk full
-#define TFTP_EBADOP htons(4) // Invalid TFTP operation
-#define TFTP_EBADID htons(5) // Unknown transfer
-#define TFTP_EEXISTS htons(6) // File exists
-#define TFTP_ENOUSER htons(7) // No such user
-#define TFTP_EOPTNEG htons(8) // Option negotiation failure
-
-
#define BOOTP_OPTION_MAGIC htonl(0x63825363)
#define MAC_MAX 32
/* Defines for DNS */
-#define DNS_PORT htons(53) /* Default DNS port */
#define DNS_MAX_PACKET 512 /* Defined by protocol */
#define DNS_MAX_SERVERS 4 /* Max no of DNS servers */
-
/*
* structures
*/
-
struct pxenv_t {
uint8_t signature[6]; /* PXENV+ */
uint16_t version;
@@ -247,11 +219,12 @@ void pxe_cleanup_isr(void);
bool install_irq_vector(uint8_t irq, void (*isr)(void), far_ptr_t *old);
/* pxe.c */
+struct url_info;
bool ip_ok(uint32_t);
int pxe_call(int, void *);
extern __lowmem char packet_buf[PKTBUF_SIZE] __aligned(16);
-const char *parse_dotquad(const char *ip_str, uint32_t *res);
int pxe_getc(struct inode *inode);
+void url_set_ip(struct url_info *);
/* undiif.c */
int undiif_start(uint32_t ip, uint32_t netmask, uint32_t gw);
@@ -261,7 +234,6 @@ void undiif_input(t_PXENV_UNDI_ISR *isr);
void parse_dhcp(int);
/* dnsresolv.c */
-int dns_mangle(char **, const char *);
uint32_t dns_resolv(const char *);
/* idle.c */
@@ -273,14 +245,13 @@ uint16_t get_port(void);
void free_port(uint16_t port);
/* tftp.c */
-void tftp_open(struct inode *inode, uint32_t ip, uint16_t server_port,
- const char *filename);
+void tftp_open(struct url_info *url, struct inode *inode);
/* gpxeurl.c */
void gpxe_open(struct inode *inode, const char *url);
#define GPXE 1
/* http.c */
-void http_open(struct inode *inode, const char *url);
+void http_open(struct url_info *url, struct inode *inode);
#endif /* pxe.h */
diff --git a/core/fs/pxe/tftp.c b/core/fs/pxe/tftp.c
index 06566d3f..c5a757c8 100644
--- a/core/fs/pxe/tftp.c
+++ b/core/fs/pxe/tftp.c
@@ -1,6 +1,8 @@
#include <minmax.h>
+#include <lwip/api.h>
#include "pxe.h"
-#include "lwip/api.h"
+#include "url.h"
+#include "tftp.h"
const uint8_t TimeoutTable[] = {
2, 2, 3, 3, 4, 5, 6, 7, 9, 10, 12, 15, 18, 21, 26, 31, 37, 44,
@@ -207,8 +209,7 @@ static void tftp_get_packet(struct inode *inode)
* @out: the lenght of this file, stores in file->file_len
*
*/
-void tftp_open(struct inode *inode, uint32_t ip, uint16_t server_port,
- const char *filename)
+void tftp_open(struct url_info *url, struct inode *inode)
{
struct pxe_pvt_inode *socket = PVT(inode);
char *buf;
@@ -232,6 +233,16 @@ void tftp_open(struct inode *inode, uint32_t ip, uint16_t server_port,
uint32_t opdata, *opdata_ptr;
struct ip_addr addr;
+ if (url->type != URL_OLD_TFTP) {
+ /*
+ * The TFTP URL specification allows the TFTP to end with a
+ * ;mode= which we just ignore.
+ */
+ url_unescape(url->path, ';');
+ }
+ if (!url->port)
+ url->port = TFTP_PORT;
+
socket->fill_buffer = tftp_get_packet;
socket->close = tftp_close_file;
@@ -250,7 +261,7 @@ void tftp_open(struct inode *inode, uint32_t ip, uint16_t server_port,
*(uint16_t *)buf = TFTP_RRQ; /* TFTP opcode */
buf += 2;
- buf = stpcpy(buf, filename);
+ buf = stpcpy(buf, url->path);
buf++; /* Point *past* the final NULL */
memcpy(buf, rrq_tail, sizeof rrq_tail);
@@ -267,11 +278,10 @@ sendreq:
return; /* No file available... */
oldtime = jiffies();
- socket->tftp_remoteip = ip;
nbuf = netbuf_new();
netbuf_ref(nbuf, rrq_packet_buf, rrq_len);
- addr.addr = ip;
- netconn_sendto(socket->conn, nbuf, &addr, ntohs(server_port));
+ addr.addr = socket->tftp_remoteip = url->ip;
+ netconn_sendto(socket->conn, nbuf, &addr, url->port);
netbuf_delete(nbuf);
/* If the WRITE call fails, we let the timeout take care of it... */
diff --git a/core/fs/pxe/tftp.h b/core/fs/pxe/tftp.h
new file mode 100644
index 00000000..b8b7f10e
--- /dev/null
+++ b/core/fs/pxe/tftp.h
@@ -0,0 +1,48 @@
+/* -----------------------------------------------------------------------
+ *
+ * Copyright 1999-2008 H. Peter Anvin - All Rights Reserved
+ * Copyright 2009-2011 Intel Corporation; author: H. Peter Anvin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+ * Boston MA 02111-1307, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * tftp.h
+ */
+#ifndef PXE_TFTP_H
+#define PXE_TFTP_H
+
+/*
+ * TFTP default port number
+ */
+#define TFTP_PORT 69
+
+/*
+ * TFTP operation codes
+ */
+#define TFTP_RRQ htons(1) // Read rest
+#define TFTP_WRQ htons(2) // Write rest
+#define TFTP_DATA htons(3) // Data packet
+#define TFTP_ACK htons(4) // ACK packet
+#define TFTP_ERROR htons(5) // ERROR packet
+#define TFTP_OACK htons(6) // OACK packet
+
+/*
+ * TFTP error codes
+ */
+#define TFTP_EUNDEF htons(0) // Unspecified error
+#define TFTP_ENOTFOUND htons(1) // File not found
+#define TFTP_EACCESS htons(2) // Access violation
+#define TFTP_ENOSPACE htons(3) // Disk full
+#define TFTP_EBADOP htons(4) // Invalid TFTP operation
+#define TFTP_EBADID htons(5) // Unknown transfer
+#define TFTP_EEXISTS htons(6) // File exists
+#define TFTP_ENOUSER htons(7) // No such user
+#define TFTP_EOPTNEG htons(8) // Option negotiation failure
+
+#endif /* PXE_TFTP_H */
diff --git a/core/fs/pxe/url.h b/core/fs/pxe/url.h
index baea2b70..53984f3a 100644
--- a/core/fs/pxe/url.h
+++ b/core/fs/pxe/url.h
@@ -5,10 +5,13 @@
#ifndef CORE_PXE_URL_H
#define CORE_PXE_URL_H
+#include <stddef.h>
+#include <stdint.h>
+
enum url_type {
- URL_NORMAL,
- URL_OLD_TFTP,
- URL_PREFIX
+ URL_NORMAL, /* It is a full URL */
+ URL_OLD_TFTP, /* It's a ::-style TFTP path */
+ URL_SUFFIX /* Prepend the pathname prefix */
};
struct url_info {
@@ -16,13 +19,15 @@ struct url_info {
char *user;
char *passwd;
char *host;
+ uint32_t ip; /* Placeholder field not set by parse_url() */
unsigned int port;
char *path; /* Includes query */
enum url_type type;
};
+enum url_type url_type(const char *url);
void parse_url(struct url_info *ui, char *url);
-char *url_escape_unsafe(const char *input);
+size_t url_escape_unsafe(char *output, const char *input, size_t bufsize);
char *url_unescape(char *buffer, char terminator);
#endif /* CORE_PXE_URL_H */
diff --git a/core/fs/pxe/urlparse.c b/core/fs/pxe/urlparse.c
index 459dca42..bc55197b 100644
--- a/core/fs/pxe/urlparse.c
+++ b/core/fs/pxe/urlparse.c
@@ -35,6 +35,26 @@
#include "url.h"
/*
+ * Return the type of a URL without modifying the string
+ */
+enum url_type url_type(const char *url)
+{
+ const char *q;
+
+ q = strchr(url, ':');
+ if (!q)
+ return URL_SUFFIX;
+
+ if (q[1] == '/' && q[2] == '/')
+ return URL_NORMAL;
+
+ if (q[1] == ':')
+ return URL_OLD_TFTP;
+
+ return URL_SUFFIX;
+}
+
+/*
* Decompose a URL into its components. This is done in-place;
* this routine does not allocate any additional storage. Freeing the
* original buffer frees all storage used.
@@ -43,93 +63,91 @@ void parse_url(struct url_info *ui, char *url)
{
char *p = url;
char *q, *r, *s;
+ int c;
memset(ui, 0, sizeof *ui);
- q = strstr(p, "://");
- if (!q) {
- q = strstr(p, "::");
+ q = strchr(p, ':');
+ if (q && (q[1] == '/' && q[2] == '/')) {
+ ui->type = URL_NORMAL;
+
+ ui->scheme = p;
+ *q = '\0';
+ p = q+3;
+
+ q = strchr(p, '/');
if (q) {
*q = '\0';
- ui->scheme = "tftp";
- ui->host = p;
- ui->path = q+2;
- ui->type = URL_OLD_TFTP;
- return;
+ ui->path = q+1;
+ q = strchr(q+1, '#');
+ if (q)
+ *q = '\0';
} else {
- ui->path = p;
- ui->type = URL_PREFIX;
- return;
+ ui->path = "";
}
- }
-
- ui->type = URL_NORMAL;
-
- ui->scheme = p;
- *q = '\0';
- p = q+3;
-
- q = strchr(p, '/');
- if (q) {
+
+ r = strchr(p, '@');
+ if (r) {
+ ui->user = p;
+ *r = '\0';
+ s = strchr(p, ':');
+ if (s) {
+ *s = '\0';
+ ui->passwd = s+1;
+ }
+ p = r+1;
+ }
+
+ ui->host = p;
+ r = strchr(p, ':');
+ if (r) {
+ *r++ = '\0';
+ ui->port = 0;
+ while ((c = *r++)) {
+ c -= '0';
+ if (c > 9)
+ break;
+ ui->port = ui->port * 10 + c;
+ }
+ }
+ } else if (q && q[1] == ':') {
*q = '\0';
- ui->path = q+1;
- q = strchr(q+1, '#');
- if (q)
- *q = '\0';
+ ui->scheme = "tftp";
+ ui->host = p;
+ ui->path = q+2;
+ ui->type = URL_OLD_TFTP;
} else {
- ui->path = "";
- }
-
- r = strchr(p, '@');
- if (r) {
- ui->user = p;
- *r = '\0';
- s = strchr(p, ':');
- if (s) {
- *s = '\0';
- ui->passwd = s+1;
- }
- p = r+1;
- }
-
- ui->host = p;
- r = strchr(p, ':');
- if (r) {
- *r = '\0';
- ui->port = atoi(r+1);
+ ui->path = p;
+ ui->type = URL_SUFFIX;
}
}
/*
- * Escapes unsafe characters in a URL. Returns a malloc'd buffer.
+ * Escapes unsafe characters in a URL.
+ * This does *not* escape things like query characters!
+ * Returns the number of characters in the total output.
*/
-char *url_escape_unsafe(const char *input)
+size_t url_escape_unsafe(char *output, const char *input, size_t bufsize)
{
- const char *p = input;
+ static const char uchexchar[] = "0123456789ABCDEF";
+ const char *p;
unsigned char c;
- char *out, *q;
+ char *q;
size_t n = 0;
- while ((c = *p++)) {
- if (c < ' ' || c > '~') {
- n += 3; /* Need escaping */
- } else {
- n++;
- }
- }
-
- q = out = malloc(n+1);
- while ((c = *p++)) {
- if (c < ' ' || c > '~') {
- q += snprintf(q, 3, "%%%02X", c);
+ q = output;
+ for (p = input; (c = *p); p++) {
+ if (c <= ' ' || c > '~') {
+ if (++n < bufsize) *q++ = '%';
+ if (++n < bufsize) *q++ = uchexchar[c >> 4];
+ if (++n < bufsize) *q++ = uchexchar[c & 15];
} else {
- *q++ = c;
+ if (++n < bufsize) *q++ = c;
}
}
*q = '\0';
-
- return out;
+ return n;
}
static int hexdigit(char c)