]> git.proxmox.com Git - grub2.git/blob - grub-core/net/net.c
change stop condition to avoid infinite loops
[grub2.git] / grub-core / net / net.c
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
36 GRUB_MOD_LICENSE ("GPLv3+");
37
38 char *grub_net_default_server;
39
40 struct 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
55 struct grub_net_route *grub_net_routes = NULL;
56 struct grub_net_network_level_interface *grub_net_network_level_interfaces = NULL;
57 struct grub_net_card *grub_net_cards = NULL;
58 struct grub_net_network_level_protocol *grub_net_network_level_protocols = NULL;
59 static struct grub_fs grub_net_fs;
60
61 struct 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
69 static struct grub_net_link_layer_entry *
70 link_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
86 void
87 grub_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
115 int
116 grub_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
130 grub_err_t
131 grub_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
197 void
198 grub_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
213 static struct grub_net_slaac_mac_list *
214 grub_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
246 static void
247 grub_net_network_level_interface_register (struct grub_net_network_level_interface *inter);
248
249 static struct grub_net_network_level_interface *
250 grub_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
275 struct grub_net_network_level_interface *
276 grub_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
293 struct grub_net_network_level_interface *
294 grub_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. */
332 static grub_err_t
333 grub_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
411 static inline void
412 grub_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
420 static int
421 parse_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
455 static int
456 parse_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
504 static int
505 match_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
544 grub_err_t
545 grub_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
575 grub_err_t
576 grub_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
617 static int
618 route_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
650 grub_err_t
651 grub_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
699 static grub_err_t
700 grub_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
725 void
726 grub_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
769 void
770 grub_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
791 int
792 grub_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
808 int
809 grub_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. */
830 static char *
831 hwaddr_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. */
838 static char *
839 addr_set_env (struct grub_env_var *var __attribute__ ((unused)),
840 const char *val __attribute__ ((unused)))
841 {
842 return NULL;
843 }
844
845 static char *
846 defserver_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
854 static const char *
855 defserver_get_env (struct grub_env_var *var __attribute__ ((unused)),
856 const char *val __attribute__ ((unused)))
857 {
858 return grub_net_default_server ? : "";
859 }
860
861 static const char *
862 defip_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
877 static char *
878 defip_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
893 static const char *
894 defmac_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
909 static char *
910 defmac_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
925 static void
926 grub_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
971 grub_err_t
972 grub_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. */
1018 static grub_err_t
1019 grub_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
1056 static grub_err_t
1057 grub_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
1080 grub_err_t
1081 grub_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
1107 grub_err_t
1108 grub_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
1134 static grub_err_t
1135 grub_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
1170 static void
1171 print_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
1203 static void
1204 print_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
1211 static grub_err_t
1212 grub_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
1233 static grub_err_t
1234 grub_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
1248 static grub_err_t
1249 grub_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
1265 grub_net_app_level_t grub_net_app_level_list;
1266 struct grub_net_socket *grub_net_sockets;
1267
1268 static grub_net_t
1269 grub_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
1367 static grub_err_t
1368 grub_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
1377 static grub_err_t
1378 grub_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
1425 static grub_err_t
1426 grub_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
1438 static void
1439 receive_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
1483 void
1484 grub_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
1496 static void
1497 grub_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*/
1512 static grub_ssize_t
1513 grub_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, &net->stall);
1562 }
1563 else
1564 return total;
1565 }
1566 grub_error (GRUB_ERR_TIMEOUT, N_("timeout reading `%s'"), net->name);
1567 return -1;
1568 }
1569
1570 static grub_off_t
1571 have_ahead (struct grub_file *file)
1572 {
1573 grub_net_t net = file->device->net;
1574 grub_off_t ret = net->offset;
1575 struct grub_net_packet *pack;
1576 for (pack = net->packs.first; pack; pack = pack->next)
1577 ret += pack->nb->tail - pack->nb->data;
1578 return ret;
1579 }
1580
1581 static grub_err_t
1582 grub_net_seek_real (struct grub_file *file, grub_off_t offset)
1583 {
1584 if (offset == file->device->net->offset)
1585 return GRUB_ERR_NONE;
1586
1587 if (offset > file->device->net->offset)
1588 {
1589 if (!file->device->net->protocol->seek || have_ahead (file) >= offset)
1590 {
1591 grub_net_fs_read_real (file, NULL,
1592 offset - file->device->net->offset);
1593 return grub_errno;
1594 }
1595 return file->device->net->protocol->seek (file, offset);
1596 }
1597
1598 {
1599 grub_err_t err;
1600 if (file->device->net->protocol->seek)
1601 return file->device->net->protocol->seek (file, offset);
1602 while (file->device->net->packs.first)
1603 {
1604 grub_netbuff_free (file->device->net->packs.first->nb);
1605 grub_net_remove_packet (file->device->net->packs.first);
1606 }
1607 file->device->net->protocol->close (file);
1608
1609 file->device->net->packs.first = NULL;
1610 file->device->net->packs.last = NULL;
1611 file->device->net->offset = 0;
1612 file->device->net->eof = 0;
1613 err = file->device->net->protocol->open (file, file->device->net->name);
1614 if (err)
1615 return err;
1616 grub_net_fs_read_real (file, NULL, offset);
1617 return grub_errno;
1618 }
1619 }
1620
1621 static grub_ssize_t
1622 grub_net_fs_read (grub_file_t file, char *buf, grub_size_t len)
1623 {
1624 if (file->offset != file->device->net->offset)
1625 {
1626 grub_err_t err;
1627 err = grub_net_seek_real (file, file->offset);
1628 if (err)
1629 return err;
1630 }
1631 return grub_net_fs_read_real (file, buf, len);
1632 }
1633
1634 static struct grub_fs grub_net_fs =
1635 {
1636 .name = "netfs",
1637 .dir = grub_net_fs_dir,
1638 .open = grub_net_fs_open,
1639 .read = grub_net_fs_read,
1640 .close = grub_net_fs_close,
1641 .label = NULL,
1642 .uuid = NULL,
1643 .mtime = NULL,
1644 };
1645
1646 static grub_err_t
1647 grub_net_fini_hw (int noreturn __attribute__ ((unused)))
1648 {
1649 struct grub_net_card *card;
1650 FOR_NET_CARDS (card)
1651 if (card->opened)
1652 {
1653 if (card->driver->close)
1654 card->driver->close (card);
1655 card->opened = 0;
1656 }
1657 return GRUB_ERR_NONE;
1658 }
1659
1660 static grub_err_t
1661 grub_net_restore_hw (void)
1662 {
1663 return GRUB_ERR_NONE;
1664 }
1665
1666 static struct grub_preboot *fini_hnd;
1667
1668 static grub_command_t cmd_addaddr, cmd_deladdr, cmd_addroute, cmd_delroute;
1669 static grub_command_t cmd_lsroutes, cmd_lscards;
1670 static grub_command_t cmd_lsaddr, cmd_slaac;
1671
1672 GRUB_MOD_INIT(net)
1673 {
1674 grub_register_variable_hook ("net_default_server", defserver_get_env,
1675 defserver_set_env);
1676 grub_env_export ("net_default_server");
1677 grub_register_variable_hook ("pxe_default_server", defserver_get_env,
1678 defserver_set_env);
1679 grub_env_export ("pxe_default_server");
1680 grub_register_variable_hook ("net_default_ip", defip_get_env,
1681 defip_set_env);
1682 grub_env_export ("net_default_ip");
1683 grub_register_variable_hook ("net_default_mac", defmac_get_env,
1684 defmac_set_env);
1685 grub_env_export ("net_default_mac");
1686
1687 cmd_addaddr = grub_register_command ("net_add_addr", grub_cmd_addaddr,
1688 /* TRANSLATORS: HWADDRESS stands for
1689 "hardware address". */
1690 N_("SHORTNAME CARD ADDRESS [HWADDRESS]"),
1691 N_("Add a network address."));
1692 cmd_slaac = grub_register_command ("net_ipv6_autoconf",
1693 grub_cmd_ipv6_autoconf,
1694 N_("[CARD [HWADDRESS]]"),
1695 N_("Perform an IPV6 autoconfiguration"));
1696
1697 cmd_deladdr = grub_register_command ("net_del_addr", grub_cmd_deladdr,
1698 N_("SHORTNAME"),
1699 N_("Delete a network address."));
1700 cmd_addroute = grub_register_command ("net_add_route", grub_cmd_addroute,
1701 /* TRANSLATORS: "gw" is a keyword. */
1702 N_("SHORTNAME NET [INTERFACE| gw GATEWAY]"),
1703 N_("Add a network route."));
1704 cmd_delroute = grub_register_command ("net_del_route", grub_cmd_delroute,
1705 N_("SHORTNAME"),
1706 N_("Delete a network route."));
1707 cmd_lsroutes = grub_register_command ("net_ls_routes", grub_cmd_listroutes,
1708 "", N_("list network routes"));
1709 cmd_lscards = grub_register_command ("net_ls_cards", grub_cmd_listcards,
1710 "", N_("list network cards"));
1711 cmd_lsaddr = grub_register_command ("net_ls_addr", grub_cmd_listaddrs,
1712 "", N_("list network addresses"));
1713 grub_bootp_init ();
1714 grub_dns_init ();
1715
1716 grub_net_open = grub_net_open_real;
1717 fini_hnd = grub_loader_register_preboot_hook (grub_net_fini_hw,
1718 grub_net_restore_hw,
1719 GRUB_LOADER_PREBOOT_HOOK_PRIO_DISK);
1720 grub_net_poll_cards_idle = grub_net_poll_cards_idle_real;
1721 }
1722
1723 GRUB_MOD_FINI(net)
1724 {
1725 grub_register_variable_hook ("net_default_server", 0, 0);
1726 grub_register_variable_hook ("pxe_default_server", 0, 0);
1727
1728 grub_bootp_fini ();
1729 grub_dns_fini ();
1730 grub_unregister_command (cmd_addaddr);
1731 grub_unregister_command (cmd_deladdr);
1732 grub_unregister_command (cmd_addroute);
1733 grub_unregister_command (cmd_delroute);
1734 grub_unregister_command (cmd_lsroutes);
1735 grub_unregister_command (cmd_lscards);
1736 grub_unregister_command (cmd_lsaddr);
1737 grub_unregister_command (cmd_slaac);
1738 grub_fs_unregister (&grub_net_fs);
1739 grub_net_open = NULL;
1740 grub_net_fini_hw (0);
1741 grub_loader_unregister_preboot_hook (fini_hnd);
1742 grub_net_poll_cards_idle = grub_net_poll_cards_idle_real;
1743 }