source: grub-pc/trunk/fuentes/.pc/efinet-open-Simple-Network-Protocol-exclusively.patch/grub-core/net/drivers/efi/efinet.c @ 22

Last change on this file since 22 was 22, checked in by mabarracus, 4 years ago

updated version and apply net.ifnames=0 into debian/rules

File size: 6.9 KB
Line 
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
19#include <grub/net/netbuff.h>
20#include <grub/dl.h>
21#include <grub/net.h>
22#include <grub/time.h>
23#include <grub/efi/api.h>
24#include <grub/efi/efi.h>
25#include <grub/i18n.h>
26
27GRUB_MOD_LICENSE ("GPLv3+");
28
29/* GUID.  */
30static grub_efi_guid_t net_io_guid = GRUB_EFI_SIMPLE_NETWORK_GUID;
31static grub_efi_guid_t pxe_io_guid = GRUB_EFI_PXE_GUID;
32
33static grub_err_t
34send_card_buffer (struct grub_net_card *dev,
35                  struct grub_net_buff *pack)
36{
37  grub_efi_status_t st;
38  grub_efi_simple_network_t *net = dev->efi_net;
39  grub_uint64_t limit_time = grub_get_time_ms () + 4000;
40
41  if (dev->txbusy)
42    while (1)
43      {
44        void *txbuf = NULL;
45        st = efi_call_3 (net->get_status, net, 0, &txbuf);
46        if (st != GRUB_EFI_SUCCESS)
47          return grub_error (GRUB_ERR_IO,
48                             N_("couldn't send network packet"));
49        if (txbuf == dev->txbuf)
50          {
51            dev->txbusy = 0;
52            break;
53          }
54        if (txbuf)
55          {
56            st = efi_call_7 (net->transmit, net, 0, dev->last_pkt_size,
57                             dev->txbuf, NULL, NULL, NULL);
58            if (st != GRUB_EFI_SUCCESS)
59              return grub_error (GRUB_ERR_IO,
60                                 N_("couldn't send network packet"));
61          }
62        if (limit_time < grub_get_time_ms ())
63          return grub_error (GRUB_ERR_TIMEOUT,
64                             N_("couldn't send network packet"));
65      }
66
67  dev->last_pkt_size = (pack->tail - pack->data);
68  if (dev->last_pkt_size > dev->mtu)
69    dev->last_pkt_size = dev->mtu;
70
71  grub_memcpy (dev->txbuf, pack->data, dev->last_pkt_size);
72
73  st = efi_call_7 (net->transmit, net, 0, dev->last_pkt_size,
74                   dev->txbuf, NULL, NULL, NULL);
75  if (st != GRUB_EFI_SUCCESS)
76    return grub_error (GRUB_ERR_IO, N_("couldn't send network packet"));
77  dev->txbusy = 1;
78  return GRUB_ERR_NONE;
79}
80
81static struct grub_net_buff *
82get_card_packet (struct grub_net_card *dev)
83{
84  grub_efi_simple_network_t *net = dev->efi_net;
85  grub_err_t err;
86  grub_efi_status_t st;
87  grub_efi_uintn_t bufsize = dev->rcvbufsize;
88  struct grub_net_buff *nb;
89  int i;
90
91  for (i = 0; i < 2; i++)
92    {
93      if (!dev->rcvbuf)
94        dev->rcvbuf = grub_malloc (dev->rcvbufsize);
95      if (!dev->rcvbuf)
96        return NULL;
97
98      st = efi_call_7 (net->receive, net, NULL, &bufsize,
99                       dev->rcvbuf, NULL, NULL, NULL);
100      if (st != GRUB_EFI_BUFFER_TOO_SMALL)
101        break;
102      dev->rcvbufsize = 2 * ALIGN_UP (dev->rcvbufsize > bufsize
103                                      ? dev->rcvbufsize : bufsize, 64);
104      grub_free (dev->rcvbuf);
105      dev->rcvbuf = 0;
106    }
107
108  if (st != GRUB_EFI_SUCCESS)
109    return NULL;
110
111  nb = grub_netbuff_alloc (bufsize + 2);
112  if (!nb)
113    return NULL;
114
115  /* Reserve 2 bytes so that 2 + 14/18 bytes of ethernet header is divisible
116     by 4. So that IP header is aligned on 4 bytes. */
117  if (grub_netbuff_reserve (nb, 2))
118    {
119      grub_netbuff_free (nb);
120      return NULL;
121    }
122  grub_memcpy (nb->data, dev->rcvbuf, bufsize);
123  err = grub_netbuff_put (nb, bufsize);
124  if (err)
125    {
126      grub_netbuff_free (nb);
127      return NULL;
128    }
129
130  return nb;
131}
132
133static struct grub_net_card_driver efidriver =
134  {
135    .name = "efinet",
136    .send = send_card_buffer,
137    .recv = get_card_packet
138  };
139
140grub_efi_handle_t
141grub_efinet_get_device_handle (struct grub_net_card *card)
142{
143  if (!card || card->driver != &efidriver)
144    return 0;
145  return card->efi_handle;
146}
147
148static void
149grub_efinet_findcards (void)
150{
151  grub_efi_uintn_t num_handles;
152  grub_efi_handle_t *handles;
153  grub_efi_handle_t *handle;
154  int i = 0;
155
156  /* Find handles which support the disk io interface.  */
157  handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &net_io_guid,
158                                    0, &num_handles);
159  if (! handles)
160    return;
161  for (handle = handles; num_handles--; handle++)
162    {
163      grub_efi_simple_network_t *net;
164      struct grub_net_card *card;
165
166      net = grub_efi_open_protocol (*handle, &net_io_guid,
167                                    GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
168      if (! net)
169        /* This should not happen... Why?  */
170        continue;
171
172      if (net->mode->state == GRUB_EFI_NETWORK_STOPPED
173          && efi_call_1 (net->start, net) != GRUB_EFI_SUCCESS)
174        continue;
175
176      if (net->mode->state == GRUB_EFI_NETWORK_STOPPED)
177        continue;
178
179      if (net->mode->state == GRUB_EFI_NETWORK_STARTED
180          && efi_call_3 (net->initialize, net, 0, 0) != GRUB_EFI_SUCCESS)
181        continue;
182
183      card = grub_zalloc (sizeof (struct grub_net_card));
184      if (!card)
185        {
186          grub_print_error ();
187          grub_free (handles);
188          return;
189        }
190
191      card->mtu = net->mode->max_packet_size;
192      card->txbufsize = ALIGN_UP (card->mtu, 64) + 256;
193      card->txbuf = grub_zalloc (card->txbufsize);
194      if (!card->txbuf)
195        {
196          grub_print_error ();
197          grub_free (handles);
198          grub_free (card);
199          return;
200        }
201      card->txbusy = 0;
202
203      card->rcvbufsize = ALIGN_UP (card->mtu, 64) + 256;
204
205      card->name = grub_xasprintf ("efinet%d", i++);
206      card->driver = &efidriver;
207      card->flags = 0;
208      card->default_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
209      grub_memcpy (card->default_address.mac,
210                   net->mode->current_address,
211                   sizeof (card->default_address.mac));
212      card->efi_net = net;
213      card->efi_handle = *handle;
214
215      grub_net_card_register (card);
216    }
217  grub_free (handles);
218}
219
220static void
221grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
222                          char **path)
223{
224  struct grub_net_card *card;
225  grub_efi_device_path_t *dp;
226
227  dp = grub_efi_get_device_path (hnd);
228  if (! dp)
229    return;
230
231  FOR_NET_CARDS (card)
232  {
233    grub_efi_device_path_t *cdp;
234    struct grub_efi_pxe *pxe;
235    struct grub_efi_pxe_mode *pxe_mode;
236    if (card->driver != &efidriver)
237      continue;
238    cdp = grub_efi_get_device_path (card->efi_handle);
239    if (! cdp)
240      continue;
241    if (grub_efi_compare_device_paths (dp, cdp) != 0)
242      continue;
243    pxe = grub_efi_open_protocol (hnd, &pxe_io_guid,
244                                  GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
245    if (! pxe)
246      continue;
247    pxe_mode = pxe->mode;
248    grub_net_configure_by_dhcp_ack (card->name, card, 0,
249                                    (struct grub_net_bootp_packet *)
250                                    &pxe_mode->dhcp_ack,
251                                    sizeof (pxe_mode->dhcp_ack),
252                                    1, device, path);
253    return;
254  }
255}
256
257GRUB_MOD_INIT(efinet)
258{
259  grub_efinet_findcards ();
260  grub_efi_net_config = grub_efi_net_config_real;
261}
262
263GRUB_MOD_FINI(efinet)
264{
265  struct grub_net_card *card, *next;
266
267  FOR_NET_CARDS_SAFE (card, next) 
268    if (card->driver == &efidriver)
269      grub_net_card_unregister (card);
270}
271
Note: See TracBrowser for help on using the repository browser.