bootp.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604
  1. /*
  2. * GRUB -- GRand Unified Bootloader
  3. * Copyright (C) 2010,2011 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. #include <grub/net.h>
  19. #include <grub/env.h>
  20. #include <grub/i18n.h>
  21. #include <grub/command.h>
  22. #include <grub/net/ip.h>
  23. #include <grub/net/netbuff.h>
  24. #include <grub/net/udp.h>
  25. #include <grub/datetime.h>
  26. static void
  27. parse_dhcp_vendor (const char *name, const void *vend, int limit, int *mask)
  28. {
  29. const grub_uint8_t *ptr, *ptr0;
  30. ptr = ptr0 = vend;
  31. if (ptr[0] != GRUB_NET_BOOTP_RFC1048_MAGIC_0
  32. || ptr[1] != GRUB_NET_BOOTP_RFC1048_MAGIC_1
  33. || ptr[2] != GRUB_NET_BOOTP_RFC1048_MAGIC_2
  34. || ptr[3] != GRUB_NET_BOOTP_RFC1048_MAGIC_3)
  35. return;
  36. ptr = ptr + sizeof (grub_uint32_t);
  37. while (ptr - ptr0 < limit)
  38. {
  39. grub_uint8_t tagtype;
  40. grub_uint8_t taglength;
  41. tagtype = *ptr++;
  42. /* Pad tag. */
  43. if (tagtype == GRUB_NET_BOOTP_PAD)
  44. continue;
  45. /* End tag. */
  46. if (tagtype == GRUB_NET_BOOTP_END)
  47. return;
  48. taglength = *ptr++;
  49. switch (tagtype)
  50. {
  51. case GRUB_NET_BOOTP_NETMASK:
  52. if (taglength == 4)
  53. {
  54. int i;
  55. for (i = 0; i < 32; i++)
  56. if (!(ptr[i / 8] & (1 << (7 - (i % 8)))))
  57. break;
  58. *mask = i;
  59. }
  60. break;
  61. case GRUB_NET_BOOTP_ROUTER:
  62. if (taglength == 4)
  63. {
  64. grub_net_network_level_netaddress_t target;
  65. grub_net_network_level_address_t gw;
  66. char *rname;
  67. target.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
  68. target.ipv4.base = 0;
  69. target.ipv4.masksize = 0;
  70. gw.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
  71. grub_memcpy (&gw.ipv4, ptr, sizeof (gw.ipv4));
  72. rname = grub_xasprintf ("%s:default", name);
  73. if (rname)
  74. grub_net_add_route_gw (rname, target, gw, NULL);
  75. grub_free (rname);
  76. }
  77. break;
  78. case GRUB_NET_BOOTP_DNS:
  79. {
  80. int i;
  81. for (i = 0; i < taglength / 4; i++)
  82. {
  83. struct grub_net_network_level_address s;
  84. s.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
  85. s.ipv4 = grub_get_unaligned32 (ptr);
  86. s.option = DNS_OPTION_PREFER_IPV4;
  87. grub_net_add_dns_server (&s);
  88. ptr += 4;
  89. }
  90. }
  91. continue;
  92. case GRUB_NET_BOOTP_HOSTNAME:
  93. grub_env_set_net_property (name, "hostname", (const char *) ptr,
  94. taglength);
  95. break;
  96. case GRUB_NET_BOOTP_DOMAIN:
  97. grub_env_set_net_property (name, "domain", (const char *) ptr,
  98. taglength);
  99. break;
  100. case GRUB_NET_BOOTP_ROOT_PATH:
  101. grub_env_set_net_property (name, "rootpath", (const char *) ptr,
  102. taglength);
  103. break;
  104. case GRUB_NET_BOOTP_EXTENSIONS_PATH:
  105. grub_env_set_net_property (name, "extensionspath", (const char *) ptr,
  106. taglength);
  107. break;
  108. /* If you need any other options please contact GRUB
  109. development team. */
  110. }
  111. ptr += taglength;
  112. }
  113. }
  114. #define OFFSET_OF(x, y) ((grub_size_t)((grub_uint8_t *)((y)->x) - (grub_uint8_t *)(y)))
  115. struct grub_net_network_level_interface *
  116. grub_net_configure_by_dhcp_ack (const char *name,
  117. struct grub_net_card *card,
  118. grub_net_interface_flags_t flags,
  119. const struct grub_net_bootp_packet *bp,
  120. grub_size_t size,
  121. int is_def, char **device, char **path)
  122. {
  123. grub_net_network_level_address_t addr;
  124. grub_net_link_level_address_t hwaddr;
  125. struct grub_net_network_level_interface *inter;
  126. int mask = -1;
  127. char server_ip[sizeof ("xxx.xxx.xxx.xxx")];
  128. addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
  129. addr.ipv4 = bp->your_ip;
  130. if (device)
  131. *device = 0;
  132. if (path)
  133. *path = 0;
  134. grub_memcpy (hwaddr.mac, bp->mac_addr,
  135. bp->hw_len < sizeof (hwaddr.mac) ? bp->hw_len
  136. : sizeof (hwaddr.mac));
  137. hwaddr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
  138. inter = grub_net_add_addr (name, card, &addr, &hwaddr, flags);
  139. if (!inter)
  140. return 0;
  141. #if 0
  142. /* This is likely based on misunderstanding. gateway_ip refers to
  143. address of BOOTP relay and should not be used after BOOTP transaction
  144. is complete.
  145. See RFC1542, 3.4 Interpretation of the 'giaddr' field
  146. */
  147. if (bp->gateway_ip)
  148. {
  149. grub_net_network_level_netaddress_t target;
  150. grub_net_network_level_address_t gw;
  151. char *rname;
  152. target.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
  153. target.ipv4.base = bp->server_ip;
  154. target.ipv4.masksize = 32;
  155. gw.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
  156. gw.ipv4 = bp->gateway_ip;
  157. rname = grub_xasprintf ("%s:gw", name);
  158. if (rname)
  159. grub_net_add_route_gw (rname, target, gw);
  160. grub_free (rname);
  161. target.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
  162. target.ipv4.base = bp->gateway_ip;
  163. target.ipv4.masksize = 32;
  164. grub_net_add_route (name, target, inter);
  165. }
  166. #endif
  167. if (size > OFFSET_OF (boot_file, bp))
  168. grub_env_set_net_property (name, "boot_file", bp->boot_file,
  169. sizeof (bp->boot_file));
  170. if (bp->server_ip)
  171. {
  172. grub_snprintf (server_ip, sizeof (server_ip), "%d.%d.%d.%d",
  173. ((grub_uint8_t *) &bp->server_ip)[0],
  174. ((grub_uint8_t *) &bp->server_ip)[1],
  175. ((grub_uint8_t *) &bp->server_ip)[2],
  176. ((grub_uint8_t *) &bp->server_ip)[3]);
  177. grub_env_set_net_property (name, "next_server", server_ip, sizeof (server_ip));
  178. grub_print_error ();
  179. }
  180. if (is_def)
  181. grub_net_default_server = 0;
  182. if (is_def && !grub_net_default_server && bp->server_ip)
  183. {
  184. grub_net_default_server = grub_strdup (server_ip);
  185. grub_print_error ();
  186. }
  187. if (is_def)
  188. {
  189. grub_env_set ("net_default_interface", name);
  190. grub_env_export ("net_default_interface");
  191. }
  192. if (device && !*device && bp->server_ip)
  193. {
  194. *device = grub_xasprintf ("tftp,%s", server_ip);
  195. grub_print_error ();
  196. }
  197. if (size > OFFSET_OF (server_name, bp)
  198. && bp->server_name[0])
  199. {
  200. grub_env_set_net_property (name, "dhcp_server_name", bp->server_name,
  201. sizeof (bp->server_name));
  202. if (is_def && !grub_net_default_server)
  203. {
  204. grub_net_default_server = grub_strdup (bp->server_name);
  205. grub_print_error ();
  206. }
  207. if (device && !*device)
  208. {
  209. *device = grub_xasprintf ("tftp,%s", bp->server_name);
  210. grub_print_error ();
  211. }
  212. }
  213. if (size > OFFSET_OF (boot_file, bp) && path)
  214. {
  215. *path = grub_strndup (bp->boot_file, sizeof (bp->boot_file));
  216. grub_print_error ();
  217. if (*path)
  218. {
  219. char *slash;
  220. slash = grub_strrchr (*path, '/');
  221. if (slash)
  222. *slash = 0;
  223. else
  224. **path = 0;
  225. }
  226. }
  227. if (size > OFFSET_OF (vendor, bp))
  228. parse_dhcp_vendor (name, &bp->vendor, size - OFFSET_OF (vendor, bp), &mask);
  229. grub_net_add_ipv4_local (inter, mask);
  230. inter->dhcp_ack = grub_malloc (size);
  231. if (inter->dhcp_ack)
  232. {
  233. grub_memcpy (inter->dhcp_ack, bp, size);
  234. inter->dhcp_acklen = size;
  235. }
  236. else
  237. grub_errno = GRUB_ERR_NONE;
  238. return inter;
  239. }
  240. void
  241. grub_net_process_dhcp (struct grub_net_buff *nb,
  242. struct grub_net_card *card)
  243. {
  244. char *name;
  245. struct grub_net_network_level_interface *inf;
  246. name = grub_xasprintf ("%s:dhcp", card->name);
  247. if (!name)
  248. {
  249. grub_print_error ();
  250. return;
  251. }
  252. grub_net_configure_by_dhcp_ack (name, card,
  253. 0, (const struct grub_net_bootp_packet *) nb->data,
  254. (nb->tail - nb->data), 0, 0, 0);
  255. grub_free (name);
  256. if (grub_errno)
  257. grub_print_error ();
  258. else
  259. {
  260. FOR_NET_NETWORK_LEVEL_INTERFACES(inf)
  261. if (grub_memcmp (inf->name, card->name, grub_strlen (card->name)) == 0
  262. && grub_memcmp (inf->name + grub_strlen (card->name),
  263. ":dhcp_tmp", sizeof (":dhcp_tmp") - 1) == 0)
  264. {
  265. grub_net_network_level_interface_unregister (inf);
  266. break;
  267. }
  268. }
  269. }
  270. static char
  271. hexdigit (grub_uint8_t val)
  272. {
  273. if (val < 10)
  274. return val + '0';
  275. return val + 'a' - 10;
  276. }
  277. static grub_err_t
  278. grub_cmd_dhcpopt (struct grub_command *cmd __attribute__ ((unused)),
  279. int argc, char **args)
  280. {
  281. struct grub_net_network_level_interface *inter;
  282. int num;
  283. grub_uint8_t *ptr;
  284. grub_uint8_t taglength;
  285. if (argc < 4)
  286. return grub_error (GRUB_ERR_BAD_ARGUMENT,
  287. N_("four arguments expected"));
  288. FOR_NET_NETWORK_LEVEL_INTERFACES (inter)
  289. if (grub_strcmp (inter->name, args[1]) == 0)
  290. break;
  291. if (!inter)
  292. return grub_error (GRUB_ERR_BAD_ARGUMENT,
  293. N_("unrecognised network interface `%s'"), args[1]);
  294. if (!inter->dhcp_ack)
  295. return grub_error (GRUB_ERR_IO, N_("no DHCP info found"));
  296. if (inter->dhcp_acklen <= OFFSET_OF (vendor, inter->dhcp_ack))
  297. return grub_error (GRUB_ERR_IO, N_("no DHCP options found"));
  298. num = grub_strtoul (args[2], 0, 0);
  299. if (grub_errno)
  300. return grub_errno;
  301. ptr = inter->dhcp_ack->vendor;
  302. if (ptr[0] != GRUB_NET_BOOTP_RFC1048_MAGIC_0
  303. || ptr[1] != GRUB_NET_BOOTP_RFC1048_MAGIC_1
  304. || ptr[2] != GRUB_NET_BOOTP_RFC1048_MAGIC_2
  305. || ptr[3] != GRUB_NET_BOOTP_RFC1048_MAGIC_3)
  306. return grub_error (GRUB_ERR_IO, N_("no DHCP options found"));
  307. ptr = ptr + sizeof (grub_uint32_t);
  308. while (1)
  309. {
  310. grub_uint8_t tagtype;
  311. if (ptr >= ((grub_uint8_t *) inter->dhcp_ack) + inter->dhcp_acklen)
  312. return grub_error (GRUB_ERR_IO, N_("no DHCP option %d found"), num);
  313. tagtype = *ptr++;
  314. /* Pad tag. */
  315. if (tagtype == 0)
  316. continue;
  317. /* End tag. */
  318. if (tagtype == 0xff)
  319. return grub_error (GRUB_ERR_IO, N_("no DHCP option %d found"), num);
  320. taglength = *ptr++;
  321. if (tagtype == num)
  322. break;
  323. ptr += taglength;
  324. }
  325. if (grub_strcmp (args[3], "string") == 0)
  326. {
  327. grub_err_t err = GRUB_ERR_NONE;
  328. char *val = grub_malloc (taglength + 1);
  329. if (!val)
  330. return grub_errno;
  331. grub_memcpy (val, ptr, taglength);
  332. val[taglength] = 0;
  333. if (args[0][0] == '-' && args[0][1] == 0)
  334. grub_printf ("%s\n", val);
  335. else
  336. err = grub_env_set (args[0], val);
  337. grub_free (val);
  338. return err;
  339. }
  340. if (grub_strcmp (args[3], "number") == 0)
  341. {
  342. grub_uint64_t val = 0;
  343. int i;
  344. for (i = 0; i < taglength; i++)
  345. val = (val << 8) | ptr[i];
  346. if (args[0][0] == '-' && args[0][1] == 0)
  347. grub_printf ("%llu\n", (unsigned long long) val);
  348. else
  349. {
  350. char valn[64];
  351. grub_snprintf (valn, sizeof (valn), "%lld\n", (unsigned long long) val);
  352. return grub_env_set (args[0], valn);
  353. }
  354. return GRUB_ERR_NONE;
  355. }
  356. if (grub_strcmp (args[3], "hex") == 0)
  357. {
  358. grub_err_t err = GRUB_ERR_NONE;
  359. char *val = grub_malloc (2 * taglength + 1);
  360. int i;
  361. if (!val)
  362. return grub_errno;
  363. for (i = 0; i < taglength; i++)
  364. {
  365. val[2 * i] = hexdigit (ptr[i] >> 4);
  366. val[2 * i + 1] = hexdigit (ptr[i] & 0xf);
  367. }
  368. val[2 * taglength] = 0;
  369. if (args[0][0] == '-' && args[0][1] == 0)
  370. grub_printf ("%s\n", val);
  371. else
  372. err = grub_env_set (args[0], val);
  373. grub_free (val);
  374. return err;
  375. }
  376. return grub_error (GRUB_ERR_BAD_ARGUMENT,
  377. N_("unrecognised DHCP option format specification `%s'"),
  378. args[3]);
  379. }
  380. /* FIXME: allow to specify mac address. */
  381. static grub_err_t
  382. grub_cmd_bootp (struct grub_command *cmd __attribute__ ((unused)),
  383. int argc, char **args)
  384. {
  385. struct grub_net_card *card;
  386. struct grub_net_network_level_interface *ifaces;
  387. grub_size_t ncards = 0;
  388. unsigned j = 0;
  389. int interval;
  390. grub_err_t err;
  391. FOR_NET_CARDS (card)
  392. {
  393. if (argc > 0 && grub_strcmp (card->name, args[0]) != 0)
  394. continue;
  395. ncards++;
  396. }
  397. if (ncards == 0)
  398. return grub_error (GRUB_ERR_NET_NO_CARD, N_("no network card found"));
  399. ifaces = grub_zalloc (ncards * sizeof (ifaces[0]));
  400. if (!ifaces)
  401. return grub_errno;
  402. j = 0;
  403. FOR_NET_CARDS (card)
  404. {
  405. if (argc > 0 && grub_strcmp (card->name, args[0]) != 0)
  406. continue;
  407. ifaces[j].card = card;
  408. ifaces[j].next = &ifaces[j+1];
  409. if (j)
  410. ifaces[j].prev = &ifaces[j-1].next;
  411. ifaces[j].name = grub_xasprintf ("%s:dhcp_tmp", card->name);
  412. card->num_ifaces++;
  413. if (!ifaces[j].name)
  414. {
  415. unsigned i;
  416. for (i = 0; i < j; i++)
  417. grub_free (ifaces[i].name);
  418. grub_free (ifaces);
  419. return grub_errno;
  420. }
  421. ifaces[j].address.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_DHCP_RECV;
  422. grub_memcpy (&ifaces[j].hwaddress, &card->default_address,
  423. sizeof (ifaces[j].hwaddress));
  424. j++;
  425. }
  426. ifaces[ncards - 1].next = grub_net_network_level_interfaces;
  427. if (grub_net_network_level_interfaces)
  428. grub_net_network_level_interfaces->prev = & ifaces[ncards - 1].next;
  429. grub_net_network_level_interfaces = &ifaces[0];
  430. ifaces[0].prev = &grub_net_network_level_interfaces;
  431. for (interval = 200; interval < 10000; interval *= 2)
  432. {
  433. int done = 0;
  434. for (j = 0; j < ncards; j++)
  435. {
  436. struct grub_net_bootp_packet *pack;
  437. struct grub_datetime date;
  438. grub_int32_t t = 0;
  439. struct grub_net_buff *nb;
  440. struct udphdr *udph;
  441. grub_net_network_level_address_t target;
  442. grub_net_link_level_address_t ll_target;
  443. if (!ifaces[j].prev)
  444. continue;
  445. nb = grub_netbuff_alloc (sizeof (*pack) + 64 + 128);
  446. if (!nb)
  447. {
  448. grub_netbuff_free (nb);
  449. return grub_errno;
  450. }
  451. err = grub_netbuff_reserve (nb, sizeof (*pack) + 64 + 128);
  452. if (err)
  453. {
  454. grub_netbuff_free (nb);
  455. return err;
  456. }
  457. err = grub_netbuff_push (nb, sizeof (*pack) + 64);
  458. if (err)
  459. {
  460. grub_netbuff_free (nb);
  461. return err;
  462. }
  463. pack = (void *) nb->data;
  464. done = 1;
  465. grub_memset (pack, 0, sizeof (*pack) + 64);
  466. pack->opcode = 1;
  467. pack->hw_type = 1;
  468. pack->hw_len = 6;
  469. err = grub_get_datetime (&date);
  470. if (err || !grub_datetime2unixtime (&date, &t))
  471. {
  472. grub_errno = GRUB_ERR_NONE;
  473. t = 0;
  474. }
  475. pack->ident = grub_cpu_to_be32 (t);
  476. pack->seconds = grub_cpu_to_be16 (t);
  477. grub_memcpy (&pack->mac_addr, &ifaces[j].hwaddress.mac, 6);
  478. grub_netbuff_push (nb, sizeof (*udph));
  479. udph = (struct udphdr *) nb->data;
  480. udph->src = grub_cpu_to_be16_compile_time (68);
  481. udph->dst = grub_cpu_to_be16_compile_time (67);
  482. udph->chksum = 0;
  483. udph->len = grub_cpu_to_be16 (nb->tail - nb->data);
  484. target.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
  485. target.ipv4 = 0xffffffff;
  486. err = grub_net_link_layer_resolve (&ifaces[j], &target, &ll_target);
  487. if (err)
  488. return err;
  489. udph->chksum = grub_net_ip_transport_checksum (nb, GRUB_NET_IP_UDP,
  490. &ifaces[j].address,
  491. &target);
  492. err = grub_net_send_ip_packet (&ifaces[j], &target, &ll_target, nb,
  493. GRUB_NET_IP_UDP);
  494. grub_netbuff_free (nb);
  495. if (err)
  496. return err;
  497. }
  498. if (!done)
  499. break;
  500. grub_net_poll_cards (interval, 0);
  501. }
  502. err = GRUB_ERR_NONE;
  503. for (j = 0; j < ncards; j++)
  504. {
  505. grub_free (ifaces[j].name);
  506. if (!ifaces[j].prev)
  507. continue;
  508. grub_error_push ();
  509. grub_net_network_level_interface_unregister (&ifaces[j]);
  510. err = grub_error (GRUB_ERR_FILE_NOT_FOUND,
  511. N_("couldn't autoconfigure %s"),
  512. ifaces[j].card->name);
  513. }
  514. grub_free (ifaces);
  515. return err;
  516. }
  517. static grub_command_t cmd_getdhcp, cmd_bootp;
  518. void
  519. grub_bootp_init (void)
  520. {
  521. cmd_bootp = grub_register_command ("net_bootp", grub_cmd_bootp,
  522. N_("[CARD]"),
  523. N_("perform a bootp autoconfiguration"));
  524. cmd_getdhcp = grub_register_command ("net_get_dhcp_option", grub_cmd_dhcpopt,
  525. N_("VAR INTERFACE NUMBER DESCRIPTION"),
  526. N_("retrieve DHCP option and save it into VAR. If VAR is - then print the value."));
  527. }
  528. void
  529. grub_bootp_fini (void)
  530. {
  531. grub_unregister_command (cmd_getdhcp);
  532. grub_unregister_command (cmd_bootp);
  533. }