2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2010,2011 Free Software Foundation, Inc.
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.
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.
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/>.
19 #include <grub/net/netbuff.h>
22 #include <grub/time.h>
23 #include <grub/efi/api.h>
24 #include <grub/efi/efi.h>
25 #include <grub/i18n.h>
27 GRUB_MOD_LICENSE ("GPLv3+");
30 static grub_efi_guid_t net_io_guid
= GRUB_EFI_SIMPLE_NETWORK_GUID
;
31 static grub_efi_guid_t pxe_io_guid
= GRUB_EFI_PXE_GUID
;
34 send_card_buffer (struct grub_net_card
*dev
,
35 struct grub_net_buff
*pack
)
38 grub_efi_simple_network_t
*net
= dev
->efi_net
;
39 grub_uint64_t limit_time
= grub_get_time_ms () + 4000;
46 st
= efi_call_3 (net
->get_status
, net
, 0, &txbuf
);
47 if (st
!= GRUB_EFI_SUCCESS
)
48 return grub_error (GRUB_ERR_IO
,
49 N_("couldn't send network packet"));
50 if (txbuf
== dev
->txbuf
)
55 if (limit_time
< grub_get_time_ms ())
56 return grub_error (GRUB_ERR_TIMEOUT
, N_("couldn't send network packet"));
59 len
= (pack
->tail
- pack
->data
);
63 grub_memcpy (dev
->txbuf
, pack
->data
, len
);
65 st
= efi_call_7 (net
->transmit
, net
, 0, len
,
66 dev
->txbuf
, NULL
, NULL
, NULL
);
67 if (st
!= GRUB_EFI_SUCCESS
)
68 return grub_error (GRUB_ERR_IO
, N_("couldn't send network packet"));
73 static struct grub_net_buff
*
74 get_card_packet (struct grub_net_card
*dev
)
76 grub_efi_simple_network_t
*net
= dev
->efi_net
;
79 grub_efi_uintn_t bufsize
= dev
->rcvbufsize
;
80 struct grub_net_buff
*nb
;
83 for (i
= 0; i
< 2; i
++)
86 dev
->rcvbuf
= grub_malloc (dev
->rcvbufsize
);
90 st
= efi_call_7 (net
->receive
, net
, NULL
, &bufsize
,
91 dev
->rcvbuf
, NULL
, NULL
, NULL
);
92 if (st
!= GRUB_EFI_BUFFER_TOO_SMALL
)
94 dev
->rcvbufsize
= 2 * ALIGN_UP (dev
->rcvbufsize
> bufsize
95 ? dev
->rcvbufsize
: bufsize
, 64);
96 grub_free (dev
->rcvbuf
);
100 if (st
!= GRUB_EFI_SUCCESS
)
103 nb
= grub_netbuff_alloc (bufsize
+ 2);
107 /* Reserve 2 bytes so that 2 + 14/18 bytes of ethernet header is divisible
108 by 4. So that IP header is aligned on 4 bytes. */
109 if (grub_netbuff_reserve (nb
, 2))
111 grub_netbuff_free (nb
);
114 grub_memcpy (nb
->data
, dev
->rcvbuf
, bufsize
);
115 err
= grub_netbuff_put (nb
, bufsize
);
118 grub_netbuff_free (nb
);
125 static struct grub_net_card_driver efidriver
=
128 .send
= send_card_buffer
,
129 .recv
= get_card_packet
133 grub_efinet_get_device_handle (struct grub_net_card
*card
)
135 if (!card
|| card
->driver
!= &efidriver
)
137 return card
->efi_handle
;
141 grub_efinet_findcards (void)
143 grub_efi_uintn_t num_handles
;
144 grub_efi_handle_t
*handles
;
145 grub_efi_handle_t
*handle
;
148 /* Find handles which support the disk io interface. */
149 handles
= grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL
, &net_io_guid
,
153 for (handle
= handles
; num_handles
--; handle
++)
155 grub_efi_simple_network_t
*net
;
156 struct grub_net_card
*card
;
158 net
= grub_efi_open_protocol (*handle
, &net_io_guid
,
159 GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
161 /* This should not happen... Why? */
164 if (net
->mode
->state
== GRUB_EFI_NETWORK_STOPPED
165 && efi_call_1 (net
->start
, net
) != GRUB_EFI_SUCCESS
)
168 if (net
->mode
->state
== GRUB_EFI_NETWORK_STOPPED
)
171 if (net
->mode
->state
== GRUB_EFI_NETWORK_STARTED
172 && efi_call_3 (net
->initialize
, net
, 0, 0) != GRUB_EFI_SUCCESS
)
175 card
= grub_zalloc (sizeof (struct grub_net_card
));
183 card
->mtu
= net
->mode
->max_packet_size
;
184 card
->txbufsize
= ALIGN_UP (card
->mtu
, 64) + 256;
185 card
->txbuf
= grub_zalloc (card
->txbufsize
);
195 card
->rcvbufsize
= ALIGN_UP (card
->mtu
, 64) + 256;
197 card
->name
= grub_xasprintf ("efinet%d", i
++);
198 card
->driver
= &efidriver
;
200 card
->default_address
.type
= GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET
;
201 grub_memcpy (card
->default_address
.mac
,
202 net
->mode
->current_address
,
203 sizeof (card
->default_address
.mac
));
205 card
->efi_handle
= *handle
;
207 grub_net_card_register (card
);
213 grub_efi_net_config_real (grub_efi_handle_t hnd
, char **device
,
216 struct grub_net_card
*card
;
217 grub_efi_device_path_t
*dp
;
219 dp
= grub_efi_get_device_path (hnd
);
225 grub_efi_device_path_t
*cdp
;
226 struct grub_efi_pxe
*pxe
;
227 struct grub_efi_pxe_mode
*pxe_mode
;
228 if (card
->driver
!= &efidriver
)
230 cdp
= grub_efi_get_device_path (card
->efi_handle
);
233 if (grub_efi_compare_device_paths (dp
, cdp
) != 0)
235 pxe
= grub_efi_open_protocol (hnd
, &pxe_io_guid
,
236 GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
239 pxe_mode
= pxe
->mode
;
240 grub_net_configure_by_dhcp_ack (card
->name
, card
, 0,
241 (struct grub_net_bootp_packet
*)
243 sizeof (pxe_mode
->dhcp_ack
),
249 GRUB_MOD_INIT(efinet
)
251 grub_efinet_findcards ();
252 grub_efi_net_config
= grub_efi_net_config_real
;
255 GRUB_MOD_FINI(efinet
)
257 struct grub_net_card
*card
, *next
;
259 FOR_NET_CARDS_SAFE (card
, next
)
260 if (card
->driver
== &efidriver
)
261 grub_net_card_unregister (card
);