bootp.c 25 KB

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