source: grub-pc/trunk/fuentes/grub-core/net/net.c @ 22

Last change on this file since 22 was 22, checked in by mabarracus, 4 years ago

updated version and apply net.ifnames=0 into debian/rules

File size: 44.4 KB
Line 
1/*
2 *  GRUB  --  GRand Unified Bootloader
3 *  Copyright (C) 2010,2011,2012,2013  Free Software Foundation, Inc.
4 *
5 *  GRUB is free software: you can redistribute it and/or modify
6 *  it under the terms of the GNU General Public License as published by
7 *  the Free Software Foundation, either version 3 of the License, or
8 *  (at your option) any later version.
9 *
10 *  GRUB is distributed in the hope that it will be useful,
11 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 *  GNU General Public License for more details.
14 *
15 *  You should have received a copy of the GNU General Public License
16 *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include <grub/net.h>
20#include <grub/net/netbuff.h>
21#include <grub/time.h>
22#include <grub/file.h>
23#include <grub/i18n.h>
24#include <grub/mm.h>
25#include <grub/misc.h>
26#include <grub/dl.h>
27#include <grub/command.h>
28#include <grub/env.h>
29#include <grub/net/ethernet.h>
30#include <grub/net/arp.h>
31#include <grub/net/ip.h>
32#include <grub/loader.h>
33#include <grub/bufio.h>
34#include <grub/kernel.h>
35
36GRUB_MOD_LICENSE ("GPLv3+");
37
38char *grub_net_default_server;
39
40struct grub_net_route
41{
42  struct grub_net_route *next;
43  struct grub_net_route **prev;
44  grub_net_network_level_netaddress_t target;
45  char *name;
46  struct grub_net_network_level_protocol *prot;
47  int is_gateway;
48  union
49  {
50    struct grub_net_network_level_interface *interface;
51    grub_net_network_level_address_t gw;
52  };
53};
54
55struct grub_net_route *grub_net_routes = NULL;
56struct grub_net_network_level_interface *grub_net_network_level_interfaces = NULL;
57struct grub_net_card *grub_net_cards = NULL;
58struct grub_net_network_level_protocol *grub_net_network_level_protocols = NULL;
59static struct grub_fs grub_net_fs;
60
61struct grub_net_link_layer_entry {
62  int avail;
63  grub_net_network_level_address_t nl_address;
64  grub_net_link_level_address_t ll_address;
65};
66
67#define LINK_LAYER_CACHE_SIZE 256
68
69static struct grub_net_link_layer_entry *
70link_layer_find_entry (const grub_net_network_level_address_t *proto,
71                       const struct grub_net_card *card)
72{
73  unsigned i;
74  if (!card->link_layer_table)
75    return NULL;
76  for (i = 0; i < LINK_LAYER_CACHE_SIZE; i++)
77    {
78      if (card->link_layer_table[i].avail == 1 
79          && grub_net_addr_cmp (&card->link_layer_table[i].nl_address,
80                                proto) == 0)
81        return &card->link_layer_table[i];
82    }
83  return NULL;
84}
85
86void
87grub_net_link_layer_add_address (struct grub_net_card *card,
88                                 const grub_net_network_level_address_t *nl,
89                                 const grub_net_link_level_address_t *ll,
90                                 int override)
91{
92  struct grub_net_link_layer_entry *entry;
93
94  /* Check if the sender is in the cache table.  */
95  entry = link_layer_find_entry (nl, card);
96  /* Update sender hardware address.  */
97  if (entry && override)
98    grub_memcpy (&entry->ll_address, ll, sizeof (entry->ll_address));
99  if (entry)
100    return;
101
102  /* Add sender to cache table.  */
103  if (card->link_layer_table == NULL)
104    card->link_layer_table = grub_zalloc (LINK_LAYER_CACHE_SIZE
105                                          * sizeof (card->link_layer_table[0]));
106  entry = &(card->link_layer_table[card->new_ll_entry]);
107  entry->avail = 1;
108  grub_memcpy (&entry->ll_address, ll, sizeof (entry->ll_address));
109  grub_memcpy (&entry->nl_address, nl, sizeof (entry->nl_address));
110  card->new_ll_entry++;
111  if (card->new_ll_entry == LINK_LAYER_CACHE_SIZE)
112    card->new_ll_entry = 0;
113}
114
115int
116grub_net_link_layer_resolve_check (struct grub_net_network_level_interface *inf,
117                                   const grub_net_network_level_address_t *proto_addr)
118{
119  struct grub_net_link_layer_entry *entry;
120
121  if (proto_addr->type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4
122      && proto_addr->ipv4 == 0xffffffff)
123    return 1;
124  entry = link_layer_find_entry (proto_addr, inf->card);
125  if (entry)
126    return 1;
127  return 0;
128}
129
130grub_err_t
131grub_net_link_layer_resolve (struct grub_net_network_level_interface *inf,
132                             const grub_net_network_level_address_t *proto_addr,
133                             grub_net_link_level_address_t *hw_addr)
134{
135  struct grub_net_link_layer_entry *entry;
136  grub_err_t err;
137
138  if ((proto_addr->type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4
139       && proto_addr->ipv4 == 0xffffffff)
140      || proto_addr->type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_DHCP_RECV
141      || (proto_addr->type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6
142          && proto_addr->ipv6[0] == grub_be_to_cpu64_compile_time (0xff02ULL
143                                                                   << 48)
144          && proto_addr->ipv6[1] == (grub_be_to_cpu64_compile_time (1))))
145    {
146      hw_addr->type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
147      grub_memset (hw_addr->mac, -1, 6);
148      return GRUB_ERR_NONE;
149    }
150
151  if (proto_addr->type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6
152      && ((grub_be_to_cpu64 (proto_addr->ipv6[0]) >> 56) == 0xff))
153    {
154      hw_addr->type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
155      hw_addr->mac[0] = 0x33;
156      hw_addr->mac[1] = 0x33;
157      hw_addr->mac[2] = ((grub_be_to_cpu64 (proto_addr->ipv6[1]) >> 24) & 0xff);
158      hw_addr->mac[3] = ((grub_be_to_cpu64 (proto_addr->ipv6[1]) >> 16) & 0xff);
159      hw_addr->mac[4] = ((grub_be_to_cpu64 (proto_addr->ipv6[1]) >> 8) & 0xff);
160      hw_addr->mac[5] = ((grub_be_to_cpu64 (proto_addr->ipv6[1]) >> 0) & 0xff);
161      return GRUB_ERR_NONE;
162    }
163
164  /* Check cache table.  */
165  entry = link_layer_find_entry (proto_addr, inf->card);
166  if (entry)
167    {
168      *hw_addr = entry->ll_address;
169      return GRUB_ERR_NONE;
170    }
171  switch (proto_addr->type)
172    {
173    case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4:
174      err = grub_net_arp_send_request (inf, proto_addr);
175      break;
176    case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6:
177      err = grub_net_icmp6_send_request (inf, proto_addr);
178      break;
179    case GRUB_NET_NETWORK_LEVEL_PROTOCOL_DHCP_RECV:
180      return grub_error (GRUB_ERR_BUG, "shouldn't reach here");
181    default:
182      return grub_error (GRUB_ERR_BUG,
183                         "unsupported address type %d", proto_addr->type);
184    }
185  if (err)
186    return err;
187  entry = link_layer_find_entry (proto_addr, inf->card);
188  if (entry)
189    {
190      *hw_addr = entry->ll_address;
191      return GRUB_ERR_NONE;
192    }
193  return grub_error (GRUB_ERR_TIMEOUT, 
194                     N_("timeout: could not resolve hardware address"));
195}
196
197void
198grub_net_card_unregister (struct grub_net_card *card)
199{
200  struct grub_net_network_level_interface *inf, *next;
201  FOR_NET_NETWORK_LEVEL_INTERFACES_SAFE(inf, next)
202    if (inf->card == card)
203      grub_net_network_level_interface_unregister (inf);
204  if (card->opened)
205    {
206      if (card->driver->close)
207        card->driver->close (card);
208      card->opened = 0;
209    }
210  grub_list_remove (GRUB_AS_LIST (card));
211}
212
213static struct grub_net_slaac_mac_list *
214grub_net_ipv6_get_slaac (struct grub_net_card *card,
215                         const grub_net_link_level_address_t *hwaddr)
216{
217  struct grub_net_slaac_mac_list *slaac;
218  char *ptr;
219
220  for (slaac = card->slaac_list; slaac; slaac = slaac->next)
221    if (grub_net_hwaddr_cmp (&slaac->address, hwaddr) == 0)
222      return slaac;
223
224  slaac = grub_zalloc (sizeof (*slaac));
225  if (!slaac)
226    return NULL;
227
228  slaac->name = grub_malloc (grub_strlen (card->name)
229                             + GRUB_NET_MAX_STR_HWADDR_LEN
230                             + sizeof (":slaac"));
231  ptr = grub_stpcpy (slaac->name, card->name);
232  if (grub_net_hwaddr_cmp (&card->default_address, hwaddr) != 0)
233    {
234      ptr = grub_stpcpy (ptr, ":");
235      grub_net_hwaddr_to_str (hwaddr, ptr);
236      ptr += grub_strlen (ptr);
237    }
238  ptr = grub_stpcpy (ptr, ":slaac");
239
240  grub_memcpy (&slaac->address, hwaddr, sizeof (slaac->address));
241  slaac->next = card->slaac_list;
242  card->slaac_list = slaac;
243  return slaac;
244}
245
246static void
247grub_net_network_level_interface_register (struct grub_net_network_level_interface *inter);
248
249static struct grub_net_network_level_interface *
250grub_net_add_addr_real (char *name, 
251                        struct grub_net_card *card,
252                        const grub_net_network_level_address_t *addr,
253                        const grub_net_link_level_address_t *hwaddress,
254                        grub_net_interface_flags_t flags)
255{
256  struct grub_net_network_level_interface *inter;
257
258  inter = grub_zalloc (sizeof (*inter));
259  if (!inter)
260    return NULL;
261
262  inter->name = name;
263  grub_memcpy (&(inter->address), addr, sizeof (inter->address));
264  grub_memcpy (&(inter->hwaddress), hwaddress, sizeof (inter->hwaddress));
265  inter->flags = flags;
266  inter->card = card;
267  inter->dhcp_ack = NULL;
268  inter->dhcp_acklen = 0;
269
270  grub_net_network_level_interface_register (inter);
271
272  return inter;
273}
274
275struct grub_net_network_level_interface *
276grub_net_add_addr (const char *name, 
277                   struct grub_net_card *card,
278                   const grub_net_network_level_address_t *addr,
279                   const grub_net_link_level_address_t *hwaddress,
280                   grub_net_interface_flags_t flags)
281{
282  char *name_dup = grub_strdup (name);
283  struct grub_net_network_level_interface *ret;
284 
285  if (!name_dup)
286    return NULL;
287  ret = grub_net_add_addr_real (name_dup, card, addr, hwaddress, flags);
288  if (!ret)
289    grub_free (name_dup);
290  return ret;
291}
292
293struct grub_net_network_level_interface *
294grub_net_ipv6_get_link_local (struct grub_net_card *card,
295                              const grub_net_link_level_address_t *hwaddr)
296{
297  struct grub_net_network_level_interface *inf;
298  char *name;
299  char *ptr;
300  grub_net_network_level_address_t addr;
301
302  name = grub_malloc (grub_strlen (card->name)
303                      + GRUB_NET_MAX_STR_HWADDR_LEN
304                      + sizeof (":link"));
305  if (!name)
306    return NULL;
307
308  addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
309  addr.ipv6[0] = grub_cpu_to_be64 (0xfe80ULL << 48);
310  addr.ipv6[1] = grub_net_ipv6_get_id (hwaddr);
311
312  FOR_NET_NETWORK_LEVEL_INTERFACES (inf)
313  {
314    if (inf->card == card
315        && grub_net_hwaddr_cmp (&inf->hwaddress, hwaddr) == 0
316        && grub_net_addr_cmp (&inf->address, &addr) == 0)
317      return inf;
318  }
319
320  ptr = grub_stpcpy (name, card->name);
321  if (grub_net_hwaddr_cmp (&card->default_address, hwaddr) != 0)
322    {
323      ptr = grub_stpcpy (ptr, ":");
324      grub_net_hwaddr_to_str (hwaddr, ptr);
325      ptr += grub_strlen (ptr);
326    }
327  ptr = grub_stpcpy (ptr, ":link");
328  return grub_net_add_addr_real (name, card, &addr, hwaddr, 0);
329}
330
331/* FIXME: allow to specify mac address.  */
332static grub_err_t
333grub_cmd_ipv6_autoconf (struct grub_command *cmd __attribute__ ((unused)),
334                        int argc, char **args)
335{
336  struct grub_net_card *card;
337  struct grub_net_network_level_interface **ifaces;
338  grub_size_t ncards = 0;
339  unsigned j = 0;
340  int interval;
341  grub_err_t err;
342  struct grub_net_slaac_mac_list **slaacs;
343
344  FOR_NET_CARDS (card)
345  {
346    if (argc > 0 && grub_strcmp (card->name, args[0]) != 0)
347      continue;
348    ncards++;
349  }
350
351  ifaces = grub_zalloc (ncards * sizeof (ifaces[0]));
352  slaacs = grub_zalloc (ncards * sizeof (slaacs[0]));
353  if (!ifaces || !slaacs)
354    {
355      grub_free (ifaces);
356      grub_free (slaacs);
357      return grub_errno;
358    }
359
360  FOR_NET_CARDS (card)
361  {
362    if (argc > 0 && grub_strcmp (card->name, args[0]) != 0)
363      continue;
364    ifaces[j] = grub_net_ipv6_get_link_local (card, &card->default_address);
365    if (!ifaces[j])
366      {
367        grub_free (ifaces);
368        grub_free (slaacs);
369        return grub_errno;
370      }
371    slaacs[j] = grub_net_ipv6_get_slaac (card, &card->default_address);
372    if (!slaacs[j])
373      {
374        grub_free (ifaces);
375        grub_free (slaacs);
376        return grub_errno;
377      }
378    j++;
379  }
380
381  for (interval = 200; interval < 10000; interval *= 2)
382    {
383      /* FIXME: send router solicitation.  */
384      int done = 1;
385      for (j = 0; j < ncards; j++)
386        {
387          if (slaacs[j]->slaac_counter)
388            continue;
389          done = 0;
390        }
391      if (done)
392        break;
393      grub_net_poll_cards (interval, 0);
394    }
395
396  err = GRUB_ERR_NONE;
397  for (j = 0; j < ncards; j++)
398    {
399      if (slaacs[j]->slaac_counter)
400        continue;
401      err = grub_error (GRUB_ERR_FILE_NOT_FOUND,
402                        N_("couldn't autoconfigure %s"),
403                        ifaces[j]->card->name);
404    }
405
406  grub_free (ifaces);
407  grub_free (slaacs);
408  return err;
409}
410
411static inline void
412grub_net_route_register (struct grub_net_route *route)
413{
414  grub_list_push (GRUB_AS_LIST_P (&grub_net_routes),
415                  GRUB_AS_LIST (route));
416}
417
418#define FOR_NET_ROUTES(var) for (var = grub_net_routes; var; var = var->next)
419
420static int
421parse_ip (const char *val, grub_uint32_t *ip, const char **rest)
422{
423  grub_uint32_t newip = 0;
424  int i;
425  const char *ptr = val;
426
427  for (i = 0; i < 4; i++)
428    {
429      unsigned long t;
430      t = grub_strtoul (ptr, (char **) &ptr, 0);
431      if (grub_errno)
432        {
433          grub_errno = GRUB_ERR_NONE;
434          return 0;
435        }
436      if (*ptr != '.' && i == 0)
437        {
438          newip = t;
439          break;
440        }
441      if (t & ~0xff)
442        return 0;
443      newip >>= 8;
444      newip |= (t << 24);
445      if (i != 3 && *ptr != '.')
446        return 0;
447      ptr++;
448    }
449  *ip = grub_cpu_to_le32 (newip);
450  if (rest)
451    *rest = (ptr - 1);
452  return 1;
453}
454
455static int
456parse_ip6 (const char *val, grub_uint64_t *ip, const char **rest)
457{
458  grub_uint16_t newip[8];
459  const char *ptr = val;
460  int word, quaddot = -1;
461
462  if (ptr[0] == ':' && ptr[1] != ':')
463    return 0;
464  if (ptr[0] == ':')
465    ptr++;
466
467  for (word = 0; word < 8; word++)
468    {
469      unsigned long t;
470      if (*ptr == ':')
471        {
472          quaddot = word;
473          word--;
474          ptr++;
475          continue;
476        }
477      t = grub_strtoul (ptr, (char **) &ptr, 16);
478      if (grub_errno)
479        {
480          grub_errno = GRUB_ERR_NONE;
481          break;
482        }
483      if (t & ~0xffff)
484        return 0;
485      newip[word] = grub_cpu_to_be16 (t);
486      if (*ptr != ':')
487        break;
488      ptr++;
489    }
490  if (quaddot == -1 && word < 7)
491    return 0;
492  if (quaddot != -1)
493    {
494      grub_memmove (&newip[quaddot + 7 - word], &newip[quaddot],
495                    (word - quaddot + 1) * sizeof (newip[0]));
496      grub_memset (&newip[quaddot], 0, (7 - word) * sizeof (newip[0]));
497    }
498  grub_memcpy (ip, newip, 16);
499  if (rest)
500    *rest = ptr;
501  return 1;
502}
503
504static int
505match_net (const grub_net_network_level_netaddress_t *net,
506           const grub_net_network_level_address_t *addr)
507{
508  if (net->type != addr->type)
509    return 0;
510  switch (net->type)
511    {
512    case GRUB_NET_NETWORK_LEVEL_PROTOCOL_DHCP_RECV:
513      return 0;
514    case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4:
515      {
516        grub_uint32_t mask = (0xffffffffU << (32 - net->ipv4.masksize));
517        if (net->ipv4.masksize == 0)
518          mask = 0;
519        return ((grub_be_to_cpu32 (net->ipv4.base) & mask)
520                == (grub_be_to_cpu32 (addr->ipv4) & mask));
521      }
522    case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6:
523      {
524        grub_uint64_t mask[2];
525        if (net->ipv6.masksize <= 64)
526          {
527            mask[0] = 0xffffffffffffffffULL << (64 - net->ipv6.masksize);
528            mask[1] = 0;
529          }
530        else 
531          {
532            mask[0] = 0xffffffffffffffffULL;
533            mask[1] = 0xffffffffffffffffULL << (128 - net->ipv6.masksize);
534          }
535        return (((grub_be_to_cpu64 (net->ipv6.base[0]) & mask[0])
536                == (grub_be_to_cpu64 (addr->ipv6[0]) & mask[0]))
537                && ((grub_be_to_cpu64 (net->ipv6.base[1]) & mask[1])
538                    == (grub_be_to_cpu64 (addr->ipv6[1]) & mask[1])));
539      }
540    }
541  return 0;
542}
543
544grub_err_t
545grub_net_resolve_address (const char *name,
546                          grub_net_network_level_address_t *addr)
547{
548  const char *rest;
549  grub_err_t err;
550  grub_size_t naddresses;
551  struct grub_net_network_level_address *addresses = 0;
552
553  if (parse_ip (name, &addr->ipv4, &rest) && *rest == 0)
554    {
555      addr->type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
556      return GRUB_ERR_NONE;
557    }
558  if (parse_ip6 (name, addr->ipv6, &rest) && *rest == 0)
559    {
560      addr->type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
561      return GRUB_ERR_NONE;
562    }
563  err = grub_net_dns_lookup (name, 0, 0, &naddresses, &addresses, 1);
564  if (err)
565    return err;
566  if (!naddresses)
567    grub_error (GRUB_ERR_NET_BAD_ADDRESS, N_("unresolvable address %s"),
568                name);
569  /* FIXME: use other results as well.  */
570  *addr = addresses[0];
571  grub_free (addresses);
572  return GRUB_ERR_NONE;
573}
574
575grub_err_t
576grub_net_resolve_net_address (const char *name,
577                              grub_net_network_level_netaddress_t *addr)
578{
579  const char *rest;
580  if (parse_ip (name, &addr->ipv4.base, &rest))
581    {
582      addr->type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
583      if (*rest == '/')
584        {
585          addr->ipv4.masksize = grub_strtoul (rest + 1, (char **) &rest, 0);
586          if (!grub_errno && *rest == 0)
587            return GRUB_ERR_NONE;
588          grub_errno = GRUB_ERR_NONE;
589        }
590      else if (*rest == 0)
591        {
592          addr->ipv4.masksize = 32;
593          return GRUB_ERR_NONE;
594        }
595    }
596  if (parse_ip6 (name, addr->ipv6.base, &rest))
597    {
598      addr->type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
599      if (*rest == '/')
600        {
601          addr->ipv6.masksize = grub_strtoul (rest + 1, (char **) &rest, 0);
602          if (!grub_errno && *rest == 0)
603            return GRUB_ERR_NONE;
604          grub_errno = GRUB_ERR_NONE;
605        }
606      else if (*rest == 0)
607        {
608          addr->ipv6.masksize = 128;
609          return GRUB_ERR_NONE;
610        }
611    }
612  return grub_error (GRUB_ERR_NET_BAD_ADDRESS,
613                     N_("unrecognised network address `%s'"),
614                     name);
615}
616
617static int
618route_cmp (const struct grub_net_route *a, const struct grub_net_route *b)
619{
620  if (a == NULL && b == NULL)
621    return 0;
622  if (b == NULL)
623    return +1;
624  if (a == NULL)
625    return -1;
626  if (a->target.type < b->target.type)
627    return -1;
628  if (a->target.type > b->target.type)
629    return +1;
630  switch (a->target.type)
631    {
632    case GRUB_NET_NETWORK_LEVEL_PROTOCOL_DHCP_RECV:
633      break;
634    case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6:
635      if (a->target.ipv6.masksize > b->target.ipv6.masksize)
636        return +1;
637      if (a->target.ipv6.masksize < b->target.ipv6.masksize)
638        return -1;
639      break;
640    case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4:
641      if (a->target.ipv4.masksize > b->target.ipv4.masksize)
642        return +1;
643      if (a->target.ipv4.masksize < b->target.ipv4.masksize)
644        return -1;
645      break;
646    }
647  return 0;
648}
649
650grub_err_t
651grub_net_route_address (grub_net_network_level_address_t addr,
652                        grub_net_network_level_address_t *gateway,
653                        struct grub_net_network_level_interface **interf)
654{
655  struct grub_net_route *route;
656  unsigned int depth = 0;
657  unsigned int routecnt = 0;
658  struct grub_net_network_level_protocol *prot = NULL;
659  grub_net_network_level_address_t curtarget = addr;
660
661  *gateway = addr;
662
663  FOR_NET_ROUTES(route)
664    routecnt++;
665
666  for (depth = 0; depth < routecnt + 2 && depth < GRUB_UINT_MAX; depth++)
667    {
668      struct grub_net_route *bestroute = NULL;
669      FOR_NET_ROUTES(route)
670      {
671        if (depth && prot != route->prot)
672          continue;
673        if (!match_net (&route->target, &curtarget))
674          continue;
675        if (route_cmp (route, bestroute) > 0)
676          bestroute = route;
677      }
678      if (bestroute == NULL)
679        return grub_error (GRUB_ERR_NET_NO_ROUTE,
680                           N_("destination unreachable"));
681
682      if (!bestroute->is_gateway)
683        {
684          *interf = bestroute->interface;
685          return GRUB_ERR_NONE;
686        }
687      if (depth == 0)
688        *gateway = bestroute->gw;
689      curtarget = bestroute->gw;
690    }
691
692  return grub_error (GRUB_ERR_NET_ROUTE_LOOP,
693                     /* TRANSLATORS: route loop is a condition when e.g.
694                        to contact server A you need to go through B
695                        and to contact B you need to go through A.  */
696                     N_("route loop detected"));
697}
698
699static grub_err_t
700grub_cmd_deladdr (struct grub_command *cmd __attribute__ ((unused)),
701                  int argc, char **args)
702{
703  struct grub_net_network_level_interface *inter;
704
705  if (argc != 1)
706    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
707
708  FOR_NET_NETWORK_LEVEL_INTERFACES (inter)
709    if (grub_strcmp (inter->name, args[0]) == 0)
710      break;
711  if (inter == NULL)
712    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("address not found"));
713
714  if (inter->flags & GRUB_NET_INTERFACE_PERMANENT)
715    return grub_error (GRUB_ERR_IO,
716                       N_("you can't delete this address"));
717
718  grub_net_network_level_interface_unregister (inter);
719  grub_free (inter->name);
720  grub_free (inter);
721
722  return GRUB_ERR_NONE; 
723}
724
725void
726grub_net_addr_to_str (const grub_net_network_level_address_t *target, char *buf)
727{
728  switch (target->type)
729    {
730    case GRUB_NET_NETWORK_LEVEL_PROTOCOL_DHCP_RECV:
731      COMPILE_TIME_ASSERT (sizeof ("temporary") < GRUB_NET_MAX_STR_ADDR_LEN);
732      grub_strcpy (buf, "temporary");
733      return;
734    case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6:
735      {
736        char *ptr = buf;
737        grub_uint64_t n = grub_be_to_cpu64 (target->ipv6[0]);
738        int i;
739        for (i = 0; i < 4; i++)
740          {
741            grub_snprintf (ptr, 6, "%" PRIxGRUB_UINT64_T ":",
742                           (n >> (48 - 16 * i)) & 0xffff);
743            ptr += grub_strlen (ptr); 
744          }
745        n  = grub_be_to_cpu64 (target->ipv6[1]);
746        for (i = 0; i < 3; i++)
747          {
748            grub_snprintf (ptr, 6, "%" PRIxGRUB_UINT64_T ":",
749                           (n >> (48 - 16 * i)) & 0xffff);
750            ptr += grub_strlen (ptr); 
751          }
752        grub_snprintf (ptr, 5, "%" PRIxGRUB_UINT64_T, n & 0xffff);
753        return;
754      }
755    case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4:
756      {
757        grub_uint32_t n = grub_be_to_cpu32 (target->ipv4);
758        grub_snprintf (buf, GRUB_NET_MAX_STR_ADDR_LEN, "%d.%d.%d.%d",
759                       ((n >> 24) & 0xff), ((n >> 16) & 0xff),
760                       ((n >> 8) & 0xff), ((n >> 0) & 0xff));
761      }
762      return;
763    }
764  grub_snprintf (buf, GRUB_NET_MAX_STR_ADDR_LEN,
765                 "Unknown address type %d", target->type);
766}
767
768
769void
770grub_net_hwaddr_to_str (const grub_net_link_level_address_t *addr, char *str)
771{
772  str[0] = 0;
773  switch (addr->type)
774    {
775    case GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET:
776      {
777        char *ptr;
778        unsigned i;
779        for (ptr = str, i = 0; i < ARRAY_SIZE (addr->mac); i++)
780          {
781            grub_snprintf (ptr, GRUB_NET_MAX_STR_HWADDR_LEN - (ptr - str),
782                           "%02x:", addr->mac[i] & 0xff);
783            ptr += (sizeof ("XX:") - 1);
784          }
785      return;
786      }
787    }
788  grub_printf (_("Unsupported hw address type %d\n"), addr->type);
789}
790
791int
792grub_net_hwaddr_cmp (const grub_net_link_level_address_t *a,
793                     const grub_net_link_level_address_t *b)
794{
795  if (a->type < b->type)
796    return -1;
797  if (a->type > b->type)
798    return +1;
799  switch (a->type)
800    {
801    case GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET:
802      return grub_memcmp (a->mac, b->mac, sizeof (a->mac));
803    }
804  grub_printf (_("Unsupported hw address type %d\n"), a->type);
805  return 1;
806}
807
808int
809grub_net_addr_cmp (const grub_net_network_level_address_t *a,
810                   const grub_net_network_level_address_t *b)
811{
812  if (a->type < b->type)
813    return -1;
814  if (a->type > b->type)
815    return +1;
816  switch (a->type)
817    {
818    case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4:
819      return grub_memcmp (&a->ipv4, &b->ipv4, sizeof (a->ipv4));
820    case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6:
821      return grub_memcmp (&a->ipv6, &b->ipv6, sizeof (a->ipv6));
822    case GRUB_NET_NETWORK_LEVEL_PROTOCOL_DHCP_RECV:
823      return 0;
824    }
825  grub_printf (_("Unsupported address type %d\n"), a->type);
826  return 1;
827}
828
829/* FIXME: implement this. */
830static char *
831hwaddr_set_env (struct grub_env_var *var __attribute__ ((unused)),
832                const char *val __attribute__ ((unused)))
833{
834  return NULL;
835}
836
837/* FIXME: implement this. */
838static char *
839addr_set_env (struct grub_env_var *var __attribute__ ((unused)),
840              const char *val __attribute__ ((unused)))
841{
842  return NULL;
843}
844
845static char *
846defserver_set_env (struct grub_env_var *var __attribute__ ((unused)),
847                   const char *val)
848{
849  grub_free (grub_net_default_server);
850  grub_net_default_server = grub_strdup (val);
851  return grub_strdup (val);
852}
853
854static const char *
855defserver_get_env (struct grub_env_var *var __attribute__ ((unused)),
856                   const char *val __attribute__ ((unused)))
857{
858  return grub_net_default_server ? : "";
859}
860
861static const char *
862defip_get_env (struct grub_env_var *var __attribute__ ((unused)),
863               const char *val __attribute__ ((unused)))
864{
865  const char *intf = grub_env_get ("net_default_interface");
866  const char *ret = NULL;
867  if (intf)
868    {
869      char *buf = grub_xasprintf ("net_%s_ip", intf);
870      if (buf)
871        ret = grub_env_get (buf);
872      grub_free (buf);
873    }
874  return ret;
875}
876
877static char *
878defip_set_env (struct grub_env_var *var __attribute__ ((unused)),
879               const char *val)
880{
881  const char *intf = grub_env_get ("net_default_interface");
882  if (intf)
883    {
884      char *buf = grub_xasprintf ("net_%s_ip", intf);
885      if (buf)
886        grub_env_set (buf, val);
887      grub_free (buf);
888    }
889  return NULL;
890}
891
892
893static const char *
894defmac_get_env (struct grub_env_var *var __attribute__ ((unused)),
895               const char *val __attribute__ ((unused)))
896{
897  const char *intf = grub_env_get ("net_default_interface");
898  const char *ret = NULL;
899  if (intf)
900    {
901      char *buf = grub_xasprintf ("net_%s_mac", intf);
902      if (buf)
903        ret = grub_env_get (buf);
904      grub_free (buf);
905    }
906  return ret;
907}
908
909static char *
910defmac_set_env (struct grub_env_var *var __attribute__ ((unused)),
911               const char *val)
912{
913  const char *intf = grub_env_get ("net_default_interface");
914  if (intf)
915    {
916      char *buf = grub_xasprintf ("net_%s_mac", intf);
917      if (buf)
918        grub_env_set (buf, val);
919      grub_free (buf);
920    }
921  return NULL;
922}
923
924
925static void
926grub_net_network_level_interface_register (struct grub_net_network_level_interface *inter)
927{
928  {
929    char buf[GRUB_NET_MAX_STR_HWADDR_LEN];
930    char *name;
931    char *ptr;
932    grub_net_hwaddr_to_str (&inter->hwaddress, buf);
933    name = grub_xasprintf ("net_%s_mac", inter->name);
934    if (!name)
935      return;
936    for (ptr = name; *ptr; ptr++)
937      if (*ptr == ':')
938        *ptr = '_';   
939    grub_env_set (name, buf);
940    grub_register_variable_hook (name, 0, hwaddr_set_env);
941    grub_env_export (name);
942    grub_free (name);
943  }
944
945  {
946    char buf[GRUB_NET_MAX_STR_ADDR_LEN];
947    char *name;
948    char *ptr;
949    grub_net_addr_to_str (&inter->address, buf);
950    name = grub_xasprintf ("net_%s_ip", inter->name);
951    if (!name)
952      return;
953    for (ptr = name; *ptr; ptr++)
954      if (*ptr == ':')
955        *ptr = '_';   
956    grub_env_set (name, buf);
957    grub_register_variable_hook (name, 0, addr_set_env);
958    grub_env_export (name);
959    grub_free (name);
960  }
961
962  inter->card->num_ifaces++;
963  inter->prev = &grub_net_network_level_interfaces;
964  inter->next = grub_net_network_level_interfaces;
965  if (inter->next)
966    inter->next->prev = &inter->next;
967  grub_net_network_level_interfaces = inter;
968}
969
970
971grub_err_t
972grub_net_add_ipv4_local (struct grub_net_network_level_interface *inter,
973                         int mask)
974{
975  grub_uint32_t ip_cpu;
976  struct grub_net_route *route;
977
978  if (inter->address.type != GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4)
979    return 0;
980
981  ip_cpu = grub_be_to_cpu32 (inter->address.ipv4);
982
983  if (mask == -1)
984    {
985      if (!(ip_cpu & 0x80000000))
986        mask = 8;
987      else if (!(ip_cpu & 0x40000000))
988        mask = 16;
989      else if (!(ip_cpu & 0x20000000))
990        mask = 24;
991    }
992  if (mask == -1)
993    return 0;
994
995  route = grub_zalloc (sizeof (*route));
996  if (!route)
997    return grub_errno;
998
999  route->name = grub_xasprintf ("%s:local", inter->name);
1000  if (!route->name)
1001    {
1002      grub_free (route);
1003      return grub_errno;
1004    }
1005
1006  route->target.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
1007  route->target.ipv4.base = grub_cpu_to_be32 (ip_cpu & (0xffffffff << (32 - mask)));
1008  route->target.ipv4.masksize = mask;
1009  route->is_gateway = 0;
1010  route->interface = inter;
1011
1012  grub_net_route_register (route);
1013
1014  return 0;
1015}
1016
1017/* FIXME: support MAC specifying.  */
1018static grub_err_t
1019grub_cmd_addaddr (struct grub_command *cmd __attribute__ ((unused)),
1020                  int argc, char **args)
1021{
1022  struct grub_net_card *card;
1023  grub_net_network_level_address_t addr;
1024  grub_err_t err;
1025  grub_net_interface_flags_t flags = 0;
1026  struct grub_net_network_level_interface *inf;
1027
1028  if (argc != 3)
1029    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("three arguments expected"));
1030 
1031  FOR_NET_CARDS (card)
1032    if (grub_strcmp (card->name, args[1]) == 0)
1033      break;
1034  if (card == NULL)
1035    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("card not found")); 
1036
1037  err = grub_net_resolve_address (args[2], &addr);
1038  if (err)
1039    return err;
1040
1041  if (card->flags & GRUB_NET_CARD_NO_MANUAL_INTERFACES)
1042    return grub_error (GRUB_ERR_IO,
1043                       "this card doesn't support address addition");
1044
1045  if (card->flags & GRUB_NET_CARD_HWADDRESS_IMMUTABLE)
1046    flags |= GRUB_NET_INTERFACE_HWADDRESS_IMMUTABLE;
1047
1048  inf = grub_net_add_addr (args[0], card, &addr, &card->default_address,
1049                           flags);
1050  if (inf)
1051    grub_net_add_ipv4_local (inf, -1);
1052
1053  return grub_errno;
1054}
1055
1056static grub_err_t
1057grub_cmd_delroute (struct grub_command *cmd __attribute__ ((unused)),
1058                   int argc, char **args)
1059{
1060  struct grub_net_route *route;
1061  struct grub_net_route **prev;
1062
1063  if (argc != 1)
1064    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
1065 
1066  for (prev = &grub_net_routes, route = *prev; route; prev = &((*prev)->next),
1067         route = *prev)
1068    if (grub_strcmp (route->name, args[0]) == 0)
1069      {
1070        *prev = route->next;
1071        grub_free (route->name);
1072        grub_free (route);
1073        if (!*prev)
1074          break;
1075      }
1076
1077  return GRUB_ERR_NONE;
1078}
1079
1080grub_err_t
1081grub_net_add_route (const char *name,
1082                    grub_net_network_level_netaddress_t target,
1083                    struct grub_net_network_level_interface *inter)
1084{
1085  struct grub_net_route *route;
1086
1087  route = grub_zalloc (sizeof (*route));
1088  if (!route)
1089    return grub_errno;
1090
1091  route->name = grub_strdup (name);
1092  if (!route->name)
1093    {
1094      grub_free (route);
1095      return grub_errno;
1096    }
1097
1098  route->target = target;
1099  route->is_gateway = 0;
1100  route->interface = inter;
1101
1102  grub_net_route_register (route);
1103
1104  return GRUB_ERR_NONE;
1105}
1106
1107grub_err_t
1108grub_net_add_route_gw (const char *name,
1109                       grub_net_network_level_netaddress_t target,
1110                       grub_net_network_level_address_t gw)
1111{
1112  struct grub_net_route *route;
1113
1114  route = grub_zalloc (sizeof (*route));
1115  if (!route)
1116    return grub_errno;
1117
1118  route->name = grub_strdup (name);
1119  if (!route->name)
1120    {
1121      grub_free (route);
1122      return grub_errno;
1123    }
1124
1125  route->target = target;
1126  route->is_gateway = 1;
1127  route->gw = gw;
1128
1129  grub_net_route_register (route);
1130
1131  return GRUB_ERR_NONE;
1132}
1133
1134static grub_err_t
1135grub_cmd_addroute (struct grub_command *cmd __attribute__ ((unused)),
1136                  int argc, char **args)
1137{
1138  grub_net_network_level_netaddress_t target;
1139  if (argc < 3)
1140    return grub_error (GRUB_ERR_BAD_ARGUMENT,
1141                       N_("three arguments expected"));
1142
1143  grub_net_resolve_net_address  (args[1], &target);
1144 
1145  if (grub_strcmp (args[2], "gw") == 0 && argc >= 4)
1146    {
1147      grub_err_t err;
1148      grub_net_network_level_address_t gw;
1149
1150      err = grub_net_resolve_address (args[3], &gw);
1151      if (err)
1152        return err;
1153      return grub_net_add_route_gw (args[0], target, gw);
1154    }
1155  else
1156    {
1157      struct grub_net_network_level_interface *inter;
1158
1159      FOR_NET_NETWORK_LEVEL_INTERFACES (inter)
1160        if (grub_strcmp (inter->name, args[2]) == 0)
1161          break;
1162
1163      if (!inter)
1164        return grub_error (GRUB_ERR_BAD_ARGUMENT,
1165                           N_("unrecognised network interface `%s'"), args[2]);
1166      return grub_net_add_route (args[0], target, inter);
1167    }
1168}
1169
1170static void
1171print_net_address (const grub_net_network_level_netaddress_t *target)
1172{
1173  switch (target->type)
1174    {
1175    case GRUB_NET_NETWORK_LEVEL_PROTOCOL_DHCP_RECV:
1176      /* TRANSLATORS: it refers to the network address.  */
1177      grub_printf ("%s\n", _("temporary"));
1178      return;
1179    case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4:
1180      {
1181        grub_uint32_t n = grub_be_to_cpu32 (target->ipv4.base);
1182        grub_printf ("%d.%d.%d.%d/%d ", ((n >> 24) & 0xff),
1183                     ((n >> 16) & 0xff),
1184                     ((n >> 8) & 0xff),
1185                     ((n >> 0) & 0xff),
1186                     target->ipv4.masksize);
1187      }
1188      return;
1189    case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6:
1190      {
1191        char buf[GRUB_NET_MAX_STR_ADDR_LEN];
1192        struct grub_net_network_level_address base;
1193        base.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
1194        grub_memcpy (&base.ipv6, &target->ipv6, 16);
1195        grub_net_addr_to_str (&base, buf);
1196        grub_printf ("%s/%d ", buf, target->ipv6.masksize);
1197      }
1198      return;
1199    }
1200  grub_printf (_("Unknown address type %d\n"), target->type);
1201}
1202
1203static void
1204print_address (const grub_net_network_level_address_t *target)
1205{
1206  char buf[GRUB_NET_MAX_STR_ADDR_LEN];
1207  grub_net_addr_to_str (target, buf);
1208  grub_xputs (buf);
1209}
1210
1211static grub_err_t
1212grub_cmd_listroutes (struct grub_command *cmd __attribute__ ((unused)),
1213                     int argc __attribute__ ((unused)),
1214                     char **args __attribute__ ((unused)))
1215{
1216  struct grub_net_route *route;
1217  FOR_NET_ROUTES(route)
1218  {
1219    grub_printf ("%s ", route->name);
1220    print_net_address (&route->target);
1221    if (route->is_gateway)
1222      {
1223        grub_printf ("gw ");
1224        print_address (&route->gw);     
1225      }
1226    else
1227      grub_printf ("%s", route->interface->name);     
1228    grub_printf ("\n");
1229  }
1230  return GRUB_ERR_NONE;
1231}
1232
1233static grub_err_t
1234grub_cmd_listcards (struct grub_command *cmd __attribute__ ((unused)),
1235                    int argc __attribute__ ((unused)),
1236                    char **args __attribute__ ((unused)))
1237{
1238  struct grub_net_card *card;
1239  FOR_NET_CARDS(card)
1240  {
1241    char buf[GRUB_NET_MAX_STR_HWADDR_LEN];
1242    grub_net_hwaddr_to_str (&card->default_address, buf);
1243    grub_printf ("%s %s\n", card->name, buf);
1244  }
1245  return GRUB_ERR_NONE;
1246}
1247
1248static grub_err_t
1249grub_cmd_listaddrs (struct grub_command *cmd __attribute__ ((unused)),
1250                    int argc __attribute__ ((unused)),
1251                    char **args __attribute__ ((unused)))
1252{
1253  struct grub_net_network_level_interface *inf;
1254  FOR_NET_NETWORK_LEVEL_INTERFACES (inf)
1255  {
1256    char bufh[GRUB_NET_MAX_STR_HWADDR_LEN];
1257    char bufn[GRUB_NET_MAX_STR_ADDR_LEN];
1258    grub_net_hwaddr_to_str (&inf->hwaddress, bufh);
1259    grub_net_addr_to_str (&inf->address, bufn);
1260    grub_printf ("%s %s %s\n", inf->name, bufh, bufn);
1261  }
1262  return GRUB_ERR_NONE;
1263}
1264
1265grub_net_app_level_t grub_net_app_level_list;
1266struct grub_net_socket *grub_net_sockets;
1267
1268static grub_net_t
1269grub_net_open_real (const char *name)
1270{
1271  grub_net_app_level_t proto;
1272  const char *protname, *server;
1273  grub_size_t protnamelen;
1274  int try;
1275
1276  if (grub_strncmp (name, "pxe:", sizeof ("pxe:") - 1) == 0)
1277    {
1278      protname = "tftp";
1279      protnamelen = sizeof ("tftp") - 1;
1280      server = name + sizeof ("pxe:") - 1;
1281    }
1282  else if (grub_strcmp (name, "pxe") == 0)
1283    {
1284      protname = "tftp";
1285      protnamelen = sizeof ("tftp") - 1;
1286      server = grub_net_default_server;
1287    }
1288  else
1289    {
1290      const char *comma;
1291      comma = grub_strchr (name, ',');
1292      if (comma)
1293        {
1294          protnamelen = comma - name;
1295          server = comma + 1;
1296          protname = name;
1297        }
1298      else
1299        {
1300          protnamelen = grub_strlen (name);
1301          server = grub_net_default_server;
1302          protname = name;
1303        }
1304    }
1305  if (!server)
1306    {
1307      grub_error (GRUB_ERR_NET_BAD_ADDRESS,
1308                  N_("no server is specified"));
1309      return NULL;
1310    } 
1311
1312  for (try = 0; try < 2; try++)
1313    {
1314      FOR_NET_APP_LEVEL (proto)
1315      {
1316        if (grub_memcmp (proto->name, protname, protnamelen) == 0
1317            && proto->name[protnamelen] == 0)
1318          {
1319            grub_net_t ret = grub_zalloc (sizeof (*ret));
1320            if (!ret)
1321              return NULL;
1322            ret->protocol = proto;
1323            if (server)
1324              {
1325                ret->server = grub_strdup (server);
1326                if (!ret->server)
1327                  {
1328                    grub_free (ret);
1329                    return NULL;
1330                  }
1331              }
1332            else
1333              ret->server = NULL;
1334            ret->fs = &grub_net_fs;
1335            ret->offset = 0;
1336            ret->eof = 0;
1337            return ret;
1338          }
1339      }
1340      if (try == 0)
1341        {
1342          if (sizeof ("http") - 1 == protnamelen
1343              && grub_memcmp ("http", protname, protnamelen) == 0)
1344            {
1345              grub_dl_load ("http");
1346              grub_errno = GRUB_ERR_NONE;
1347              continue;
1348            }
1349          if (sizeof ("tftp") - 1 == protnamelen
1350              && grub_memcmp ("tftp", protname, protnamelen) == 0)
1351            {
1352              grub_dl_load ("tftp");
1353              grub_errno = GRUB_ERR_NONE;
1354              continue;
1355            }
1356        }
1357      break;
1358    }
1359
1360  /* Restore original error.  */
1361  grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("disk `%s' not found"),
1362              name);
1363
1364  return NULL;
1365}
1366
1367static grub_err_t
1368grub_net_fs_dir (grub_device_t device, const char *path __attribute__ ((unused)),
1369                 grub_fs_dir_hook_t hook __attribute__ ((unused)),
1370                 void *hook_data __attribute__ ((unused)))
1371{
1372  if (!device->net)
1373    return grub_error (GRUB_ERR_BUG, "invalid net device");
1374  return GRUB_ERR_NONE;
1375}
1376
1377static grub_err_t
1378grub_net_fs_open (struct grub_file *file_out, const char *name)
1379{
1380  grub_err_t err;
1381  struct grub_file *file, *bufio;
1382
1383  file = grub_malloc (sizeof (*file));
1384  if (!file)
1385    return grub_errno;
1386
1387  grub_memcpy (file, file_out, sizeof (struct grub_file));
1388  file->device->net->packs.first = NULL;
1389  file->device->net->packs.last = NULL;
1390  file->device->net->name = grub_strdup (name);
1391  if (!file->device->net->name)
1392    return grub_errno;
1393
1394  err = file->device->net->protocol->open (file, name);
1395  if (err)
1396    {
1397      while (file->device->net->packs.first)
1398        {
1399          grub_netbuff_free (file->device->net->packs.first->nb);
1400          grub_net_remove_packet (file->device->net->packs.first);
1401        }
1402      grub_free (file->device->net->name);
1403      grub_free (file);
1404      return err;
1405    }
1406  bufio = grub_bufio_open (file, 32768);
1407  if (! bufio)
1408    {
1409      while (file->device->net->packs.first)
1410        {
1411          grub_netbuff_free (file->device->net->packs.first->nb);
1412          grub_net_remove_packet (file->device->net->packs.first);
1413        }
1414      file->device->net->protocol->close (file);
1415      grub_free (file->device->net->name);
1416      grub_free (file);
1417      return grub_errno;
1418    }
1419
1420  grub_memcpy (file_out, bufio, sizeof (struct grub_file));
1421  grub_free (bufio);
1422  return GRUB_ERR_NONE;
1423}
1424
1425static grub_err_t
1426grub_net_fs_close (grub_file_t file)
1427{
1428  while (file->device->net->packs.first)
1429    {
1430      grub_netbuff_free (file->device->net->packs.first->nb);
1431      grub_net_remove_packet (file->device->net->packs.first);
1432    }
1433  file->device->net->protocol->close (file);
1434  grub_free (file->device->net->name);
1435  return GRUB_ERR_NONE;
1436}
1437
1438static void
1439receive_packets (struct grub_net_card *card, int *stop_condition)
1440{
1441  int received = 0;
1442  if (card->num_ifaces == 0)
1443    return;
1444  if (!card->opened)
1445    {
1446      grub_err_t err = GRUB_ERR_NONE;
1447      if (card->driver->open)
1448        err = card->driver->open (card);
1449      if (err)
1450        {
1451          grub_errno = GRUB_ERR_NONE;
1452          return;
1453        }
1454      card->opened = 1;
1455    }
1456  while (received < 100)
1457    {
1458      /* Maybe should be better have a fixed number of packets for each card
1459         and just mark them as used and not used.  */ 
1460      struct grub_net_buff *nb;
1461
1462      if (received > 10 && stop_condition && *stop_condition)
1463        break;
1464
1465      nb = card->driver->recv (card);
1466      if (!nb)
1467        {
1468          card->last_poll = grub_get_time_ms ();
1469          break;
1470        }
1471      received++;
1472      grub_net_recv_ethernet_packet (nb, card);
1473      if (grub_errno)
1474        {
1475          grub_dprintf ("net", "error receiving: %d: %s\n", grub_errno,
1476                        grub_errmsg);
1477          grub_errno = GRUB_ERR_NONE;
1478        }
1479    }
1480  grub_print_error ();
1481}
1482
1483void
1484grub_net_poll_cards (unsigned time, int *stop_condition)
1485{
1486  struct grub_net_card *card;
1487  grub_uint64_t start_time;
1488  start_time = grub_get_time_ms ();
1489  while ((grub_get_time_ms () - start_time) < time
1490         && (!stop_condition || !*stop_condition))
1491    FOR_NET_CARDS (card)
1492      receive_packets (card, stop_condition);
1493  grub_net_tcp_retransmit ();
1494}
1495
1496static void
1497grub_net_poll_cards_idle_real (void)
1498{
1499  struct grub_net_card *card;
1500  FOR_NET_CARDS (card)
1501  {
1502    grub_uint64_t ctime = grub_get_time_ms ();
1503
1504    if (ctime < card->last_poll
1505        || ctime >= card->last_poll + card->idle_poll_delay_ms)
1506      receive_packets (card, 0);
1507  }
1508  grub_net_tcp_retransmit ();
1509}
1510
1511/*  Read from the packets list*/
1512static grub_ssize_t
1513grub_net_fs_read_real (grub_file_t file, char *buf, grub_size_t len)
1514{
1515  grub_net_t net = file->device->net;
1516  struct grub_net_buff *nb;
1517  char *ptr = buf;
1518  grub_size_t amount, total = 0;
1519  int try = 0;
1520
1521  while (try <= GRUB_NET_TRIES)
1522    {
1523      while (net->packs.first)
1524        {
1525          try = 0;
1526          nb = net->packs.first->nb;
1527          amount = nb->tail - nb->data;
1528          if (amount > len)
1529            amount = len;
1530          len -= amount;
1531          total += amount;
1532          file->device->net->offset += amount;
1533          if (grub_file_progress_hook)
1534            grub_file_progress_hook (0, 0, amount, file);
1535          if (buf)
1536            {
1537              grub_memcpy (ptr, nb->data, amount);
1538              ptr += amount;
1539            }
1540          if (amount == (grub_size_t) (nb->tail - nb->data))
1541            {
1542              grub_netbuff_free (nb);
1543              grub_net_remove_packet (net->packs.first);
1544            }
1545          else
1546            nb->data += amount;
1547
1548          if (!len)
1549            {
1550              if (net->protocol->packets_pulled)
1551                net->protocol->packets_pulled (file);
1552              return total;
1553            }
1554        }
1555      if (net->protocol->packets_pulled)
1556        net->protocol->packets_pulled (file);
1557
1558      if (!net->eof)
1559        {
1560          try++;
1561          grub_net_poll_cards (GRUB_NET_INTERVAL +
1562                               (try * GRUB_NET_INTERVAL_ADDITION), &net->stall);
1563        }
1564      else
1565        return total;
1566    }
1567  grub_error (GRUB_ERR_TIMEOUT, N_("timeout reading `%s'"), net->name);
1568  return -1;
1569}
1570
1571static grub_off_t
1572have_ahead (struct grub_file *file)
1573{
1574  grub_net_t net = file->device->net;
1575  grub_off_t ret = net->offset;
1576  struct grub_net_packet *pack;
1577  for (pack = net->packs.first; pack; pack = pack->next)
1578    ret += pack->nb->tail - pack->nb->data;
1579  return ret;
1580}
1581
1582static grub_err_t
1583grub_net_seek_real (struct grub_file *file, grub_off_t offset)
1584{
1585  if (offset == file->device->net->offset)
1586    return GRUB_ERR_NONE;
1587
1588  if (offset > file->device->net->offset)
1589    {
1590      if (!file->device->net->protocol->seek || have_ahead (file) >= offset)
1591        {
1592          grub_net_fs_read_real (file, NULL,
1593                                 offset - file->device->net->offset);
1594          return grub_errno;
1595        }
1596      return file->device->net->protocol->seek (file, offset);
1597    }
1598
1599  {
1600    grub_err_t err;
1601    if (file->device->net->protocol->seek)
1602      return file->device->net->protocol->seek (file, offset);
1603    while (file->device->net->packs.first)
1604      {
1605        grub_netbuff_free (file->device->net->packs.first->nb);
1606        grub_net_remove_packet (file->device->net->packs.first);
1607      }
1608    file->device->net->protocol->close (file);
1609
1610    file->device->net->packs.first = NULL;
1611    file->device->net->packs.last = NULL;
1612    file->device->net->offset = 0;
1613    file->device->net->eof = 0;
1614    err = file->device->net->protocol->open (file, file->device->net->name);
1615    if (err)
1616      return err;
1617    grub_net_fs_read_real (file, NULL, offset);
1618    return grub_errno;
1619  }
1620}
1621
1622static grub_ssize_t
1623grub_net_fs_read (grub_file_t file, char *buf, grub_size_t len)
1624{
1625  if (file->offset != file->device->net->offset)
1626    {
1627      grub_err_t err;
1628      err = grub_net_seek_real (file, file->offset);
1629      if (err)
1630        return err;
1631    }
1632  return grub_net_fs_read_real (file, buf, len);
1633}
1634
1635static struct grub_fs grub_net_fs =
1636  {
1637    .name = "netfs",
1638    .dir = grub_net_fs_dir,
1639    .open = grub_net_fs_open,
1640    .read = grub_net_fs_read,
1641    .close = grub_net_fs_close,
1642    .label = NULL,
1643    .uuid = NULL,
1644    .mtime = NULL,
1645  };
1646
1647static grub_err_t
1648grub_net_fini_hw (int noreturn __attribute__ ((unused)))
1649{
1650  struct grub_net_card *card;
1651  FOR_NET_CARDS (card) 
1652    if (card->opened)
1653      {
1654        if (card->driver->close)
1655          card->driver->close (card);
1656        card->opened = 0;
1657      }
1658  return GRUB_ERR_NONE;
1659}
1660
1661static grub_err_t
1662grub_net_restore_hw (void)
1663{
1664  return GRUB_ERR_NONE;
1665}
1666
1667static struct grub_preboot *fini_hnd;
1668
1669static grub_command_t cmd_addaddr, cmd_deladdr, cmd_addroute, cmd_delroute;
1670static grub_command_t cmd_lsroutes, cmd_lscards;
1671static grub_command_t cmd_lsaddr, cmd_slaac;
1672
1673GRUB_MOD_INIT(net)
1674{
1675  grub_register_variable_hook ("net_default_server", defserver_get_env,
1676                               defserver_set_env);
1677  grub_env_export ("net_default_server");
1678  grub_register_variable_hook ("pxe_default_server", defserver_get_env,
1679                               defserver_set_env);
1680  grub_env_export ("pxe_default_server");
1681  grub_register_variable_hook ("net_default_ip", defip_get_env,
1682                               defip_set_env);
1683  grub_env_export ("net_default_ip");
1684  grub_register_variable_hook ("net_default_mac", defmac_get_env,
1685                               defmac_set_env);
1686  grub_env_export ("net_default_mac");
1687
1688  cmd_addaddr = grub_register_command ("net_add_addr", grub_cmd_addaddr,
1689                                        /* TRANSLATORS: HWADDRESS stands for
1690                                           "hardware address".  */
1691                                       N_("SHORTNAME CARD ADDRESS [HWADDRESS]"),
1692                                       N_("Add a network address."));
1693  cmd_slaac = grub_register_command ("net_ipv6_autoconf",
1694                                     grub_cmd_ipv6_autoconf,
1695                                     N_("[CARD [HWADDRESS]]"),
1696                                     N_("Perform an IPV6 autoconfiguration"));
1697
1698  cmd_deladdr = grub_register_command ("net_del_addr", grub_cmd_deladdr,
1699                                       N_("SHORTNAME"),
1700                                       N_("Delete a network address."));
1701  cmd_addroute = grub_register_command ("net_add_route", grub_cmd_addroute,
1702                                        /* TRANSLATORS: "gw" is a keyword.  */
1703                                        N_("SHORTNAME NET [INTERFACE| gw GATEWAY]"),
1704                                        N_("Add a network route."));
1705  cmd_delroute = grub_register_command ("net_del_route", grub_cmd_delroute,
1706                                        N_("SHORTNAME"),
1707                                        N_("Delete a network route."));
1708  cmd_lsroutes = grub_register_command ("net_ls_routes", grub_cmd_listroutes,
1709                                        "", N_("list network routes"));
1710  cmd_lscards = grub_register_command ("net_ls_cards", grub_cmd_listcards,
1711                                       "", N_("list network cards"));
1712  cmd_lsaddr = grub_register_command ("net_ls_addr", grub_cmd_listaddrs,
1713                                       "", N_("list network addresses"));
1714  grub_bootp_init ();
1715  grub_dns_init ();
1716
1717  grub_net_open = grub_net_open_real;
1718  fini_hnd = grub_loader_register_preboot_hook (grub_net_fini_hw,
1719                                                grub_net_restore_hw,
1720                                                GRUB_LOADER_PREBOOT_HOOK_PRIO_DISK);
1721  grub_net_poll_cards_idle = grub_net_poll_cards_idle_real;
1722}
1723
1724GRUB_MOD_FINI(net)
1725{
1726  grub_register_variable_hook ("net_default_server", 0, 0);
1727  grub_register_variable_hook ("pxe_default_server", 0, 0);
1728
1729  grub_bootp_fini ();
1730  grub_dns_fini ();
1731  grub_unregister_command (cmd_addaddr);
1732  grub_unregister_command (cmd_deladdr);
1733  grub_unregister_command (cmd_addroute);
1734  grub_unregister_command (cmd_delroute);
1735  grub_unregister_command (cmd_lsroutes);
1736  grub_unregister_command (cmd_lscards);
1737  grub_unregister_command (cmd_lsaddr);
1738  grub_unregister_command (cmd_slaac);
1739  grub_fs_unregister (&grub_net_fs);
1740  grub_net_open = NULL;
1741  grub_net_fini_hw (0);
1742  grub_loader_unregister_preboot_hook (fini_hnd);
1743  grub_net_poll_cards_idle = grub_net_poll_cards_idle_real;
1744}
Note: See TracBrowser for help on using the repository browser.