ofnet.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549
  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/netbuff.h>
  19. #include <grub/ieee1275/ieee1275.h>
  20. #include <grub/dl.h>
  21. #include <grub/net.h>
  22. #include <grub/time.h>
  23. #include <grub/i18n.h>
  24. GRUB_MOD_LICENSE ("GPLv3+");
  25. struct grub_ofnetcard_data
  26. {
  27. char *path;
  28. char *suffix;
  29. grub_ieee1275_ihandle_t handle;
  30. };
  31. static grub_err_t
  32. card_open (struct grub_net_card *dev)
  33. {
  34. int status;
  35. struct grub_ofnetcard_data *data = dev->data;
  36. status = grub_ieee1275_open (data->path, &(data->handle));
  37. if (status)
  38. return grub_error (GRUB_ERR_IO, "Couldn't open network card.");
  39. return GRUB_ERR_NONE;
  40. }
  41. static void
  42. card_close (struct grub_net_card *dev)
  43. {
  44. struct grub_ofnetcard_data *data = dev->data;
  45. if (data->handle)
  46. grub_ieee1275_close (data->handle);
  47. }
  48. static grub_err_t
  49. send_card_buffer (struct grub_net_card *dev, struct grub_net_buff *pack)
  50. {
  51. grub_ssize_t actual;
  52. int status;
  53. struct grub_ofnetcard_data *data = dev->data;
  54. grub_size_t len;
  55. len = (pack->tail - pack->data);
  56. if (len > dev->mtu)
  57. len = dev->mtu;
  58. grub_memcpy (dev->txbuf, pack->data, len);
  59. status = grub_ieee1275_write (data->handle, dev->txbuf,
  60. len, &actual);
  61. if (status)
  62. return grub_error (GRUB_ERR_IO, N_("couldn't send network packet"));
  63. return GRUB_ERR_NONE;
  64. }
  65. static struct grub_net_buff *
  66. get_card_packet (struct grub_net_card *dev)
  67. {
  68. grub_ssize_t actual;
  69. int rc;
  70. struct grub_ofnetcard_data *data = dev->data;
  71. struct grub_net_buff *nb;
  72. rc = grub_ieee1275_read (data->handle, dev->rcvbuf, dev->rcvbufsize, &actual);
  73. if (actual <= 0 || rc < 0)
  74. return NULL;
  75. nb = grub_netbuff_alloc (actual + 2);
  76. if (!nb)
  77. return NULL;
  78. /* Reserve 2 bytes so that 2 + 14/18 bytes of ethernet header is divisible
  79. by 4. So that IP header is aligned on 4 bytes. */
  80. grub_netbuff_reserve (nb, 2);
  81. grub_memcpy (nb->data, dev->rcvbuf, actual);
  82. if (grub_netbuff_put (nb, actual))
  83. {
  84. grub_netbuff_free (nb);
  85. return NULL;
  86. }
  87. return nb;
  88. }
  89. static struct grub_net_card_driver ofdriver =
  90. {
  91. .name = "ofnet",
  92. .open = card_open,
  93. .close = card_close,
  94. .send = send_card_buffer,
  95. .recv = get_card_packet
  96. };
  97. static const struct
  98. {
  99. const char *name;
  100. int offset;
  101. }
  102. bootp_response_properties[] =
  103. {
  104. { .name = "bootp-response", .offset = 0},
  105. { .name = "dhcp-response", .offset = 0},
  106. { .name = "bootpreply-packet", .offset = 0x2a},
  107. };
  108. enum
  109. {
  110. BOOTARGS_SERVER_ADDR,
  111. BOOTARGS_FILENAME,
  112. BOOTARGS_CLIENT_ADDR,
  113. BOOTARGS_GATEWAY_ADDR,
  114. BOOTARGS_BOOTP_RETRIES,
  115. BOOTARGS_TFTP_RETRIES,
  116. BOOTARGS_SUBNET_MASK,
  117. BOOTARGS_BLOCKSIZE
  118. };
  119. static int
  120. grub_ieee1275_parse_bootpath (const char *devpath, char *bootpath,
  121. char **device, struct grub_net_card **card)
  122. {
  123. char *args;
  124. char *comma_char = 0;
  125. char *equal_char = 0;
  126. grub_size_t field_counter = 0;
  127. grub_net_network_level_address_t client_addr = {0, {0}, 0}, gateway_addr = {0, {0}, 0}, subnet_mask = {0, {0}, 0};
  128. grub_net_link_level_address_t hw_addr = {0, {{0, 0, 0, 0, 0, 0}}};
  129. grub_net_interface_flags_t flags = 0;
  130. struct grub_net_network_level_interface *inter = NULL;
  131. grub_uint16_t vlantag = 0;
  132. hw_addr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
  133. args = bootpath + grub_strlen (devpath) + 1;
  134. do
  135. {
  136. comma_char = grub_strchr (args, ',');
  137. if (comma_char != 0)
  138. *comma_char = 0;
  139. /* Check if it's an option (like speed=auto) and not a default parameter */
  140. equal_char = grub_strchr (args, '=');
  141. if (equal_char != 0)
  142. {
  143. *equal_char = 0;
  144. grub_env_set_net_property ((*card)->name, args, equal_char + 1,
  145. grub_strlen(equal_char + 1));
  146. if ((grub_strcmp (args, "vtag") == 0) &&
  147. (grub_strlen (equal_char + 1) == 8))
  148. vlantag = grub_strtoul (equal_char + 1 + 4, 0, 16);
  149. *equal_char = '=';
  150. }
  151. else
  152. {
  153. switch (field_counter++)
  154. {
  155. case BOOTARGS_SERVER_ADDR:
  156. *device = grub_xasprintf ("tftp,%s", args);
  157. if (!*device)
  158. return grub_errno;
  159. break;
  160. case BOOTARGS_CLIENT_ADDR:
  161. grub_net_resolve_address (args, &client_addr);
  162. break;
  163. case BOOTARGS_GATEWAY_ADDR:
  164. grub_net_resolve_address (args, &gateway_addr);
  165. break;
  166. case BOOTARGS_SUBNET_MASK:
  167. grub_net_resolve_address (args, &subnet_mask);
  168. break;
  169. }
  170. }
  171. args = comma_char + 1;
  172. if (comma_char != 0)
  173. *comma_char = ',';
  174. } while (comma_char != 0);
  175. if ((client_addr.ipv4 != 0) && (subnet_mask.ipv4 != 0))
  176. {
  177. grub_ieee1275_phandle_t devhandle;
  178. grub_ieee1275_finddevice (devpath, &devhandle);
  179. grub_ieee1275_get_property (devhandle, "mac-address",
  180. hw_addr.mac, sizeof(hw_addr.mac), 0);
  181. inter = grub_net_add_addr ((*card)->name, *card, &client_addr, &hw_addr,
  182. flags);
  183. inter->vlantag = vlantag;
  184. grub_net_add_ipv4_local (inter,
  185. __builtin_clz (~grub_be_to_cpu32 (subnet_mask.ipv4)));
  186. }
  187. if (gateway_addr.ipv4 != 0)
  188. {
  189. grub_net_network_level_netaddress_t target;
  190. char *rname;
  191. target.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
  192. target.ipv4.base = 0;
  193. target.ipv4.masksize = 0;
  194. rname = grub_xasprintf ("%s:default", ((*card)->name));
  195. if (rname)
  196. grub_net_add_route_gw (rname, target, gateway_addr, inter);
  197. else
  198. return grub_errno;
  199. }
  200. return 0;
  201. }
  202. static void
  203. grub_ieee1275_net_config_real (const char *devpath, char **device, char **path,
  204. char *bootpath)
  205. {
  206. struct grub_net_card *card;
  207. /* FIXME: Check that it's the right card. */
  208. FOR_NET_CARDS (card)
  209. {
  210. char *bootp_response;
  211. char *canon;
  212. char c;
  213. struct grub_ofnetcard_data *data;
  214. grub_ssize_t size = -1;
  215. unsigned int i;
  216. if (card->driver != &ofdriver)
  217. continue;
  218. data = card->data;
  219. c = *data->suffix;
  220. *data->suffix = '\0';
  221. canon = grub_ieee1275_canonicalise_devname (data->path);
  222. *data->suffix = c;
  223. if (grub_strcmp (devpath, canon) != 0)
  224. {
  225. grub_free (canon);
  226. continue;
  227. }
  228. grub_free (canon);
  229. grub_ieee1275_parse_bootpath (devpath, bootpath, device, &card);
  230. for (i = 0; i < ARRAY_SIZE (bootp_response_properties); i++)
  231. if (grub_ieee1275_get_property_length (grub_ieee1275_chosen,
  232. bootp_response_properties[i].name,
  233. &size) >= 0)
  234. break;
  235. if (size < 0)
  236. return;
  237. bootp_response = grub_malloc (size);
  238. if (!bootp_response)
  239. {
  240. grub_print_error ();
  241. return;
  242. }
  243. if (grub_ieee1275_get_property (grub_ieee1275_chosen,
  244. bootp_response_properties[i].name,
  245. bootp_response, size, 0) < 0)
  246. return;
  247. grub_net_configure_by_dhcp_ack (card->name, card, 0,
  248. (struct grub_net_bootp_packet *)
  249. (bootp_response
  250. + bootp_response_properties[i].offset),
  251. size - bootp_response_properties[i].offset,
  252. 1, device, path);
  253. grub_free (bootp_response);
  254. return;
  255. }
  256. }
  257. /* Allocate memory with alloc-mem */
  258. static void *
  259. grub_ieee1275_alloc_mem (grub_size_t len)
  260. {
  261. struct alloc_args
  262. {
  263. struct grub_ieee1275_common_hdr common;
  264. grub_ieee1275_cell_t method;
  265. grub_ieee1275_cell_t len;
  266. grub_ieee1275_cell_t catch;
  267. grub_ieee1275_cell_t result;
  268. }
  269. args;
  270. INIT_IEEE1275_COMMON (&args.common, "interpret", 2, 2);
  271. args.len = len;
  272. args.method = (grub_ieee1275_cell_t) "alloc-mem";
  273. if (IEEE1275_CALL_ENTRY_FN (&args) == -1 || args.catch)
  274. {
  275. grub_error (GRUB_ERR_INVALID_COMMAND, N_("alloc-mem failed"));
  276. return NULL;
  277. }
  278. else
  279. return (void *)args.result;
  280. }
  281. /* Free memory allocated by alloc-mem */
  282. static grub_err_t
  283. grub_ieee1275_free_mem (void *addr, grub_size_t len)
  284. {
  285. struct free_args
  286. {
  287. struct grub_ieee1275_common_hdr common;
  288. grub_ieee1275_cell_t method;
  289. grub_ieee1275_cell_t len;
  290. grub_ieee1275_cell_t addr;
  291. grub_ieee1275_cell_t catch;
  292. }
  293. args;
  294. INIT_IEEE1275_COMMON (&args.common, "interpret", 3, 1);
  295. args.addr = (grub_ieee1275_cell_t)addr;
  296. args.len = len;
  297. args.method = (grub_ieee1275_cell_t) "free-mem";
  298. if (IEEE1275_CALL_ENTRY_FN(&args) == -1 || args.catch)
  299. {
  300. grub_error (GRUB_ERR_INVALID_COMMAND, N_("free-mem failed"));
  301. return grub_errno;
  302. }
  303. return GRUB_ERR_NONE;
  304. }
  305. static void *
  306. ofnet_alloc_netbuf (grub_size_t len)
  307. {
  308. if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_VIRT_TO_REAL_BROKEN))
  309. return grub_ieee1275_alloc_mem (len);
  310. else
  311. return grub_zalloc (len);
  312. }
  313. static void
  314. ofnet_free_netbuf (void *addr, grub_size_t len)
  315. {
  316. if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_VIRT_TO_REAL_BROKEN))
  317. grub_ieee1275_free_mem (addr, len);
  318. else
  319. grub_free (addr);
  320. }
  321. static int
  322. search_net_devices (struct grub_ieee1275_devalias *alias)
  323. {
  324. struct grub_ofnetcard_data *ofdata;
  325. struct grub_net_card *card;
  326. grub_ieee1275_phandle_t devhandle;
  327. grub_net_link_level_address_t lla;
  328. grub_ssize_t prop_size;
  329. grub_uint64_t prop;
  330. grub_uint8_t *pprop;
  331. char *shortname;
  332. char need_suffix = 1;
  333. if (grub_strcmp (alias->type, "network") != 0)
  334. return 0;
  335. ofdata = grub_malloc (sizeof (struct grub_ofnetcard_data));
  336. if (!ofdata)
  337. {
  338. grub_print_error ();
  339. return 1;
  340. }
  341. card = grub_zalloc (sizeof (struct grub_net_card));
  342. if (!card)
  343. {
  344. grub_free (ofdata);
  345. grub_print_error ();
  346. return 1;
  347. }
  348. #define SUFFIX ":speed=auto,duplex=auto,1.1.1.1,dummy,1.1.1.1,1.1.1.1,5,5,1.1.1.1,512"
  349. if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_NO_OFNET_SUFFIX))
  350. need_suffix = 0;
  351. /* sun4v vnet devices do not support setting duplex/speed */
  352. {
  353. char *ptr;
  354. grub_ieee1275_finddevice (alias->path, &devhandle);
  355. grub_ieee1275_get_property_length (devhandle, "compatible", &prop_size);
  356. if (prop_size > 0)
  357. {
  358. pprop = grub_malloc (prop_size);
  359. if (!pprop)
  360. {
  361. grub_free (card);
  362. grub_free (ofdata);
  363. grub_print_error ();
  364. return 1;
  365. }
  366. if (!grub_ieee1275_get_property (devhandle, "compatible",
  367. pprop, prop_size, NULL))
  368. {
  369. for (ptr = (char *) pprop; ptr - (char *) pprop < prop_size;
  370. ptr += grub_strlen (ptr) + 1)
  371. {
  372. if (!grub_strcmp(ptr, "SUNW,sun4v-network"))
  373. need_suffix = 0;
  374. }
  375. }
  376. grub_free (pprop);
  377. }
  378. }
  379. if (need_suffix)
  380. ofdata->path = grub_malloc (grub_strlen (alias->path) + sizeof (SUFFIX));
  381. else
  382. ofdata->path = grub_malloc (grub_strlen (alias->path) + 1);
  383. if (!ofdata->path)
  384. {
  385. grub_print_error ();
  386. return 0;
  387. }
  388. ofdata->suffix = grub_stpcpy (ofdata->path, alias->path);
  389. if (need_suffix)
  390. grub_memcpy (ofdata->suffix, SUFFIX, sizeof (SUFFIX));
  391. else
  392. *ofdata->suffix = '\0';
  393. grub_ieee1275_finddevice (ofdata->path, &devhandle);
  394. {
  395. grub_uint32_t t;
  396. if (grub_ieee1275_get_integer_property (devhandle,
  397. "max-frame-size", &t,
  398. sizeof (t), 0))
  399. card->mtu = 1500;
  400. else
  401. card->mtu = t;
  402. }
  403. pprop = (grub_uint8_t *) &prop;
  404. if (grub_ieee1275_get_property (devhandle, "mac-address",
  405. pprop, sizeof(prop), &prop_size)
  406. && grub_ieee1275_get_property (devhandle, "local-mac-address",
  407. pprop, sizeof(prop), &prop_size))
  408. {
  409. grub_error (GRUB_ERR_IO, "Couldn't retrieve mac address.");
  410. grub_print_error ();
  411. return 0;
  412. }
  413. if (prop_size == 8)
  414. grub_memcpy (&lla.mac, pprop+2, 6);
  415. else
  416. grub_memcpy (&lla.mac, pprop, 6);
  417. lla.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
  418. card->default_address = lla;
  419. card->txbufsize = ALIGN_UP (card->mtu, 64) + 256;
  420. card->rcvbufsize = ALIGN_UP (card->mtu, 64) + 256;
  421. card->txbuf = ofnet_alloc_netbuf (card->txbufsize);
  422. if (!card->txbuf)
  423. goto fail_netbuf;
  424. card->rcvbuf = ofnet_alloc_netbuf (card->rcvbufsize);
  425. if (!card->rcvbuf)
  426. {
  427. grub_error_push ();
  428. ofnet_free_netbuf (card->txbuf, card->txbufsize);
  429. grub_error_pop ();
  430. goto fail_netbuf;
  431. }
  432. card->driver = NULL;
  433. card->data = ofdata;
  434. card->flags = 0;
  435. shortname = grub_ieee1275_get_devname (alias->path);
  436. card->name = grub_xasprintf ("ofnet_%s", shortname ? : alias->path);
  437. card->idle_poll_delay_ms = 10;
  438. grub_free (shortname);
  439. card->driver = &ofdriver;
  440. grub_net_card_register (card);
  441. return 0;
  442. fail_netbuf:
  443. grub_free (ofdata->path);
  444. grub_free (ofdata);
  445. grub_free (card);
  446. grub_print_error ();
  447. return 0;
  448. }
  449. static void
  450. grub_ofnet_findcards (void)
  451. {
  452. /* Look at all nodes for devices of the type network. */
  453. grub_ieee1275_devices_iterate (search_net_devices);
  454. }
  455. GRUB_MOD_INIT(ofnet)
  456. {
  457. grub_ofnet_findcards ();
  458. grub_ieee1275_net_config = grub_ieee1275_net_config_real;
  459. }
  460. GRUB_MOD_FINI(ofnet)
  461. {
  462. struct grub_net_card *card, *next;
  463. FOR_NET_CARDS_SAFE (card, next)
  464. if (card->driver && grub_strcmp (card->driver->name, "ofnet") == 0)
  465. grub_net_card_unregister (card);
  466. grub_ieee1275_net_config = 0;
  467. }