bootp.c 25 KB

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