FOR_NET_NETWORK_LEVEL_INTERFACES (inf)
{
/* Am I the protocol address target? */
- if (grub_memcmp (target_protocol_address, &inf->address.ipv4, 6) == 0
+ if (inf->address.type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4
+ && grub_memcmp (target_protocol_address, &inf->address.ipv4, 4) == 0
&& grub_be_to_cpu16 (arp_header->op) == ARP_REQUEST)
{
grub_net_link_level_address_t aux;
#include <grub/dl.h>
#include <grub/command.h>
#include <grub/env.h>
+#include <grub/term.h>
#include <grub/net/ethernet.h>
#include <grub/datetime.h>
{
protnamelen = comma - name;
server = comma + 1;
+ protname = name;
}
else
{
protnamelen = grub_strlen (name);
server = default_server;
+ protname = name;
}
}
if (!server)
{
grub_error (GRUB_ERR_NET_BAD_ADDRESS, "no server");
return NULL;
- }
+ }
FOR_NET_APP_LEVEL (proto)
{
if (grub_memcmp (proto->name, protname, protnamelen) == 0
&& proto->name[protnamelen] == 0)
{
- grub_net_t ret = grub_malloc (sizeof (*ret));
+ grub_net_t ret = grub_zalloc (sizeof (*ret));
if (!ret)
return NULL;
ret->protocol = proto;
ret->server = NULL;
ret->fs = &grub_net_fs;
ret->offset = 0;
+ ret->eof = 0;
return ret;
}
}
static grub_err_t
grub_net_fs_open (struct grub_file *file, const char *name)
{
- grub_err_t err;
- grub_net_network_level_address_t addr;
- struct grub_net_network_level_interface *inf;
- grub_net_network_level_address_t gateway;
- grub_net_socket_t socket;
- static int port = 25300;
-
- err = grub_net_resolve_address (file->device->net->server, &addr);
- if (err)
- return err;
-
- err = grub_net_route_address (addr, &gateway, &inf);
- if (err)
- return err;
-
- socket = (grub_net_socket_t) grub_malloc (sizeof (*socket));
- if (socket == NULL)
- return grub_errno;
-
- socket->inf = inf;
- socket->out_nla = addr;
- socket->in_port = port++;
- socket->status = 0;
- socket->app = file->device->net->protocol;
- socket->packs.first = NULL;
- socket->packs.last = NULL;
- file->device->net->socket = socket;
- grub_net_socket_register (socket);
-
- err = file->device->net->protocol->open (file,name);
- if (err)
- goto fail;
- file->not_easily_seekable = 1;
-
- return GRUB_ERR_NONE;
-fail:
- grub_net_socket_unregister (socket);
- grub_free (socket);
- return err;
+ file->device->net->packs.first = NULL;
+ file->device->net->packs.last = NULL;
+ file->device->net->name = grub_strdup (name);
+ if (!file->device->net->name)
+ return grub_errno;
+ return file->device->net->protocol->open (file, name);
}
static grub_err_t
grub_net_fs_close (grub_file_t file)
{
- grub_net_socket_t sock = file->device->net->socket;
- while (sock->packs.first)
+ while (file->device->net->packs.first)
{
- grub_netbuff_free (sock->packs.first->nb);
- grub_net_remove_packet (sock->packs.first);
+ grub_netbuff_free (file->device->net->packs.first->nb);
+ grub_net_remove_packet (file->device->net->packs.first);
}
- grub_net_socket_unregister (sock);
- grub_free (sock);
+ file->device->net->protocol->close (file);
+ grub_free (file->device->net->name);
return GRUB_ERR_NONE;
-
}
static void
static grub_ssize_t
grub_net_fs_read_real (grub_file_t file, char *buf, grub_size_t len)
{
- grub_net_socket_t sock = file->device->net->socket;
+ grub_net_t sock = file->device->net;
struct grub_net_buff *nb;
- char *ptr = buf;
+ char *ptr = buf;
grub_size_t amount, total = 0;
int try = 0;
while (try <= 3)
if (!len)
return total;
}
- if (sock->status == 1)
+ if (!sock->eof)
{
try++;
grub_net_poll_cards (200);
static grub_err_t
grub_net_seek_real (struct grub_file *file, grub_off_t offset)
{
- grub_net_socket_t sock = file->device->net->socket;
- struct grub_net_buff *nb;
grub_size_t len = offset - file->device->net->offset;
if (!len)
return GRUB_ERR_NONE;
- /* We cant seek backwards past the current packet. */
if (file->device->net->offset > offset)
- {
- nb = sock->packs.first->nb;
- return grub_netbuff_push (nb, file->device->net->offset - offset);
+ {
+ grub_err_t err;
+ while (file->device->net->packs.first)
+ {
+ grub_netbuff_free (file->device->net->packs.first->nb);
+ grub_net_remove_packet (file->device->net->packs.first);
+ }
+ file->device->net->protocol->close (file);
+
+ file->device->net->packs.first = NULL;
+ file->device->net->packs.last = NULL;
+ file->device->net->offset = 0;
+ file->device->net->eof = 0;
+ err = file->device->net->protocol->open (file, file->device->net->name);
+ if (err)
+ return err;
+ len = offset;
}
grub_net_fs_read_real (file, NULL, len);
grub_uint64_t file_size;
grub_uint64_t block;
grub_uint32_t block_size;
+ int have_oack;
+ grub_net_socket_t sock;
} *tftp_data_t;
+static grub_err_t
+tftp_receive (grub_net_socket_t sock __attribute__ ((unused)),
+ struct grub_net_buff *nb,
+ void *f)
+{
+ grub_file_t file = f;
+ struct tftphdr *tftph = (void *) nb->data;
+ char nbdata[512];
+ tftp_data_t data = file->data;
+ grub_err_t err;
+ char *ptr;
+ struct grub_net_buff nb_ack;
+
+ nb_ack.head = nbdata;
+ nb_ack.end = nbdata + sizeof (nbdata);
+
+ tftph = (struct tftphdr *) nb->data;
+ switch (grub_be_to_cpu16 (tftph->opcode))
+ {
+ case TFTP_OACK:
+ data->block_size = 512;
+ data->have_oack = 1;
+ for (ptr = nb->data + sizeof (tftph->opcode); ptr < nb->tail;)
+ {
+ if (grub_memcmp (ptr, "tsize\0", sizeof ("tsize\0") - 1) == 0)
+ {
+ data->file_size = grub_strtoul (ptr + sizeof ("tsize\0") - 1,
+ 0, 0);
+ }
+ if (grub_memcmp (ptr, "blksize\0", sizeof ("blksize\0") - 1) == 0)
+ {
+ data->block_size = grub_strtoul (ptr + sizeof ("blksize\0") - 1,
+ 0, 0);
+ }
+ while (ptr < nb->tail && *ptr)
+ ptr++;
+ ptr++;
+ }
+ data->block = 0;
+ grub_netbuff_free (nb);
+ break;
+ case TFTP_DATA:
+ err = grub_netbuff_pull (nb, sizeof (tftph->opcode) +
+ sizeof (tftph->u.data.block));
+ if (err)
+ return err;
+ if (grub_be_to_cpu16 (tftph->u.data.block) == data->block + 1)
+ {
+ unsigned size = nb->tail - nb->data;
+ data->block++;
+ if (size < data->block_size)
+ {
+ file->device->net->eof = 1;
+ }
+ /* Prevent garbage in broken cards. */
+ if (size > data->block_size)
+ {
+ err = grub_netbuff_unput (nb, size - data->block_size);
+ if (err)
+ return err;
+ }
+ /* If there is data, puts packet in socket list. */
+ if ((nb->tail - nb->data) > 0)
+ grub_net_put_packet (&file->device->net->packs, nb);
+ else
+ grub_netbuff_free (nb);
+ }
+ else
+ {
+ grub_netbuff_free (nb);
+ return GRUB_ERR_NONE;
+ }
+ break;
+ case TFTP_ERROR:
+ grub_netbuff_free (nb);
+ return grub_error (GRUB_ERR_IO, (char *) tftph->u.err.errmsg);
+ }
+ grub_netbuff_clear (&nb_ack);
+ grub_netbuff_reserve (&nb_ack, 512);
+ err = grub_netbuff_push (&nb_ack, sizeof (tftph->opcode)
+ + sizeof (tftph->u.ack.block));
+ if (err)
+ return err;
+
+ tftph = (struct tftphdr *) nb_ack.data;
+ tftph->opcode = grub_cpu_to_be16 (TFTP_ACK);
+ tftph->u.ack.block = grub_cpu_to_be16 (data->block);
+
+ err = grub_net_send_udp_packet (data->sock, &nb_ack);
+ if (file->device->net->eof)
+ {
+ grub_net_udp_close (data->sock);
+ data->sock = NULL;
+ }
+ return err;
+}
+
static grub_err_t
tftp_open (struct grub_file *file, const char *filename)
{
tftp_data_t data;
grub_err_t err;
- data = grub_malloc (sizeof (*data));
+ data = grub_zalloc (sizeof (*data));
if (!data)
return grub_errno;
- file->device->net->socket->data = (void *) data;
nb.head = open_data;
nb.end = open_data + sizeof (open_data);
grub_netbuff_clear (&nb);
grub_netbuff_reserve (&nb, 1500);
- if ((err = grub_netbuff_push (&nb, sizeof (*tftph))) != GRUB_ERR_NONE)
+ err = grub_netbuff_push (&nb, sizeof (*tftph));
+ if (err)
return err;
tftph = (struct tftphdr *) nb.data;
err = grub_netbuff_unput (&nb, nb.tail - (nb.data + hdrlen));
if (err)
return err;
- file->device->net->socket->out_port = TFTP_SERVER_PORT;
- err = grub_net_send_udp_packet (file->device->net->socket, &nb);
+ file->not_easily_seekable = 1;
+ file->data = data;
+ data->sock = grub_net_udp_open (file->device->net->server,
+ TFTP_SERVER_PORT, tftp_receive,
+ file);
+ if (!data->sock)
+ return grub_errno;
+
+ err = grub_net_send_udp_packet (data->sock, &nb);
if (err)
- return err;
+ {
+ grub_net_udp_close (data->sock);
+ return err;
+ }
/* Receive OACK packet. */
for (i = 0; i < 3; i++)
grub_net_poll_cards (100);
if (grub_errno)
return grub_errno;
- if (file->device->net->socket->status != 0)
+ if (data->have_oack)
break;
/* Retry. */
- err = grub_net_send_udp_packet (file->device->net->socket, &nb);
- if (err)
- return err;
- }
-
- if (file->device->net->socket->status == 0)
- return grub_error (GRUB_ERR_TIMEOUT, "Time out opening tftp.");
- file->size = data->file_size;
-
- return GRUB_ERR_NONE;
-}
-
-static grub_err_t
-tftp_receive (grub_net_socket_t sock, struct grub_net_buff *nb)
-{
- struct tftphdr *tftph;
- char nbdata[128];
- tftp_data_t data = sock->data;
- grub_err_t err;
- char *ptr;
- struct grub_net_buff nb_ack;
-
- nb_ack.head = nbdata;
- nb_ack.end = nbdata + sizeof (nbdata);
-
- tftph = (struct tftphdr *) nb->data;
- switch (grub_be_to_cpu16 (tftph->opcode))
- {
- case TFTP_OACK:
- data->block_size = 512;
- for (ptr = nb->data + sizeof (tftph->opcode); ptr < nb->tail;)
- {
- if (grub_memcmp (ptr, "tsize\0", sizeof ("tsize\0") - 1) == 0)
- {
- data->file_size = grub_strtoul (ptr + sizeof ("tsize\0") - 1,
- 0, 0);
- }
- if (grub_memcmp (ptr, "blksize\0", sizeof ("blksize\0") - 1) == 0)
- {
- data->block_size = grub_strtoul (ptr + sizeof ("blksize\0") - 1,
- 0, 0);
- }
- while (ptr < nb->tail && *ptr)
- ptr++;
- ptr++;
- }
- sock->status = 1;
- data->block = 0;
- grub_netbuff_clear (nb);
- break;
- case TFTP_DATA:
- err = grub_netbuff_pull (nb, sizeof (tftph->opcode) +
- sizeof (tftph->u.data.block));
+ err = grub_net_send_udp_packet (data->sock, &nb);
if (err)
- return err;
- if (grub_be_to_cpu16 (tftph->u.data.block) == data->block + 1)
{
- data->block++;
- unsigned size = nb->tail - nb->data;
- if (size < data->block_size)
- sock->status = 2;
- /* Prevent garbage in broken cards. */
- if (size > data->block_size)
- {
- err = grub_netbuff_unput (nb, size - data->block_size);
- if (err)
- return err;
- }
+ grub_net_udp_close (data->sock);
+ return err;
}
- else
- grub_netbuff_clear (nb);
-
- break;
- case TFTP_ERROR:
- grub_netbuff_clear (nb);
- return grub_error (GRUB_ERR_IO, (char *) tftph->u.err.errmsg);
- break;
}
- grub_netbuff_clear (&nb_ack);
- grub_netbuff_reserve (&nb_ack, 128);
- err = grub_netbuff_push (&nb_ack, sizeof (tftph->opcode)
- + sizeof (tftph->u.ack.block));
- if (err)
- return err;
- tftph = (struct tftphdr *) nb_ack.data;
- tftph->opcode = grub_cpu_to_be16 (TFTP_ACK);
- tftph->u.ack.block = grub_cpu_to_be16 (data->block);
+ if (!data->have_oack)
+ {
+ grub_net_udp_close (data->sock);
+ return grub_error (GRUB_ERR_TIMEOUT, "Time out opening tftp.");
+ }
+ file->size = data->file_size;
- err = grub_net_send_udp_packet (sock, &nb_ack);
- return err;
+ return GRUB_ERR_NONE;
}
static grub_err_t
-tftp_close (struct grub_file *file __attribute__ ((unused)))
+tftp_close (struct grub_file *file)
{
- grub_free (file->device->net->socket->data);
+ tftp_data_t data = file->data;
+ if (data->sock)
+ grub_net_udp_close (data->sock);
+ grub_free (data);
return GRUB_ERR_NONE;
}
{
.name = "tftp",
.open = tftp_open,
- .read = tftp_receive,
.close = tftp_close
};
#include <grub/net/netbuff.h>
#include <grub/time.h>
+grub_net_socket_t
+grub_net_udp_open (char *server,
+ grub_uint16_t out_port,
+ grub_err_t (*recv_hook) (grub_net_socket_t sock,
+ struct grub_net_buff *nb,
+ void *data),
+ void *recv_hook_data)
+{
+ grub_err_t err;
+ grub_net_network_level_address_t addr;
+ struct grub_net_network_level_interface *inf;
+ grub_net_network_level_address_t gateway;
+ grub_net_socket_t socket;
+ static int in_port = 25300;
+
+ err = grub_net_resolve_address (server, &addr);
+ if (err)
+ return NULL;
+
+ err = grub_net_route_address (addr, &gateway, &inf);
+ if (err)
+ return NULL;
+
+ socket = grub_zalloc (sizeof (*socket));
+ if (socket == NULL)
+ return NULL;
+
+ socket->x_out_port = out_port;
+ socket->x_inf = inf;
+ socket->x_out_nla = addr;
+ socket->x_in_port = in_port++;
+ socket->x_status = GRUB_NET_SOCKET_START;
+ socket->recv_hook = recv_hook;
+ socket->recv_hook_data = recv_hook_data;
+
+ grub_net_socket_register (socket);
+
+ return socket;
+}
+
grub_err_t
grub_net_send_udp_packet (const grub_net_socket_t socket,
struct grub_net_buff *nb)
return err;
udph = (struct udphdr *) nb->data;
- udph->src = grub_cpu_to_be16 (socket->in_port);
- udph->dst = grub_cpu_to_be16 (socket->out_port);
+ udph->src = grub_cpu_to_be16 (socket->x_in_port);
+ udph->dst = grub_cpu_to_be16 (socket->x_out_port);
/* No chechksum. */
udph->chksum = 0;
udph->len = grub_cpu_to_be16 (nb->tail - nb->data);
- return grub_net_send_ip_packet (socket->inf, &(socket->out_nla), nb);
+ return grub_net_send_ip_packet (socket->x_inf, &(socket->x_out_nla), nb);
}
grub_err_t
FOR_NET_SOCKETS (sock)
{
- if (grub_be_to_cpu16 (udph->dst) == sock->in_port
- && inf == sock->inf && sock->app)
+ if (grub_be_to_cpu16 (udph->dst) == sock->x_in_port
+ && inf == sock->x_inf && sock->recv_hook)
{
- if (sock->status == 0)
- sock->out_port = grub_be_to_cpu16 (udph->src);
+ if (sock->x_status == GRUB_NET_SOCKET_START)
+ {
+ sock->x_out_port = grub_be_to_cpu16 (udph->src);
+ sock->x_status = GRUB_NET_SOCKET_ESTABLISHED;
+ }
/* App protocol remove its own reader. */
- sock->app->read (sock, nb);
-
- /* If there is data, puts packet in socket list. */
- if ((nb->tail - nb->data) > 0)
- grub_net_put_packet (&sock->packs, nb);
- else
- grub_netbuff_free (nb);
+ sock->recv_hook (sock, nb, sock->recv_hook_data);
return GRUB_ERR_NONE;
}
}
int (*hook) (const char *filename,
const struct grub_dirhook_info *info));
grub_err_t (*open) (struct grub_file *file, const char *filename);
- grub_err_t (*read) (grub_net_socket_t sock, struct grub_net_buff *nb);
grub_err_t (*close) (struct grub_file *file);
- grub_err_t (*label) (grub_device_t device, char **label);
};
struct grub_net_socket
{
struct grub_net_socket *next;
- int status;
- int in_port;
- int out_port;
- grub_net_app_level_t app;
- grub_net_network_level_address_t out_nla;
- struct grub_net_network_level_interface *inf;
- grub_net_packets_t packs;
- void *data;
+
+ enum { GRUB_NET_SOCKET_START,
+ GRUB_NET_SOCKET_ESTABLISHED,
+ GRUB_NET_SOCKET_CLOSED } x_status;
+ int x_in_port;
+ int x_out_port;
+ grub_err_t (*recv_hook) (grub_net_socket_t sock, struct grub_net_buff *nb,
+ void *recv);
+ void *recv_hook_data;
+ grub_net_network_level_address_t x_out_nla;
+ struct grub_net_network_level_interface *x_inf;
};
extern struct grub_net_socket *grub_net_sockets;
typedef struct grub_net
{
char *server;
+ char *name;
grub_net_app_level_t protocol;
- grub_net_socket_t socket;
+ grub_net_packets_t packs;
grub_off_t offset;
grub_fs_t fs;
+ int eof;
} *grub_net_t;
extern grub_net_t (*EXPORT_VAR (grub_net_open)) (const char *name);
grub_uint16_t chksum;
} __attribute__ ((packed));
+
+grub_net_socket_t
+grub_net_udp_open (char *server,
+ grub_uint16_t out_port,
+ grub_err_t (*recv_hook) (grub_net_socket_t sock,
+ struct grub_net_buff *nb,
+ void *data),
+ void *recv_hook_data);
+
+static inline void
+grub_net_udp_close (grub_net_socket_t sock)
+{
+ grub_net_socket_unregister (sock);
+ grub_free (sock);
+}
+
grub_err_t
grub_net_send_udp_packet (const grub_net_socket_t socket , struct grub_net_buff *nb);