]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
Restructurisations, cleanups and few bugfixes
authorVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Sat, 2 Jul 2011 20:13:33 +0000 (22:13 +0200)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Sat, 2 Jul 2011 20:13:33 +0000 (22:13 +0200)
grub-core/net/arp.c
grub-core/net/net.c
grub-core/net/tftp.c
grub-core/net/udp.c
include/grub/net.h
include/grub/net/udp.h

index fecde32824b05ee763770cf7e15524216de60fbd..d726f2c3a6b09a51ae3fe891c8aca2fced751d53 100644 (file)
@@ -144,7 +144,8 @@ grub_net_arp_receive (struct grub_net_buff *nb)
   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;
index d5f9e374ec03244c117aeaf10dffbd522f2ab65e..595379a992df13d70ae8b87651bbc6f71d7457ac 100644 (file)
@@ -27,6 +27,7 @@
 #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>
 
@@ -630,25 +631,27 @@ grub_net_open_real (const char *name)
        {
          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;
@@ -665,6 +668,7 @@ grub_net_open_real (const char *name)
          ret->server = NULL;
        ret->fs = &grub_net_fs;
        ret->offset = 0;
+       ret->eof = 0;
        return ret;
       }
   }
@@ -686,61 +690,26 @@ grub_net_fs_dir (grub_device_t device, const char *path __attribute__ ((unused))
 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
@@ -787,9 +756,9 @@ grub_net_poll_cards (unsigned time)
 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)
@@ -820,7 +789,7 @@ grub_net_fs_read_real (grub_file_t file, char *buf, grub_size_t len)
          if (!len)
            return total;
        }
-      if (sock->status == 1)
+      if (!sock->eof)
        {
          try++;
          grub_net_poll_cards (200);
@@ -834,18 +803,29 @@ grub_net_fs_read_real (grub_file_t file, char *buf, grub_size_t len)
 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);
index 700f0effd08d3cb770b801e7fb203cedbfcaeffd..6ffe27669b2be4447db5688f2a45c89e9b4cac22 100644 (file)
@@ -16,8 +16,107 @@ typedef struct tftp_data
   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)
 {
@@ -31,17 +130,17 @@ 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;
@@ -78,11 +177,21 @@ tftp_open (struct grub_file *file, const char *filename)
   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++)
@@ -90,106 +199,34 @@ tftp_open (struct grub_file *file, const char *filename)
       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;
 }
 
@@ -197,7 +234,6 @@ static struct grub_net_app_protocol grub_tftp_protocol =
   {
     .name = "tftp",
     .open = tftp_open,
-    .read = tftp_receive,
     .close = tftp_close
   };
 
index b9339e49a452ae80dc07e62818f7a493edfd1d43..47a67a967a8ce56ab02a7e7c0f28c3edd05b6f91 100644 (file)
@@ -4,6 +4,46 @@
 #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)
@@ -16,14 +56,14 @@ grub_net_send_udp_packet (const grub_net_socket_t socket,
     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
@@ -40,20 +80,17 @@ grub_net_recv_udp_packet (struct grub_net_buff * nb,
 
   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;
       }
   }
index 630fd33fb45e0b02fb95470d0daa53da3399979e..0656787a61a0efcd0a1e3b6b643c5ae6ce5e47f1 100644 (file)
@@ -201,22 +201,23 @@ struct grub_net_app_protocol
                     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;
@@ -240,10 +241,12 @@ grub_net_socket_unregister (grub_net_socket_t sock)
 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);
index eacf3325c93ced7600caa8ede992bc6b2b88cb95..2726122998c75e0407f56cff01fd785b7dcdefb8 100644 (file)
@@ -11,6 +11,22 @@ struct udphdr
   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);