]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
several cleanups. Ping reply support
authorVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Fri, 8 Jul 2011 12:41:52 +0000 (14:41 +0200)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Fri, 8 Jul 2011 12:41:52 +0000 (14:41 +0200)
grub-core/Makefile.core.def
grub-core/net/bootp.c
grub-core/net/icmp.c [new file with mode: 0644]
grub-core/net/ip.c
grub-core/net/tftp.c
grub-core/net/udp.c
include/grub/net.h
include/grub/net/arp.h
include/grub/net/ip.h
include/grub/net/udp.h

index 2d96d67390e6975ebcac90d1324bdbb23e0065f3..9bc8935958e1241da55af74e1259d6257b4ef421 100644 (file)
@@ -1597,6 +1597,7 @@ module = {
   common = net/bootp.c;
   common = net/ip.c;
   common = net/udp.c;
+  common = net/icmp.c;
   common = net/ethernet.c;
   common = net/arp.c;
   common = net/netbuff.c;
index 84bdc04d7e233e650fac3cad7e30dcc5a9ad99a0..1428c2a07fc71be109bc5d4db1898770c515711e 100644 (file)
@@ -488,7 +488,8 @@ grub_cmd_bootp (struct grub_command *cmd __attribute__ ((unused)),
          target.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
          target.ipv4 = 0xffffffff;
 
-         err = grub_net_send_ip_packet (&ifaces[j], &target, nb);
+         err = grub_net_send_ip_packet (&ifaces[j], &target, nb,
+                                        GRUB_NET_IP_UDP);
          grub_netbuff_free (nb);
          if (err)
            return err;
diff --git a/grub-core/net/icmp.c b/grub-core/net/icmp.c
new file mode 100644 (file)
index 0000000..8ea0201
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2010,2011  Free Software Foundation, Inc.
+ *
+ *  GRUB 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, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/net.h>
+#include <grub/net/ip.h>
+#include <grub/net/netbuff.h>
+
+struct icmp_header
+{
+  grub_uint8_t type;
+  grub_uint8_t code;
+  grub_uint16_t checksum;
+};
+
+struct ping_header
+{
+  grub_uint16_t id;
+  grub_uint16_t seq;
+};
+
+enum
+  {
+    ICMP_ECHO_REPLY = 0,
+    ICMP_ECHO = 8,
+  };
+
+grub_err_t
+grub_net_recv_icmp_packet (struct grub_net_buff * nb,
+                          struct grub_net_network_level_interface *inf,
+                          const grub_net_network_level_address_t *src)
+{
+  struct icmp_header *icmph;
+  grub_err_t err;
+  grub_uint16_t checksum;
+
+  icmph = (struct icmp_header *) nb->data;
+
+  if (nb->tail - nb->data < (grub_ssize_t) sizeof (*icmph))
+    return grub_error (GRUB_ERR_OUT_OF_RANGE, "ICMP packet too small");
+
+  checksum = icmph->checksum;
+  icmph->checksum = 0;
+  if (checksum != grub_net_ip_chksum (nb->data, nb->tail - nb->data))
+    return GRUB_ERR_NONE;
+  icmph->checksum = checksum;
+
+  err = grub_netbuff_pull (nb, sizeof (*icmph));
+  if (err)
+    return err;
+
+  switch (icmph->type)
+    {
+    case ICMP_ECHO:
+      {
+       struct grub_net_buff *nb_reply;
+       struct icmp_header *icmphr;
+       if (icmph->code)
+         break;
+       nb_reply = grub_netbuff_alloc (nb->tail - nb->data + 512);
+       if (!nb_reply)
+         {
+           grub_netbuff_free (nb);
+           return grub_errno;
+         }
+       err = grub_netbuff_reserve (nb_reply, nb->tail - nb->data + 512);
+       if (err)
+         goto ping_fail;
+       err = grub_netbuff_push (nb_reply, nb->tail - nb->data);
+       if (err)
+         goto ping_fail;
+       grub_memcpy (nb_reply->data, nb->data, nb->tail - nb->data);
+       err = grub_netbuff_push (nb_reply, sizeof (*icmphr));
+       if (err)
+         goto ping_fail;
+       icmphr = (struct icmp_header *) nb_reply->data;
+       icmphr->type = ICMP_ECHO_REPLY;
+       icmphr->code = 0;
+       icmphr->checksum = 0;
+       icmphr->checksum = grub_net_ip_chksum ((void *) nb_reply->data,
+                                              nb_reply->tail - nb_reply->data);
+       err = grub_net_send_ip_packet (inf, src, nb_reply, GRUB_NET_IP_ICMP);
+
+      ping_fail:
+       grub_netbuff_free (nb);
+       grub_netbuff_free (nb_reply);
+       return err;
+      }
+    };
+
+  grub_netbuff_free (nb);
+  return GRUB_ERR_NONE;
+}
index 642a67f18e42b4a2d0003d076a75dd301728b73a..e2ba4adfbdf1b53e6bf333f8f0a0b30f229d92ca 100644 (file)
@@ -50,18 +50,23 @@ struct ip6hdr
 } __attribute__ ((packed));
 
 grub_uint16_t
-grub_net_ip_chksum (void *ipv, int len)
+grub_net_ip_chksum (void *ipv, grub_size_t len)
 {
   grub_uint16_t *ip = (grub_uint16_t *) ipv;
   grub_uint32_t sum = 0;
 
-  len >>= 1;
-  while (len--)
+  for (; len >= 2; len -= 2)
     {
       sum += grub_be_to_cpu16 (*(ip++));
       if (sum > 0xFFFF)
        sum -= 0xFFFF;
     }
+  if (len)
+    {
+      sum += *((grub_uint8_t *) ip) << 8;
+      if (sum > 0xFFFF)
+       sum -= 0xFFFF;
+    }
 
   return grub_cpu_to_be16 ((~sum) & 0x0000FFFF);
 }
@@ -69,7 +74,8 @@ grub_net_ip_chksum (void *ipv, int len)
 grub_err_t
 grub_net_send_ip_packet (struct grub_net_network_level_interface * inf,
                         const grub_net_network_level_address_t * target,
-                        struct grub_net_buff * nb)
+                        struct grub_net_buff * nb,
+                        grub_net_ip_protocol_t proto)
 {
   struct iphdr *iph;
   static int id = 0x2400;
@@ -85,7 +91,7 @@ grub_net_send_ip_packet (struct grub_net_network_level_interface * inf,
   iph->ident = grub_cpu_to_be16 (++id);
   iph->frags = 0;
   iph->ttl = 0xff;
-  iph->protocol = 0x11;
+  iph->protocol = proto;
   iph->src = inf->address.ipv4;
   iph->dest = target->ipv4;
 
@@ -108,6 +114,7 @@ grub_net_recv_ip_packets (struct grub_net_buff * nb,
   struct iphdr *iph = (struct iphdr *) nb->data;
   grub_err_t err;
   struct grub_net_network_level_interface *inf = NULL;
+  grub_net_network_level_address_t source;
 
   err = grub_netbuff_pull (nb, sizeof (*iph));
   if (err)
@@ -117,7 +124,7 @@ grub_net_recv_ip_packets (struct grub_net_buff * nb,
   {
     struct udphdr *udph;
     udph = (struct udphdr *) nb->data;
-    if (iph->protocol == IP_UDP && grub_be_to_cpu16 (udph->dst) == 68)
+    if (iph->protocol == GRUB_NET_IP_UDP && grub_be_to_cpu16 (udph->dst) == 68)
       {
        FOR_NET_NETWORK_LEVEL_INTERFACES (inf)
          if (inf->card == card
@@ -146,10 +153,15 @@ grub_net_recv_ip_packets (struct grub_net_buff * nb,
       }
     }
 
+  source.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
+  source.ipv4 = iph->src;
+
   switch (iph->protocol)
     {
-    case IP_UDP:
-      return grub_net_recv_udp_packet (nb, inf);
+    case GRUB_NET_IP_UDP:
+      return grub_net_recv_udp_packet (nb, inf, &source);
+    case GRUB_NET_IP_ICMP:
+      return grub_net_recv_icmp_packet (nb, inf, &source);
     default:
       grub_netbuff_free (nb);
       break;
index be153402190aa4fbd390776c29bcf45b9382f77b..13c4971f9b8e20c39e76be40765c448ae5e9650a 100644 (file)
@@ -102,11 +102,11 @@ typedef struct tftp_data
   grub_uint64_t block;
   grub_uint32_t block_size;
   int have_oack;
-  grub_net_socket_t sock;
+  grub_net_udp_socket_t sock;
 } *tftp_data_t;
 
 static grub_err_t
-tftp_receive (grub_net_socket_t sock __attribute__ ((unused)),
+tftp_receive (grub_net_udp_socket_t sock __attribute__ ((unused)),
              struct grub_net_buff *nb,
              void *f)
 {
index 47a67a967a8ce56ab02a7e7c0f28c3edd05b6f91..15bc1f490cbc1cb1b21c02780265f5f713af86b2 100644 (file)
@@ -1,13 +1,66 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2010,2011  Free Software Foundation, Inc.
+ *
+ *  GRUB 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, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
 #include <grub/net.h>
 #include <grub/net/udp.h>
 #include <grub/net/ip.h>
 #include <grub/net/netbuff.h>
 #include <grub/time.h>
 
-grub_net_socket_t
+struct grub_net_udp_socket
+{
+  struct grub_net_udp_socket *next;
+
+  enum { GRUB_NET_SOCKET_START,
+        GRUB_NET_SOCKET_ESTABLISHED,
+        GRUB_NET_SOCKET_CLOSED } status;
+  int in_port;
+  int out_port;
+  grub_err_t (*recv_hook) (grub_net_udp_socket_t sock, struct grub_net_buff *nb,
+                          void *recv);
+  void *recv_hook_data;
+  grub_net_network_level_address_t out_nla;
+  struct grub_net_network_level_interface *inf;
+};
+
+struct grub_net_udp_socket *udp_sockets;
+
+#define FOR_UDP_SOCKETS(var) for (var = udp_sockets; var; var = var->next)
+
+static inline void
+udp_socket_register (grub_net_udp_socket_t sock)
+{
+  grub_list_push (GRUB_AS_LIST_P (&udp_sockets),
+                 GRUB_AS_LIST (sock));
+}
+
+void
+grub_net_udp_close (grub_net_udp_socket_t sock)
+{
+  grub_list_remove (GRUB_AS_LIST_P (&udp_sockets),
+                   GRUB_AS_LIST (sock));
+  grub_free (sock);
+}
+
+grub_net_udp_socket_t
 grub_net_udp_open (char *server,
                   grub_uint16_t out_port,
-                  grub_err_t (*recv_hook) (grub_net_socket_t sock,
+                  grub_err_t (*recv_hook) (grub_net_udp_socket_t sock,
                                            struct grub_net_buff *nb,
                                            void *data),
                   void *recv_hook_data)
@@ -16,12 +69,18 @@ grub_net_udp_open (char *server,
   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;
+  grub_net_udp_socket_t socket;
   static int in_port = 25300;
 
   err = grub_net_resolve_address (server, &addr);
   if (err)
     return NULL;
+
+  if (addr.type != GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4)
+    {
+      grub_error (GRUB_ERR_BAD_ARGUMENT, "not a IPv4 address");
+      return NULL;
+    }
  
   err = grub_net_route_address (addr, &gateway, &inf);
   if (err)
@@ -31,21 +90,21 @@ grub_net_udp_open (char *server,
   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->out_port = out_port;
+  socket->inf = inf;
+  socket->out_nla = addr;
+  socket->in_port = in_port++;
+  socket->status = GRUB_NET_SOCKET_START;
   socket->recv_hook = recv_hook;
   socket->recv_hook_data = recv_hook_data;
 
-  grub_net_socket_register (socket);
+  udp_socket_register (socket);
 
   return socket;
 }
 
 grub_err_t
-grub_net_send_udp_packet (const grub_net_socket_t socket,
+grub_net_send_udp_packet (const grub_net_udp_socket_t socket,
                          struct grub_net_buff *nb)
 {
   struct udphdr *udph;
@@ -56,37 +115,41 @@ 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->x_in_port);
-  udph->dst = grub_cpu_to_be16 (socket->x_out_port);
+  udph->src = grub_cpu_to_be16 (socket->in_port);
+  udph->dst = grub_cpu_to_be16 (socket->out_port);
 
   /* No chechksum. */
   udph->chksum = 0;
   udph->len = grub_cpu_to_be16 (nb->tail - nb->data);
 
-  return grub_net_send_ip_packet (socket->x_inf, &(socket->x_out_nla), nb);
+  return grub_net_send_ip_packet (socket->inf, &(socket->out_nla), nb,
+                                 GRUB_NET_IP_UDP);
 }
 
 grub_err_t
-grub_net_recv_udp_packet (struct grub_net_buff * nb,
-                         struct grub_net_network_level_interface * inf)
+grub_net_recv_udp_packet (struct grub_net_buff *nb,
+                         struct grub_net_network_level_interface *inf,
+                         const grub_net_network_level_address_t *source)
 {
   struct udphdr *udph;
-  grub_net_socket_t sock;
+  grub_net_udp_socket_t sock;
   grub_err_t err;
   udph = (struct udphdr *) nb->data;
   err = grub_netbuff_pull (nb, sizeof (*udph));
   if (err)
     return err;
 
-  FOR_NET_SOCKETS (sock)
+  FOR_UDP_SOCKETS (sock)
   {
-    if (grub_be_to_cpu16 (udph->dst) == sock->x_in_port
-       && inf == sock->x_inf && sock->recv_hook)
+    if (grub_be_to_cpu16 (udph->dst) == sock->in_port
+       && inf == sock->inf && sock->recv_hook
+       && source->type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4
+       && source->ipv4 == sock->out_nla.ipv4)
       {
-       if (sock->x_status == GRUB_NET_SOCKET_START)
+       if (sock->status == GRUB_NET_SOCKET_START)
          {
-           sock->x_out_port = grub_be_to_cpu16 (udph->src);
-           sock->x_status = GRUB_NET_SOCKET_ESTABLISHED;
+           sock->out_port = grub_be_to_cpu16 (udph->src);
+           sock->status = GRUB_NET_SOCKET_ESTABLISHED;
          }
 
        /* App protocol remove its own reader.  */
index 45d08f3f566e6397b6ec2ea7e769bf33bde0eb37..f6600690a8989af0b04df4a369f6025aaf337a7a 100644 (file)
@@ -196,40 +196,6 @@ struct grub_net_app_protocol
   grub_err_t (*close) (struct grub_file *file);
 };
 
-struct grub_net_socket
-{
-  struct grub_net_socket *next;
-
-  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;
-
-static inline void
-grub_net_socket_register (grub_net_socket_t sock)
-{
-  grub_list_push (GRUB_AS_LIST_P (&grub_net_sockets),
-                 GRUB_AS_LIST (sock));
-}
-
-static inline void
-grub_net_socket_unregister (grub_net_socket_t sock)
-{
-  grub_list_remove (GRUB_AS_LIST_P (&grub_net_sockets),
-                   GRUB_AS_LIST (sock));
-}
-
-#define FOR_NET_SOCKETS(var) for (var = grub_net_sockets; var; var = var->next)
-
 typedef struct grub_net
 {
   char *server;
@@ -337,7 +303,7 @@ void
 grub_net_card_unregister (struct grub_net_card *card);
 
 #define FOR_NET_CARDS(var) for (var = grub_net_cards; var; var = var->next)
-#define FOR_NET_CARDS_SAFE(var, next) for (var = grub_net_cards, next = var->next; var; var = next, next = var->next)
+#define FOR_NET_CARDS_SAFE(var, next) for (var = grub_net_cards, next = (var ? var->next : 0); var; var = next, next = (var ? var->next : 0))
 
 
 struct grub_net_session *
@@ -426,7 +392,7 @@ grub_net_addr_to_str (const grub_net_network_level_address_t *target,
 extern struct grub_net_network_level_interface *grub_net_network_level_interfaces;
 #define FOR_NET_NETWORK_LEVEL_INTERFACES(var) for (var = grub_net_network_level_interfaces; var; var = var->next)
 
-#define FOR_NET_NETWORK_LEVEL_INTERFACES_SAFE(var,next) for (var = grub_net_network_level_interfaces, next = var->next; var; var = next, next = var->next)
+#define FOR_NET_NETWORK_LEVEL_INTERFACES_SAFE(var,next) for (var = grub_net_network_level_interfaces, next = (var ? var->next : 0); var; var = next, next = (var ? var->next : 0))
 
 void
 grub_net_poll_cards (unsigned time);
index c60ea333f7bf794acb199c264c8792b76d553286..27a6719c4c68fe058a04438ddf1f03a634686dc2 100644 (file)
@@ -1,3 +1,21 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2010,2011  Free Software Foundation, Inc.
+ *
+ *  GRUB 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, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
 #ifndef GRUB_NET_ARP_HEADER
 #define GRUB_NET_ARP_HEADER    1
 #include <grub/misc.h>
index 9bed1e19cd80ed5dffe3a62eda44f0e980bd29a3..a3c64c1cb2a8e08e4d390458f720c9c4e6ee4680 100644 (file)
 #include <grub/misc.h>
 #include <grub/net.h>
 
-enum
+typedef enum grub_net_ip_protocol
   {
-    IP_UDP =          0x11 /* UDP protocol */
-  };
-#define IP_BROADCAST    0xFFFFFFFF
+    GRUB_NET_IP_ICMP = 1,
+    GRUB_NET_IP_TCP = 6,
+    GRUB_NET_IP_UDP = 17
+  } grub_net_ip_protocol_t;
+#define GRUB_NET_IP_BROADCAST    0xFFFFFFFF
 
-grub_uint16_t grub_net_ip_chksum(void *ipv, int len);
+grub_uint16_t grub_net_ip_chksum(void *ipv, grub_size_t len);
 
 grub_err_t
 grub_net_recv_ip_packets (struct grub_net_buff *nb,
@@ -37,6 +39,16 @@ grub_net_recv_ip_packets (struct grub_net_buff *nb,
 grub_err_t
 grub_net_send_ip_packet (struct grub_net_network_level_interface *inf,
                         const grub_net_network_level_address_t *target,
-                        struct grub_net_buff *nb);
+                        struct grub_net_buff *nb,
+                        grub_net_ip_protocol_t proto);
+
+grub_err_t 
+grub_net_recv_icmp_packet (struct grub_net_buff *nb,
+                          struct grub_net_network_level_interface *inf,
+                          const grub_net_network_level_address_t *src);
+grub_err_t
+grub_net_recv_udp_packet (struct grub_net_buff *nb,
+                         struct grub_net_network_level_interface *inf,
+                         const grub_net_network_level_address_t *src);
 
 #endif 
index 5aacf8abb4ccf758caacd4e02aae39a988f3393f..8d978569d51d84771e723add49a1615a64fb20c4 100644 (file)
@@ -11,28 +11,23 @@ struct udphdr
   grub_uint16_t chksum;
 } __attribute__ ((packed));
 
+struct grub_net_udp_socket;
+typedef struct grub_net_udp_socket *grub_net_udp_socket_t;
 
-grub_net_socket_t
+grub_net_udp_socket_t
 grub_net_udp_open (char *server,
                   grub_uint16_t out_port,
-                  grub_err_t (*recv_hook) (grub_net_socket_t sock,
+                  grub_err_t (*recv_hook) (grub_net_udp_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);
-}
+void
+grub_net_udp_close (grub_net_udp_socket_t sock);
 
 grub_err_t
-grub_net_send_udp_packet (const grub_net_socket_t socket, struct grub_net_buff *nb);
-
-grub_err_t 
-grub_net_recv_udp_packet (struct grub_net_buff *nb,
-                         struct grub_net_network_level_interface *inf);
+grub_net_send_udp_packet (const grub_net_udp_socket_t socket,
+                         struct grub_net_buff *nb);
 
 
 #endif