source: grub-pc/trunk/fuentes/.pc/efinet-enable-hardware-filters-on-interface.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: 10.2 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 grub_err_t
134open_card (struct grub_net_card *dev)
135{
136  grub_efi_simple_network_t *net;
137
138  /* Try to reopen SNP exlusively to close any active MNP protocol instance
139     that may compete for packet polling
140   */
141  net = grub_efi_open_protocol (dev->efi_handle, &net_io_guid,
142                                GRUB_EFI_OPEN_PROTOCOL_BY_EXCLUSIVE);
143  if (net)
144    {
145      if (net->mode->state == GRUB_EFI_NETWORK_STOPPED
146          && efi_call_1 (net->start, net) != GRUB_EFI_SUCCESS)
147        return grub_error (GRUB_ERR_NET_NO_CARD, "%s: net start failed",
148                           dev->name);
149
150      if (net->mode->state == GRUB_EFI_NETWORK_STOPPED)
151        return grub_error (GRUB_ERR_NET_NO_CARD, "%s: card stopped",
152                           dev->name);
153
154      if (net->mode->state == GRUB_EFI_NETWORK_STARTED
155          && efi_call_3 (net->initialize, net, 0, 0) != GRUB_EFI_SUCCESS)
156        return grub_error (GRUB_ERR_NET_NO_CARD, "%s: net initialize failed",
157                           dev->name);
158
159      efi_call_4 (grub_efi_system_table->boot_services->close_protocol,
160                  dev->efi_net, &net_io_guid,
161                  grub_efi_image_handle, dev->efi_handle);
162      dev->efi_net = net;
163    }
164
165  /* If it failed we just try to run as best as we can */
166  return GRUB_ERR_NONE;
167}
168
169static void
170close_card (struct grub_net_card *dev)
171{
172  efi_call_4 (grub_efi_system_table->boot_services->close_protocol,
173              dev->efi_net, &net_io_guid,
174              grub_efi_image_handle, dev->efi_handle);
175}
176
177static struct grub_net_card_driver efidriver =
178  {
179    .name = "efinet",
180    .open = open_card,
181    .close = close_card,
182    .send = send_card_buffer,
183    .recv = get_card_packet
184  };
185
186grub_efi_handle_t
187grub_efinet_get_device_handle (struct grub_net_card *card)
188{
189  if (!card || card->driver != &efidriver)
190    return 0;
191  return card->efi_handle;
192}
193
194static void
195grub_efinet_findcards (void)
196{
197  grub_efi_uintn_t num_handles;
198  grub_efi_handle_t *handles;
199  grub_efi_handle_t *handle;
200  int i = 0;
201
202  /* Find handles which support the disk io interface.  */
203  handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &net_io_guid,
204                                    0, &num_handles);
205  if (! handles)
206    return;
207  for (handle = handles; num_handles--; handle++)
208    {
209      grub_efi_simple_network_t *net;
210      struct grub_net_card *card;
211      grub_efi_device_path_t *dp, *parent = NULL, *child = NULL;
212
213      /* EDK2 UEFI PXE driver creates IPv4 and IPv6 messaging devices as
214         children of main MAC messaging device. We only need one device with
215         bound SNP per physical card, otherwise they compete with each other
216         when polling for incoming packets.
217       */
218      dp = grub_efi_get_device_path (*handle);
219      if (!dp)
220        continue;
221      for (; ! GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp); dp = GRUB_EFI_NEXT_DEVICE_PATH (dp))
222        {
223          parent = child;
224          child = dp;
225        }
226      if (child
227          && GRUB_EFI_DEVICE_PATH_TYPE (child) == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
228          && (GRUB_EFI_DEVICE_PATH_SUBTYPE (child) == GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE
229              || GRUB_EFI_DEVICE_PATH_SUBTYPE (child) == GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE)
230          && parent
231          && GRUB_EFI_DEVICE_PATH_TYPE (parent) == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
232          && GRUB_EFI_DEVICE_PATH_SUBTYPE (parent) == GRUB_EFI_MAC_ADDRESS_DEVICE_PATH_SUBTYPE)
233        continue;
234
235      net = grub_efi_open_protocol (*handle, &net_io_guid,
236                                    GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
237      if (! net)
238        /* This should not happen... Why?  */
239        continue;
240
241      if (net->mode->state == GRUB_EFI_NETWORK_STOPPED
242          && efi_call_1 (net->start, net) != GRUB_EFI_SUCCESS)
243        continue;
244
245      if (net->mode->state == GRUB_EFI_NETWORK_STOPPED)
246        continue;
247
248      if (net->mode->state == GRUB_EFI_NETWORK_STARTED
249          && efi_call_3 (net->initialize, net, 0, 0) != GRUB_EFI_SUCCESS)
250        continue;
251
252      card = grub_zalloc (sizeof (struct grub_net_card));
253      if (!card)
254        {
255          grub_print_error ();
256          grub_free (handles);
257          return;
258        }
259
260      card->mtu = net->mode->max_packet_size;
261      card->txbufsize = ALIGN_UP (card->mtu, 64) + 256;
262      card->txbuf = grub_zalloc (card->txbufsize);
263      if (!card->txbuf)
264        {
265          grub_print_error ();
266          grub_free (handles);
267          grub_free (card);
268          return;
269        }
270      card->txbusy = 0;
271
272      card->rcvbufsize = ALIGN_UP (card->mtu, 64) + 256;
273
274      card->name = grub_xasprintf ("efinet%d", i++);
275      card->driver = &efidriver;
276      card->flags = 0;
277      card->default_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
278      grub_memcpy (card->default_address.mac,
279                   net->mode->current_address,
280                   sizeof (card->default_address.mac));
281      card->efi_net = net;
282      card->efi_handle = *handle;
283
284      grub_net_card_register (card);
285    }
286  grub_free (handles);
287}
288
289static void
290grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
291                          char **path)
292{
293  struct grub_net_card *card;
294  grub_efi_device_path_t *dp;
295
296  dp = grub_efi_get_device_path (hnd);
297  if (! dp)
298    return;
299
300  FOR_NET_CARDS (card)
301  {
302    grub_efi_device_path_t *cdp;
303    struct grub_efi_pxe *pxe;
304    struct grub_efi_pxe_mode *pxe_mode;
305    if (card->driver != &efidriver)
306      continue;
307    cdp = grub_efi_get_device_path (card->efi_handle);
308    if (! cdp)
309      continue;
310    if (grub_efi_compare_device_paths (dp, cdp) != 0)
311      {
312        grub_efi_device_path_t *ldp, *dup_dp, *dup_ldp;
313        int match;
314
315        /* EDK2 UEFI PXE driver creates pseudo devices with type IPv4/IPv6
316           as children of Ethernet card and binds PXE and Load File protocols
317           to it. Loaded Image Device Path protocol will point to these pseudo
318           devices. We skip them when enumerating cards, so here we need to
319           find matching MAC device.
320         */
321        ldp = grub_efi_find_last_device_path (dp);
322        if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
323            || (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE
324                && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE))
325          continue;
326        dup_dp = grub_efi_duplicate_device_path (dp);
327        if (!dup_dp)
328          continue;
329        dup_ldp = grub_efi_find_last_device_path (dup_dp);
330        dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
331        dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
332        dup_ldp->length = sizeof (*dup_ldp);
333        match = grub_efi_compare_device_paths (dup_dp, cdp) == 0;
334        grub_free (dup_dp);
335        if (!match)
336          continue;
337      }
338    pxe = grub_efi_open_protocol (hnd, &pxe_io_guid,
339                                  GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
340    if (! pxe)
341      continue;
342    pxe_mode = pxe->mode;
343    grub_net_configure_by_dhcp_ack (card->name, card, 0,
344                                    (struct grub_net_bootp_packet *)
345                                    &pxe_mode->dhcp_ack,
346                                    sizeof (pxe_mode->dhcp_ack),
347                                    1, device, path);
348    return;
349  }
350}
351
352GRUB_MOD_INIT(efinet)
353{
354  grub_efinet_findcards ();
355  grub_efi_net_config = grub_efi_net_config_real;
356}
357
358GRUB_MOD_FINI(efinet)
359{
360  struct grub_net_card *card, *next;
361
362  FOR_NET_CARDS_SAFE (card, next) 
363    if (card->driver == &efidriver)
364      grub_net_card_unregister (card);
365}
366
Note: See TracBrowser for help on using the repository browser.