bootp.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890
  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. struct grub_dhcp_discover_options
  27. {
  28. grub_uint8_t magic[4];
  29. struct
  30. {
  31. grub_uint8_t code;
  32. grub_uint8_t len;
  33. grub_uint8_t data;
  34. } GRUB_PACKED message_type;
  35. grub_uint8_t end;
  36. } GRUB_PACKED;
  37. struct grub_dhcp_request_options
  38. {
  39. grub_uint8_t magic[4];
  40. struct
  41. {
  42. grub_uint8_t code;
  43. grub_uint8_t len;
  44. grub_uint8_t data;
  45. } GRUB_PACKED message_type;
  46. struct
  47. {
  48. grub_uint8_t type;
  49. grub_uint8_t len;
  50. grub_uint32_t data;
  51. } GRUB_PACKED server_identifier;
  52. struct
  53. {
  54. grub_uint8_t type;
  55. grub_uint8_t len;
  56. grub_uint32_t data;
  57. } GRUB_PACKED requested_ip;
  58. struct
  59. {
  60. grub_uint8_t type;
  61. grub_uint8_t len;
  62. grub_uint8_t data[7];
  63. } GRUB_PACKED parameter_request;
  64. grub_uint8_t end;
  65. } GRUB_PACKED;
  66. enum
  67. {
  68. GRUB_DHCP_OPT_OVERLOAD_FILE = 1,
  69. GRUB_DHCP_OPT_OVERLOAD_SNAME = 2,
  70. };
  71. enum
  72. {
  73. GRUB_DHCP_MESSAGE_UNKNOWN,
  74. GRUB_DHCP_MESSAGE_DISCOVER,
  75. GRUB_DHCP_MESSAGE_OFFER,
  76. GRUB_DHCP_MESSAGE_REQUEST,
  77. GRUB_DHCP_MESSAGE_DECLINE,
  78. GRUB_DHCP_MESSAGE_ACK,
  79. GRUB_DHCP_MESSAGE_NAK,
  80. GRUB_DHCP_MESSAGE_RELEASE,
  81. GRUB_DHCP_MESSAGE_INFORM,
  82. };
  83. #define GRUB_BOOTP_MAX_OPTIONS_SIZE 64
  84. /* Max timeout when waiting for BOOTP/DHCP reply */
  85. #define GRUB_DHCP_MAX_PACKET_TIMEOUT 32
  86. #define GRUB_BOOTP_MAX_OPTIONS_SIZE 64
  87. /* Max timeout when waiting for BOOTP/DHCP reply */
  88. #define GRUB_DHCP_MAX_PACKET_TIMEOUT 32
  89. static const void *
  90. find_dhcp_option (const struct grub_net_bootp_packet *bp, grub_size_t size,
  91. grub_uint8_t opt_code, grub_uint8_t *opt_len)
  92. {
  93. const grub_uint8_t *ptr;
  94. grub_uint8_t overload = 0;
  95. int end = 0;
  96. grub_size_t i;
  97. if (opt_len)
  98. *opt_len = 0;
  99. /* Is the packet big enough to hold at least the magic cookie? */
  100. if (size < sizeof (*bp) + sizeof (grub_uint32_t))
  101. return NULL;
  102. /*
  103. * Pointer arithmetic to point behind the common stub packet, where
  104. * the options start.
  105. */
  106. ptr = (grub_uint8_t *) (bp + 1);
  107. if (ptr[0] != GRUB_NET_BOOTP_RFC1048_MAGIC_0
  108. || ptr[1] != GRUB_NET_BOOTP_RFC1048_MAGIC_1
  109. || ptr[2] != GRUB_NET_BOOTP_RFC1048_MAGIC_2
  110. || ptr[3] != GRUB_NET_BOOTP_RFC1048_MAGIC_3)
  111. return NULL;
  112. size -= sizeof (*bp);
  113. i = sizeof (grub_uint32_t);
  114. again:
  115. while (i < size)
  116. {
  117. grub_uint8_t tagtype;
  118. grub_uint8_t taglength;
  119. tagtype = ptr[i++];
  120. /* Pad tag. */
  121. if (tagtype == GRUB_NET_BOOTP_PAD)
  122. continue;
  123. /* End tag. */
  124. if (tagtype == GRUB_NET_BOOTP_END)
  125. {
  126. end = 1;
  127. break;
  128. }
  129. if (i >= size)
  130. return NULL;
  131. taglength = ptr[i++];
  132. if (i + taglength >= size)
  133. return NULL;
  134. /* FIXME RFC 3396 options concatentation */
  135. if (tagtype == opt_code)
  136. {
  137. if (opt_len)
  138. *opt_len = taglength;
  139. return &ptr[i];
  140. }
  141. if (tagtype == GRUB_NET_DHCP_OVERLOAD && taglength == 1)
  142. overload = ptr[i];
  143. i += taglength;
  144. }
  145. if (!end)
  146. return NULL;
  147. /* RFC2131, 4.1, 23ff:
  148. * If the options in a DHCP message extend into the 'sname' and 'file'
  149. * fields, the 'option overload' option MUST appear in the 'options'
  150. * field, with value 1, 2 or 3, as specified in RFC 1533. If the
  151. * 'option overload' option is present in the 'options' field, the
  152. * options in the 'options' field MUST be terminated by an 'end' option,
  153. * and MAY contain one or more 'pad' options to fill the options field.
  154. * The options in the 'sname' and 'file' fields (if in use as indicated
  155. * by the 'options overload' option) MUST begin with the first octet of
  156. * the field, MUST be terminated by an 'end' option, and MUST be
  157. * followed by 'pad' options to fill the remainder of the field. Any
  158. * individual option in the 'options', 'sname' and 'file' fields MUST be
  159. * entirely contained in that field. The options in the 'options' field
  160. * MUST be interpreted first, so that any 'option overload' options may
  161. * be interpreted. The 'file' field MUST be interpreted next (if the
  162. * 'option overload' option indicates that the 'file' field contains
  163. * DHCP options), followed by the 'sname' field.
  164. *
  165. * FIXME: We do not explicitly check for trailing 'pad' options here.
  166. */
  167. end = 0;
  168. if (overload & GRUB_DHCP_OPT_OVERLOAD_FILE)
  169. {
  170. overload &= ~GRUB_DHCP_OPT_OVERLOAD_FILE;
  171. ptr = (grub_uint8_t *) &bp->boot_file[0];
  172. size = sizeof (bp->boot_file);
  173. i = 0;
  174. goto again;
  175. }
  176. if (overload & GRUB_DHCP_OPT_OVERLOAD_SNAME)
  177. {
  178. overload &= ~GRUB_DHCP_OPT_OVERLOAD_SNAME;
  179. ptr = (grub_uint8_t *) &bp->server_name[0];
  180. size = sizeof (bp->server_name);
  181. i = 0;
  182. goto again;
  183. }
  184. return NULL;
  185. }
  186. #define OFFSET_OF(x, y) ((grub_size_t)((grub_uint8_t *)((y)->x) - (grub_uint8_t *)(y)))
  187. struct grub_net_network_level_interface *
  188. grub_net_configure_by_dhcp_ack (const char *name,
  189. struct grub_net_card *card,
  190. grub_net_interface_flags_t flags,
  191. const struct grub_net_bootp_packet *bp,
  192. grub_size_t size,
  193. int is_def, char **device, char **path)
  194. {
  195. grub_net_network_level_address_t addr;
  196. grub_net_link_level_address_t hwaddr;
  197. struct grub_net_network_level_interface *inter;
  198. int mask = -1;
  199. char server_ip[sizeof ("xxx.xxx.xxx.xxx")];
  200. const grub_uint8_t *opt;
  201. grub_uint8_t opt_len, overload = 0;
  202. const char *boot_file = 0, *server_name = 0;
  203. grub_size_t boot_file_len, server_name_len;
  204. addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
  205. addr.ipv4 = bp->your_ip;
  206. if (device)
  207. *device = 0;
  208. if (path)
  209. *path = 0;
  210. grub_memcpy (hwaddr.mac, bp->mac_addr,
  211. bp->hw_len < sizeof (hwaddr.mac) ? bp->hw_len
  212. : sizeof (hwaddr.mac));
  213. hwaddr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
  214. inter = grub_net_add_addr (name, card, &addr, &hwaddr, flags);
  215. if (!inter)
  216. return 0;
  217. opt = find_dhcp_option (bp, size, GRUB_NET_DHCP_OVERLOAD, &opt_len);
  218. if (opt && opt_len == 1)
  219. overload = *opt;
  220. opt = find_dhcp_option (bp, size, GRUB_NET_DHCP_TFTP_SERVER_NAME, &opt_len);
  221. if (opt && opt_len)
  222. {
  223. server_name = (const char *) opt;
  224. server_name_len = opt_len;
  225. }
  226. else if (size > OFFSET_OF (server_name, bp) && !(overload & GRUB_DHCP_OPT_OVERLOAD_SNAME) &&
  227. bp->server_name[0])
  228. {
  229. server_name = bp->server_name;
  230. server_name_len = sizeof (bp->server_name);
  231. }
  232. opt = find_dhcp_option (bp, size, GRUB_NET_DHCP_BOOTFILE_NAME, &opt_len);
  233. if (opt && opt_len)
  234. {
  235. boot_file = (const char *) opt;
  236. boot_file_len = opt_len;
  237. }
  238. else if (size > OFFSET_OF (boot_file, bp) && !(overload && GRUB_DHCP_OPT_OVERLOAD_FILE) &&
  239. bp->boot_file[0])
  240. {
  241. boot_file = bp->boot_file;
  242. boot_file_len = sizeof (bp->boot_file);
  243. }
  244. if (bp->server_ip)
  245. {
  246. grub_snprintf (server_ip, sizeof (server_ip), "%d.%d.%d.%d",
  247. ((grub_uint8_t *) &bp->server_ip)[0],
  248. ((grub_uint8_t *) &bp->server_ip)[1],
  249. ((grub_uint8_t *) &bp->server_ip)[2],
  250. ((grub_uint8_t *) &bp->server_ip)[3]);
  251. grub_env_set_net_property (name, "next_server", server_ip, sizeof (server_ip));
  252. grub_print_error ();
  253. }
  254. if (is_def)
  255. grub_net_default_server = 0;
  256. if (is_def && !grub_net_default_server && bp->server_ip)
  257. {
  258. grub_net_default_server = grub_strdup (server_ip);
  259. grub_print_error ();
  260. }
  261. if (is_def)
  262. {
  263. grub_env_set ("net_default_interface", name);
  264. grub_env_export ("net_default_interface");
  265. }
  266. if (device && !*device && bp->server_ip)
  267. {
  268. *device = grub_xasprintf ("tftp,%s", server_ip);
  269. grub_print_error ();
  270. }
  271. if (server_name)
  272. {
  273. grub_env_set_net_property (name, "dhcp_server_name", server_name, server_name_len);
  274. if (is_def && !grub_net_default_server)
  275. {
  276. grub_net_default_server = grub_strdup (server_name);
  277. grub_print_error ();
  278. }
  279. if (device && !*device)
  280. {
  281. *device = grub_xasprintf ("tftp,%s", server_name);
  282. grub_print_error ();
  283. }
  284. }
  285. if (boot_file)
  286. {
  287. grub_env_set_net_property (name, "boot_file", boot_file, boot_file_len);
  288. if (path)
  289. {
  290. *path = grub_strndup (boot_file, boot_file_len);
  291. grub_print_error ();
  292. if (*path)
  293. {
  294. char *slash;
  295. slash = grub_strrchr (*path, '/');
  296. if (slash)
  297. *slash = 0;
  298. else
  299. **path = 0;
  300. }
  301. }
  302. }
  303. opt = find_dhcp_option (bp, size, GRUB_NET_BOOTP_NETMASK, &opt_len);
  304. if (opt && opt_len == 4)
  305. {
  306. int i;
  307. for (i = 0; i < 32; i++)
  308. if (!(opt[i / 8] & (1 << (7 - (i % 8)))))
  309. break;
  310. mask = i;
  311. }
  312. grub_net_add_ipv4_local (inter, mask);
  313. /* We do not implement dead gateway detection and the first entry SHOULD
  314. be preferred one */
  315. opt = find_dhcp_option (bp, size, GRUB_NET_BOOTP_ROUTER, &opt_len);
  316. if (opt && opt_len && !(opt_len & 3))
  317. {
  318. grub_net_network_level_netaddress_t target;
  319. grub_net_network_level_address_t gw;
  320. char *rname;
  321. target.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
  322. target.ipv4.base = 0;
  323. target.ipv4.masksize = 0;
  324. gw.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
  325. gw.ipv4 = grub_get_unaligned32 (opt);
  326. rname = grub_xasprintf ("%s:default", name);
  327. if (rname)
  328. grub_net_add_route_gw (rname, target, gw, 0);
  329. grub_free (rname);
  330. }
  331. opt = find_dhcp_option (bp, size, GRUB_NET_BOOTP_DNS, &opt_len);
  332. if (opt && opt_len && !(opt_len & 3))
  333. {
  334. int i;
  335. for (i = 0; i < opt_len / 4; i++)
  336. {
  337. struct grub_net_network_level_address s;
  338. s.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
  339. s.ipv4 = grub_get_unaligned32 (opt);
  340. s.option = DNS_OPTION_PREFER_IPV4;
  341. grub_net_add_dns_server (&s);
  342. opt += 4;
  343. }
  344. }
  345. opt = find_dhcp_option (bp, size, GRUB_NET_BOOTP_HOSTNAME, &opt_len);
  346. if (opt && opt_len)
  347. grub_env_set_net_property (name, "hostname", (const char *) opt, opt_len);
  348. opt = find_dhcp_option (bp, size, GRUB_NET_BOOTP_DOMAIN, &opt_len);
  349. if (opt && opt_len)
  350. grub_env_set_net_property (name, "domain", (const char *) opt, opt_len);
  351. opt = find_dhcp_option (bp, size, GRUB_NET_BOOTP_ROOT_PATH, &opt_len);
  352. if (opt && opt_len)
  353. grub_env_set_net_property (name, "rootpath", (const char *) opt, opt_len);
  354. opt = find_dhcp_option (bp, size, GRUB_NET_BOOTP_EXTENSIONS_PATH, &opt_len);
  355. if (opt && opt_len)
  356. grub_env_set_net_property (name, "extensionspath", (const char *) opt, opt_len);
  357. inter->dhcp_ack = grub_malloc (size);
  358. if (inter->dhcp_ack)
  359. {
  360. grub_memcpy (inter->dhcp_ack, bp, size);
  361. inter->dhcp_acklen = size;
  362. }
  363. else
  364. grub_errno = GRUB_ERR_NONE;
  365. return inter;
  366. }
  367. static grub_err_t
  368. send_dhcp_packet (struct grub_net_network_level_interface *iface)
  369. {
  370. grub_err_t err;
  371. struct grub_net_bootp_packet *pack;
  372. struct grub_datetime date;
  373. grub_int32_t t = 0;
  374. struct grub_net_buff *nb;
  375. struct udphdr *udph;
  376. grub_net_network_level_address_t target;
  377. grub_net_link_level_address_t ll_target;
  378. static struct grub_dhcp_discover_options discover_options =
  379. {
  380. {
  381. GRUB_NET_BOOTP_RFC1048_MAGIC_0,
  382. GRUB_NET_BOOTP_RFC1048_MAGIC_1,
  383. GRUB_NET_BOOTP_RFC1048_MAGIC_2,
  384. GRUB_NET_BOOTP_RFC1048_MAGIC_3,
  385. },
  386. {
  387. GRUB_NET_DHCP_MESSAGE_TYPE,
  388. sizeof (discover_options.message_type.data),
  389. GRUB_DHCP_MESSAGE_DISCOVER,
  390. },
  391. GRUB_NET_BOOTP_END,
  392. };
  393. static struct grub_dhcp_request_options request_options =
  394. {
  395. {
  396. GRUB_NET_BOOTP_RFC1048_MAGIC_0,
  397. GRUB_NET_BOOTP_RFC1048_MAGIC_1,
  398. GRUB_NET_BOOTP_RFC1048_MAGIC_2,
  399. GRUB_NET_BOOTP_RFC1048_MAGIC_3,
  400. },
  401. {
  402. GRUB_NET_DHCP_MESSAGE_TYPE,
  403. sizeof (request_options.message_type.data),
  404. GRUB_DHCP_MESSAGE_REQUEST,
  405. },
  406. {
  407. GRUB_NET_DHCP_SERVER_IDENTIFIER,
  408. sizeof (request_options.server_identifier.data),
  409. 0,
  410. },
  411. {
  412. GRUB_NET_DHCP_REQUESTED_IP_ADDRESS,
  413. sizeof (request_options.requested_ip.data),
  414. 0,
  415. },
  416. {
  417. GRUB_NET_DHCP_PARAMETER_REQUEST_LIST,
  418. sizeof (request_options.parameter_request.data),
  419. {
  420. GRUB_NET_BOOTP_NETMASK,
  421. GRUB_NET_BOOTP_ROUTER,
  422. GRUB_NET_BOOTP_DNS,
  423. GRUB_NET_BOOTP_DOMAIN,
  424. GRUB_NET_BOOTP_HOSTNAME,
  425. GRUB_NET_BOOTP_ROOT_PATH,
  426. GRUB_NET_BOOTP_EXTENSIONS_PATH,
  427. },
  428. },
  429. GRUB_NET_BOOTP_END,
  430. };
  431. COMPILE_TIME_ASSERT (sizeof (discover_options) <= GRUB_BOOTP_MAX_OPTIONS_SIZE);
  432. COMPILE_TIME_ASSERT (sizeof (request_options) <= GRUB_BOOTP_MAX_OPTIONS_SIZE);
  433. nb = grub_netbuff_alloc (sizeof (*pack) + GRUB_BOOTP_MAX_OPTIONS_SIZE + 128);
  434. if (!nb)
  435. return grub_errno;
  436. err = grub_netbuff_reserve (nb, sizeof (*pack) + GRUB_BOOTP_MAX_OPTIONS_SIZE + 128);
  437. if (err)
  438. goto out;
  439. err = grub_netbuff_push (nb, GRUB_BOOTP_MAX_OPTIONS_SIZE);
  440. if (err)
  441. goto out;
  442. grub_memset (nb->data, 0, GRUB_BOOTP_MAX_OPTIONS_SIZE);
  443. if (!iface->srv_id)
  444. {
  445. grub_memcpy (nb->data, &discover_options, sizeof (discover_options));
  446. }
  447. else
  448. {
  449. struct grub_dhcp_request_options *ro = (struct grub_dhcp_request_options *) nb->data;
  450. grub_memcpy (nb->data, &request_options, sizeof (request_options));
  451. /* my_ip and srv_id are stored in network order so do not need conversion. */
  452. grub_set_unaligned32 (&ro->server_identifier.data, iface->srv_id);
  453. grub_set_unaligned32 (&ro->requested_ip.data, iface->my_ip);
  454. }
  455. err = grub_netbuff_push (nb, sizeof (*pack));
  456. if (err)
  457. goto out;
  458. pack = (void *) nb->data;
  459. grub_memset (pack, 0, sizeof (*pack));
  460. pack->opcode = 1;
  461. pack->hw_type = 1;
  462. pack->hw_len = 6;
  463. err = grub_get_datetime (&date);
  464. if (err || !grub_datetime2unixtime (&date, &t))
  465. {
  466. grub_errno = GRUB_ERR_NONE;
  467. t = 0;
  468. }
  469. pack->seconds = grub_cpu_to_be16 (t);
  470. if (!iface->srv_id)
  471. iface->xid = pack->ident = grub_cpu_to_be32 (t);
  472. else
  473. pack->ident = iface->xid;
  474. grub_memcpy (&pack->mac_addr, &iface->hwaddress.mac, 6);
  475. grub_netbuff_push (nb, sizeof (*udph));
  476. udph = (struct udphdr *) nb->data;
  477. udph->src = grub_cpu_to_be16_compile_time (68);
  478. udph->dst = grub_cpu_to_be16_compile_time (67);
  479. udph->chksum = 0;
  480. udph->len = grub_cpu_to_be16 (nb->tail - nb->data);
  481. target.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
  482. target.ipv4 = 0xffffffff;
  483. err = grub_net_link_layer_resolve (iface, &target, &ll_target);
  484. if (err)
  485. goto out;
  486. udph->chksum = grub_net_ip_transport_checksum (nb, GRUB_NET_IP_UDP,
  487. &iface->address,
  488. &target);
  489. err = grub_net_send_ip_packet (iface, &target, &ll_target, nb,
  490. GRUB_NET_IP_UDP);
  491. out:
  492. grub_netbuff_free (nb);
  493. return err;
  494. }
  495. /*
  496. * This is called directly from net/ip.c:handle_dgram(), because those
  497. * BOOTP/DHCP packets are a bit special due to their improper
  498. * sender/receiver IP fields.
  499. */
  500. void
  501. grub_net_process_dhcp (struct grub_net_buff *nb,
  502. struct grub_net_network_level_interface *iface)
  503. {
  504. char *name;
  505. struct grub_net_card *card = iface->card;
  506. const struct grub_net_bootp_packet *bp = (const struct grub_net_bootp_packet *) nb->data;
  507. grub_size_t size = nb->tail - nb->data;
  508. const grub_uint8_t *opt;
  509. grub_uint8_t opt_len, type;
  510. grub_uint32_t srv_id = 0;
  511. opt = find_dhcp_option (bp, size, GRUB_NET_DHCP_MESSAGE_TYPE, &opt_len);
  512. if (opt && opt_len == 1)
  513. type = *opt;
  514. else
  515. type = GRUB_DHCP_MESSAGE_UNKNOWN;
  516. opt = find_dhcp_option (bp, size, GRUB_NET_DHCP_SERVER_IDENTIFIER, &opt_len);
  517. if (opt && opt_len == sizeof (srv_id))
  518. srv_id = grub_get_unaligned32 (opt);
  519. /*
  520. * If we received BOOTP reply or DHCPACK, proceed with configuration.
  521. * Otherwise store offered address and server id for later processing
  522. * of DHCPACK.
  523. * xid and srv_id are stored in network order so do not need conversion.
  524. */
  525. if ((!iface->srv_id && type == GRUB_DHCP_MESSAGE_UNKNOWN)
  526. || (iface->srv_id && type == GRUB_DHCP_MESSAGE_ACK
  527. && bp->ident == iface->xid
  528. && srv_id == iface->srv_id))
  529. {
  530. name = grub_xasprintf ("%s:dhcp", card->name);
  531. if (!name)
  532. {
  533. grub_print_error ();
  534. return;
  535. }
  536. grub_net_configure_by_dhcp_ack (name, card, 0, bp, size, 0, 0, 0);
  537. grub_free (name);
  538. if (grub_errno)
  539. grub_print_error ();
  540. else
  541. grub_net_network_level_interface_unregister (iface);
  542. }
  543. else if (!iface->srv_id && type == GRUB_DHCP_MESSAGE_OFFER && srv_id)
  544. {
  545. iface->srv_id = srv_id;
  546. iface->my_ip = bp->your_ip;
  547. /* Reset retransmission timer */
  548. iface->dhcp_tmo = iface->dhcp_tmo_left = 1;
  549. }
  550. else if (iface->srv_id && type == GRUB_DHCP_MESSAGE_NAK
  551. && bp->ident == iface->xid
  552. && srv_id == iface->srv_id)
  553. {
  554. iface->xid = iface->srv_id = iface->my_ip = 0;
  555. /* Reset retransmission timer */
  556. iface->dhcp_tmo = iface->dhcp_tmo_left = 1;
  557. }
  558. }
  559. static char
  560. hexdigit (grub_uint8_t val)
  561. {
  562. if (val < 10)
  563. return val + '0';
  564. return val + 'a' - 10;
  565. }
  566. static grub_err_t
  567. grub_cmd_dhcpopt (struct grub_command *cmd __attribute__ ((unused)),
  568. int argc, char **args)
  569. {
  570. struct grub_net_network_level_interface *inter;
  571. unsigned num;
  572. const grub_uint8_t *ptr;
  573. grub_uint8_t taglength;
  574. if (argc < 4)
  575. return grub_error (GRUB_ERR_BAD_ARGUMENT,
  576. N_("four arguments expected"));
  577. FOR_NET_NETWORK_LEVEL_INTERFACES (inter)
  578. if (grub_strcmp (inter->name, args[1]) == 0)
  579. break;
  580. if (!inter)
  581. return grub_error (GRUB_ERR_BAD_ARGUMENT,
  582. N_("unrecognised network interface `%s'"), args[1]);
  583. if (!inter->dhcp_ack)
  584. return grub_error (GRUB_ERR_IO, N_("no DHCP info found"));
  585. ptr = inter->dhcp_ack->vendor;
  586. /* This duplicates check in find_dhcp_option to preserve previous error return */
  587. if (inter->dhcp_acklen < OFFSET_OF (vendor, inter->dhcp_ack) + sizeof (grub_uint32_t)
  588. || ptr[0] != GRUB_NET_BOOTP_RFC1048_MAGIC_0
  589. || ptr[1] != GRUB_NET_BOOTP_RFC1048_MAGIC_1
  590. || ptr[2] != GRUB_NET_BOOTP_RFC1048_MAGIC_2
  591. || ptr[3] != GRUB_NET_BOOTP_RFC1048_MAGIC_3)
  592. return grub_error (GRUB_ERR_IO, N_("no DHCP options found"));
  593. num = grub_strtoul (args[2], 0, 0);
  594. if (grub_errno)
  595. return grub_errno;
  596. /* Exclude PAD (0) and END (255) option codes */
  597. if (num == 0 || num > 254)
  598. return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("invalid DHCP option code"));
  599. ptr = find_dhcp_option (inter->dhcp_ack, inter->dhcp_acklen, num, &taglength);
  600. if (!ptr)
  601. return grub_error (GRUB_ERR_IO, N_("no DHCP option %u found"), num);
  602. if (grub_strcmp (args[3], "string") == 0)
  603. {
  604. grub_err_t err = GRUB_ERR_NONE;
  605. char *val = grub_malloc (taglength + 1);
  606. if (!val)
  607. return grub_errno;
  608. grub_memcpy (val, ptr, taglength);
  609. val[taglength] = 0;
  610. if (args[0][0] == '-' && args[0][1] == 0)
  611. grub_printf ("%s\n", val);
  612. else
  613. err = grub_env_set (args[0], val);
  614. grub_free (val);
  615. return err;
  616. }
  617. if (grub_strcmp (args[3], "number") == 0)
  618. {
  619. grub_uint64_t val = 0;
  620. int i;
  621. for (i = 0; i < taglength; i++)
  622. val = (val << 8) | ptr[i];
  623. if (args[0][0] == '-' && args[0][1] == 0)
  624. grub_printf ("%llu\n", (unsigned long long) val);
  625. else
  626. {
  627. char valn[64];
  628. grub_snprintf (valn, sizeof (valn), "%lld\n", (unsigned long long) val);
  629. return grub_env_set (args[0], valn);
  630. }
  631. return GRUB_ERR_NONE;
  632. }
  633. if (grub_strcmp (args[3], "hex") == 0)
  634. {
  635. grub_err_t err = GRUB_ERR_NONE;
  636. char *val = grub_malloc (2 * taglength + 1);
  637. int i;
  638. if (!val)
  639. return grub_errno;
  640. for (i = 0; i < taglength; i++)
  641. {
  642. val[2 * i] = hexdigit (ptr[i] >> 4);
  643. val[2 * i + 1] = hexdigit (ptr[i] & 0xf);
  644. }
  645. val[2 * taglength] = 0;
  646. if (args[0][0] == '-' && args[0][1] == 0)
  647. grub_printf ("%s\n", val);
  648. else
  649. err = grub_env_set (args[0], val);
  650. grub_free (val);
  651. return err;
  652. }
  653. return grub_error (GRUB_ERR_BAD_ARGUMENT,
  654. N_("unrecognised DHCP option format specification `%s'"),
  655. args[3]);
  656. }
  657. /* FIXME: allow to specify mac address. */
  658. static grub_err_t
  659. grub_cmd_bootp (struct grub_command *cmd __attribute__ ((unused)),
  660. int argc, char **args)
  661. {
  662. struct grub_net_card *card;
  663. struct grub_net_network_level_interface *ifaces;
  664. grub_size_t ncards = 0;
  665. unsigned j = 0;
  666. grub_err_t err;
  667. unsigned i;
  668. FOR_NET_CARDS (card)
  669. {
  670. if (argc > 0 && grub_strcmp (card->name, args[0]) != 0)
  671. continue;
  672. ncards++;
  673. }
  674. if (ncards == 0)
  675. return grub_error (GRUB_ERR_NET_NO_CARD, N_("no network card found"));
  676. ifaces = grub_zalloc (ncards * sizeof (ifaces[0]));
  677. if (!ifaces)
  678. return grub_errno;
  679. j = 0;
  680. FOR_NET_CARDS (card)
  681. {
  682. if (argc > 0 && grub_strcmp (card->name, args[0]) != 0)
  683. continue;
  684. ifaces[j].card = card;
  685. ifaces[j].next = &ifaces[j+1];
  686. if (j)
  687. ifaces[j].prev = &ifaces[j-1].next;
  688. ifaces[j].name = grub_xasprintf ("%s:dhcp_tmp", card->name);
  689. card->num_ifaces++;
  690. if (!ifaces[j].name)
  691. {
  692. for (i = 0; i < j; i++)
  693. grub_free (ifaces[i].name);
  694. grub_free (ifaces);
  695. return grub_errno;
  696. }
  697. ifaces[j].address.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_DHCP_RECV;
  698. grub_memcpy (&ifaces[j].hwaddress, &card->default_address,
  699. sizeof (ifaces[j].hwaddress));
  700. ifaces[j].dhcp_tmo = ifaces[j].dhcp_tmo_left = 1;
  701. j++;
  702. }
  703. ifaces[ncards - 1].next = grub_net_network_level_interfaces;
  704. if (grub_net_network_level_interfaces)
  705. grub_net_network_level_interfaces->prev = & ifaces[ncards - 1].next;
  706. grub_net_network_level_interfaces = &ifaces[0];
  707. ifaces[0].prev = &grub_net_network_level_interfaces;
  708. /*
  709. * Running DHCP restransmission timer is kept per interface in dhcp_tmo_left.
  710. * When it runs off, dhcp_tmo is increased exponentionally and dhcp_tmo_left
  711. * initialized to it. Max value is 32 which gives approximately 12s total per
  712. * packet timeout assuming 200ms poll tick. Timeout is reset when DHCP OFFER
  713. * is received, so total timeout is 25s in the worst case.
  714. *
  715. * DHCP NAK also resets timer and transaction starts again.
  716. *
  717. * Total wait time is limited to ~25s to prevent endless loop in case of
  718. * permanent NAK
  719. */
  720. for (i = 0; i < GRUB_DHCP_MAX_PACKET_TIMEOUT * 4; i++)
  721. {
  722. int need_poll = 0;
  723. for (j = 0; j < ncards; j++)
  724. {
  725. if (!ifaces[j].prev ||
  726. ifaces[j].dhcp_tmo > GRUB_DHCP_MAX_PACKET_TIMEOUT)
  727. continue;
  728. if (--ifaces[j].dhcp_tmo_left)
  729. {
  730. need_poll = 1;
  731. continue;
  732. }
  733. ifaces[j].dhcp_tmo *= 2;
  734. if (ifaces[j].dhcp_tmo > GRUB_DHCP_MAX_PACKET_TIMEOUT)
  735. continue;
  736. err = send_dhcp_packet (&ifaces[j]);
  737. if (err)
  738. {
  739. grub_print_error ();
  740. /* To ignore it during next poll */
  741. ifaces[j].dhcp_tmo = GRUB_DHCP_MAX_PACKET_TIMEOUT + 1;
  742. continue;
  743. }
  744. ifaces[j].dhcp_tmo_left = ifaces[j].dhcp_tmo;
  745. need_poll = 1;
  746. }
  747. if (!need_poll)
  748. break;
  749. grub_net_poll_cards (200, 0);
  750. }
  751. err = GRUB_ERR_NONE;
  752. for (j = 0; j < ncards; j++)
  753. {
  754. grub_free (ifaces[j].name);
  755. if (!ifaces[j].prev)
  756. continue;
  757. grub_error_push ();
  758. grub_net_network_level_interface_unregister (&ifaces[j]);
  759. err = grub_error (GRUB_ERR_FILE_NOT_FOUND,
  760. N_("couldn't autoconfigure %s"),
  761. ifaces[j].card->name);
  762. }
  763. grub_free (ifaces);
  764. return err;
  765. }
  766. static grub_command_t cmd_getdhcp, cmd_bootp, cmd_dhcp;
  767. void
  768. grub_bootp_init (void)
  769. {
  770. cmd_bootp = grub_register_command ("net_bootp", grub_cmd_bootp,
  771. N_("[CARD]"),
  772. N_("perform a bootp autoconfiguration"));
  773. cmd_dhcp = grub_register_command ("net_dhcp", grub_cmd_bootp,
  774. N_("[CARD]"),
  775. N_("perform a DHCP autoconfiguration"));
  776. cmd_getdhcp = grub_register_command ("net_get_dhcp_option", grub_cmd_dhcpopt,
  777. N_("VAR INTERFACE NUMBER DESCRIPTION"),
  778. N_("retrieve DHCP option and save it into VAR. If VAR is - then print the value."));
  779. }
  780. void
  781. grub_bootp_fini (void)
  782. {
  783. grub_unregister_command (cmd_getdhcp);
  784. grub_unregister_command (cmd_bootp);
  785. grub_unregister_command (cmd_dhcp);
  786. }