iPXE
snpnet.c File Reference

SNP NIC driver. More...

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <ipxe/iobuf.h>
#include <ipxe/netdevice.h>
#include <ipxe/ethernet.h>
#include <ipxe/if_ether.h>
#include <ipxe/vsprintf.h>
#include <ipxe/timer.h>
#include <ipxe/efi/efi.h>
#include <ipxe/efi/Protocol/SimpleNetwork.h>
#include <ipxe/efi/efi_driver.h>
#include <ipxe/efi/efi_utils.h>
#include <ipxe/efi/efi_snp.h>
#include "snpnet.h"

Go to the source code of this file.

Data Structures

struct  snp_nic
 An SNP NIC. More...
struct  snp_insomniac_patch
 An SNP interface patch to inhibit shutdown for insomniac devices. More...

Macros

#define SNP_RX_QUOTA   4
 Maximum number of received packets per poll.
#define SNP_INITIALIZE_RETRY_MAX   10
 Maximum initialisation retry count.
#define SNP_INITIALIZE_RETRY_DELAY_MS   10
 Delay between each initialisation retry.
#define SNP_RX_PAD   8
 Additional padding for receive buffers.

Functions

 FILE_LICENCE (GPL2_OR_LATER)
 FILE_SECBOOT (PERMITTED)
static const char * snpnet_mac_text (EFI_MAC_ADDRESS *mac, size_t len)
 Format SNP MAC address (for debugging)
static void snpnet_dump_mode (struct net_device *netdev)
 Dump SNP mode information (for debugging)
static void snpnet_check_link (struct net_device *netdev)
 Check link state.
static int snpnet_transmit (struct net_device *netdev, struct io_buffer *iobuf)
 Transmit packet.
static void snpnet_poll_tx (struct net_device *netdev)
 Poll for completed packets.
static void snpnet_poll_rx (struct net_device *netdev)
 Poll for received packets.
static void snpnet_poll (struct net_device *netdev)
 Poll for completed packets.
static int snpnet_rx_filters (struct net_device *netdev)
 Set receive filters.
static int snpnet_open (struct net_device *netdev)
 Open network device.
static void snpnet_close (struct net_device *netdev)
 Close network device.
int snpnet_supported (EFI_HANDLE device, EFI_GUID *protocol, int inhibit_wifi)
 Check to see if driver supports a device.
static int snpnet_is_insomniac (EFI_HANDLE device)
 Check if device must be insomniac.
static EFI_STATUS EFIAPI snpnet_do_nothing (EFI_SIMPLE_NETWORK_PROTOCOL *snp __unused)
 Ignore shutdown attempt.
static int snpnet_insomniac_patch (EFI_HANDLE device, struct snp_insomniac_patch *patch)
 Patch SNP protocol interface to prevent shutdown.
static int snpnet_insomniac_restore (EFI_HANDLE device, struct snp_insomniac_patch *patch)
 Restore patched SNP protocol interface.
int snpnet_exclude (EFI_HANDLE device)
 Exclude existing drivers.
int snpnet_start (struct efi_device *efidev)
 Attach driver to device.
void snpnet_stop (struct efi_device *efidev)
 Detach driver from device.

Variables

static struct net_device_operations snpnet_operations
 SNP network device operations.

Detailed Description

SNP NIC driver.

Definition in file snpnet.c.

Macro Definition Documentation

◆ SNP_RX_QUOTA

#define SNP_RX_QUOTA   4

Maximum number of received packets per poll.

Definition at line 69 of file snpnet.c.

Referenced by snpnet_poll_rx().

◆ SNP_INITIALIZE_RETRY_MAX

#define SNP_INITIALIZE_RETRY_MAX   10

Maximum initialisation retry count.

Definition at line 72 of file snpnet.c.

Referenced by snpnet_open().

◆ SNP_INITIALIZE_RETRY_DELAY_MS

#define SNP_INITIALIZE_RETRY_DELAY_MS   10

Delay between each initialisation retry.

Definition at line 75 of file snpnet.c.

Referenced by snpnet_open().

◆ SNP_RX_PAD

#define SNP_RX_PAD   8

Additional padding for receive buffers.

Some SNP implementations seem to require additional space in the allocated receive buffers, otherwise full-length packets will be silently dropped.

The EDK2 MnpDxe driver happens to allocate an additional 8 bytes of padding (4 for a VLAN tag, 4 for the Ethernet frame checksum). Match this behaviour since drivers are very likely to have been tested against MnpDxe.

Definition at line 88 of file snpnet.c.

Referenced by snpnet_poll_rx().

Function Documentation

◆ FILE_LICENCE()

FILE_LICENCE ( GPL2_OR_LATER )

◆ FILE_SECBOOT()

FILE_SECBOOT ( PERMITTED )

◆ snpnet_mac_text()

const char * snpnet_mac_text ( EFI_MAC_ADDRESS * mac,
size_t len )
static

Format SNP MAC address (for debugging)

Parameters
macMAC address
lenLength of MAC address
Return values
textMAC address as text

Definition at line 105 of file snpnet.c.

105 {
106 static char buf[ sizeof ( *mac ) * 3 /* "xx:" or "xx\0" */ ];
107 size_t used = 0;
108 unsigned int i;
109
110 for ( i = 0 ; i < len ; i++ ) {
111 used += ssnprintf ( &buf[used], ( sizeof ( buf ) - used ),
112 "%s%02x", ( used ? ":" : "" ),
113 mac->Addr[i] );
114 }
115 return buf;
116}
ring len
Length.
Definition dwmac.h:226
uint8_t mac[ETH_ALEN]
MAC address.
Definition ena.h:13
int ssnprintf(char *buf, ssize_t ssize, const char *fmt,...)
Version of vsnprintf() that accepts a signed buffer size.
Definition vsprintf.c:421

References len, mac, and ssnprintf().

Referenced by snpnet_dump_mode().

◆ snpnet_dump_mode()

void snpnet_dump_mode ( struct net_device * netdev)
static

Dump SNP mode information (for debugging)

Parameters
netdevNetwork device

Definition at line 123 of file snpnet.c.

123 {
124 struct snp_nic *snp = netdev->priv;
126 size_t mac_len = mode->HwAddressSize;
127 unsigned int i;
128
129 /* Do nothing unless debugging is enabled */
130 if ( ! DBG_EXTRA )
131 return;
132
133 DBGC2 ( snp, "SNP %s st %d type %d hdr %d pkt %d rxflt %#x/%#x%s "
134 "nvram %d acc %d mcast %d/%d\n", netdev->name, mode->State,
135 mode->IfType, mode->MediaHeaderSize, mode->MaxPacketSize,
136 mode->ReceiveFilterSetting, mode->ReceiveFilterMask,
137 ( mode->MultipleTxSupported ? " multitx" : "" ),
138 mode->NvRamSize, mode->NvRamAccessSize,
139 mode->MCastFilterCount, mode->MaxMCastFilterCount );
140 DBGC2 ( snp, "SNP %s hw %s", netdev->name,
141 snpnet_mac_text ( &mode->PermanentAddress, mac_len ) );
142 DBGC2 ( snp, " addr %s%s",
143 snpnet_mac_text ( &mode->CurrentAddress, mac_len ),
144 ( mode->MacAddressChangeable ? "" : "(f)" ) );
145 DBGC2 ( snp, " bcast %s\n",
146 snpnet_mac_text ( &mode->BroadcastAddress, mac_len ) );
147 for ( i = 0 ; i < mode->MCastFilterCount ; i++ ) {
148 DBGC2 ( snp, "SNP %s mcast %s\n", netdev->name,
149 snpnet_mac_text ( &mode->MCastFilter[i], mac_len ) );
150 }
151 DBGC2 ( snp, "SNP %s media %s\n", netdev->name,
152 ( mode->MediaPresentSupported ?
153 ( mode->MediaPresent ? "present" : "not present" ) :
154 "presence not supported" ) );
155}
uint16_t mode
Acceleration mode.
Definition ena.h:15
static struct net_device * netdev
Definition gdbudp.c:53
#define DBGC2(...)
Definition compiler.h:522
#define DBG_EXTRA
Definition compiler.h:319
static const char * snpnet_mac_text(EFI_MAC_ADDRESS *mac, size_t len)
Format SNP MAC address (for debugging)
Definition snpnet.c:105
EFI_SIMPLE_NETWORK_MODE * Mode
Pointer to the EFI_SIMPLE_NETWORK_MODE data for the device.
An SNP NIC.
Definition snpnet.c:47
EFI_SIMPLE_NETWORK_PROTOCOL * snp
Simple network protocol.
Definition snpnet.c:51

References DBG_EXTRA, DBGC2, _EFI_SIMPLE_NETWORK_PROTOCOL::Mode, mode, netdev, snp_nic::snp, and snpnet_mac_text().

Referenced by snpnet_open().

◆ snpnet_check_link()

void snpnet_check_link ( struct net_device * netdev)
static

Check link state.

Parameters
netdevNetwork device

Definition at line 162 of file snpnet.c.

162 {
163 struct snp_nic *snp = netdev->priv;
165
166 /* Do nothing unless media presence detection is supported */
167 if ( ! mode->MediaPresentSupported )
168 return;
169
170 /* Report any link status change */
171 if ( mode->MediaPresent && ( ! netdev_link_ok ( netdev ) ) ) {
173 } else if ( ( ! mode->MediaPresent ) && netdev_link_ok ( netdev ) ) {
175 }
176}
void netdev_link_down(struct net_device *netdev)
Mark network device as having link down.
Definition netdevice.c:231
static int netdev_link_ok(struct net_device *netdev)
Check link state of network device.
Definition netdevice.h:640
static void netdev_link_up(struct net_device *netdev)
Mark network device as having link up.
Definition netdevice.h:789

References _EFI_SIMPLE_NETWORK_PROTOCOL::Mode, mode, netdev, netdev_link_down(), netdev_link_ok(), netdev_link_up(), and snp_nic::snp.

Referenced by snpnet_poll(), and snpnet_start().

◆ snpnet_transmit()

int snpnet_transmit ( struct net_device * netdev,
struct io_buffer * iobuf )
static

Transmit packet.

Parameters
netdevNetwork device
iobufI/O buffer
Return values
rcReturn status code

Definition at line 185 of file snpnet.c.

186 {
187 struct snp_nic *snp = netdev->priv;
188 EFI_STATUS efirc;
189 int rc;
190
191 /* Do nothing if shutdown is in progress */
193 return -ECANCELED;
194
195 /* Defer the packet if there is already a transmission in progress */
196 if ( snp->txbuf ) {
197 netdev_tx_defer ( netdev, iobuf );
198 return 0;
199 }
200
201 /* Pad to minimum Ethernet length, to work around underlying
202 * drivers that do not correctly handle frame padding
203 * themselves.
204 */
205 iob_pad ( iobuf, ETH_ZLEN );
206
207 /* Transmit packet */
208 if ( ( efirc = snp->snp->Transmit ( snp->snp, 0, iob_len ( iobuf ),
209 iobuf->data, NULL, NULL,
210 NULL ) ) != 0 ) {
211 rc = -EEFI ( efirc );
212 DBGC ( snp, "SNP %s could not transmit: %s\n",
213 netdev->name, strerror ( rc ) );
214 return rc;
215 }
216 snp->txbuf = iobuf;
217
218 return 0;
219}
#define NULL
NULL pointer (VOID *)
Definition Base.h:322
RETURN_STATUS EFI_STATUS
Function return status for EFI API.
struct arbelprm_rc_send_wqe rc
Definition arbel.h:3
int efi_shutdown_in_progress
EFI shutdown is in progress.
Definition efi_init.c:60
#define DBGC(...)
Definition compiler.h:505
#define ECANCELED
Operation canceled.
Definition errno.h:344
#define ETH_ZLEN
Definition if_ether.h:11
#define EEFI(efirc)
Convert an EFI status code to an iPXE status code.
Definition efi.h:175
void iob_pad(struct io_buffer *iobuf, size_t min_len)
Pad I/O buffer.
Definition iobpad.c:50
static size_t iob_len(struct io_buffer *iobuf)
Calculate length of data in an I/O buffer.
Definition iobuf.h:160
void netdev_tx_defer(struct net_device *netdev, struct io_buffer *iobuf)
Defer transmitted packet.
Definition netdevice.c:413
char * strerror(int errno)
Retrieve string representation of error number.
Definition strerror.c:79
EFI_SIMPLE_NETWORK_TRANSMIT Transmit
void * data
Start of data.
Definition iobuf.h:53

References io_buffer::data, DBGC, ECANCELED, EEFI, efi_shutdown_in_progress, ETH_ZLEN, iob_len(), iob_pad(), netdev, netdev_tx_defer(), NULL, rc, snp_nic::snp, strerror(), and _EFI_SIMPLE_NETWORK_PROTOCOL::Transmit.

◆ snpnet_poll_tx()

void snpnet_poll_tx ( struct net_device * netdev)
static

Poll for completed packets.

Parameters
netdevNetwork device

Definition at line 226 of file snpnet.c.

226 {
227 struct snp_nic *snp = netdev->priv;
228 struct io_buffer *iobuf;
229 UINT32 irq;
230 VOID *txbuf;
231 EFI_STATUS efirc;
232 int rc;
233
234 /* Get status */
235 txbuf = NULL;
236 if ( ( efirc = snp->snp->GetStatus ( snp->snp, &irq, &txbuf ) ) != 0 ) {
237 rc = -EEFI ( efirc );
238 DBGC ( snp, "SNP %s could not get status: %s\n",
239 netdev->name, strerror ( rc ) );
241 return;
242 }
243
244 /* Do nothing unless we have a completion */
245 if ( ! txbuf )
246 return;
247
248 /* Sanity check */
249 if ( ! snp->txbuf ) {
250 DBGC ( snp, "SNP %s reported spurious TX completion\n",
251 netdev->name );
253 return;
254 }
255
256 /* Complete transmission */
257 iobuf = snp->txbuf;
258 snp->txbuf = NULL;
259 netdev_tx_complete ( netdev, iobuf );
260}
unsigned int UINT32
4-byte unsigned value.
#define VOID
Undeclared type.
Definition Base.h:272
#define EPIPE
Broken pipe.
Definition errno.h:620
void netdev_tx_err(struct net_device *netdev, struct io_buffer *iobuf, int rc)
Discard transmitted packet.
Definition netdevice.c:441
void netdev_rx_err(struct net_device *netdev, struct io_buffer *iobuf, int rc)
Discard received packet.
Definition netdevice.c:587
static void netdev_tx_complete(struct net_device *netdev, struct io_buffer *iobuf)
Complete network transmission.
Definition netdevice.h:767
EFI_SIMPLE_NETWORK_GET_STATUS GetStatus
A persistent I/O buffer.
Definition iobuf.h:38
struct io_buffer * txbuf
Current transmit buffer.
Definition snpnet.c:63

References DBGC, EEFI, EPIPE, _EFI_SIMPLE_NETWORK_PROTOCOL::GetStatus, netdev, netdev_rx_err(), netdev_tx_complete(), netdev_tx_err(), NULL, rc, snp_nic::snp, strerror(), snp_nic::txbuf, and VOID.

Referenced by snpnet_poll().

◆ snpnet_poll_rx()

void snpnet_poll_rx ( struct net_device * netdev)
static

Poll for received packets.

Parameters
netdevNetwork device

Definition at line 267 of file snpnet.c.

267 {
268 struct snp_nic *snp = netdev->priv;
269 UINTN len;
270 unsigned int quota;
271 EFI_STATUS efirc;
272 int rc;
273
274 /* Retrieve up to SNP_RX_QUOTA packets */
275 for ( quota = SNP_RX_QUOTA ; quota ; quota-- ) {
276
277 /* Allocate buffer, if required */
278 if ( ! snp->rxbuf ) {
279 snp->rxbuf = alloc_iob ( snp->mtu + SNP_RX_PAD );
280 if ( ! snp->rxbuf ) {
281 /* Leave for next poll */
282 break;
283 }
284 }
285
286 /* Receive packet */
287 len = iob_tailroom ( snp->rxbuf );
288 if ( ( efirc = snp->snp->Receive ( snp->snp, NULL, &len,
289 snp->rxbuf->data, NULL,
290 NULL, NULL ) ) != 0 ) {
291
292 /* EFI_NOT_READY is just the usual "no packet"
293 * status indication; ignore it.
294 */
295 if ( efirc == EFI_NOT_READY )
296 break;
297
298 /* Anything else is an error */
299 rc = -EEFI ( efirc );
300 DBGC ( snp, "SNP %s could not receive: %s\n",
301 netdev->name, strerror ( rc ) );
303 break;
304 }
305
306 /* Hand off to network stack */
307 iob_put ( snp->rxbuf, len );
308 netdev_rx ( netdev, snp->rxbuf );
309 snp->rxbuf = NULL;
310 }
311}
UINT64 UINTN
Unsigned value of native width.
#define EFI_NOT_READY
Enumeration of EFI_STATUS.
struct io_buffer * alloc_iob(size_t len)
Allocate I/O buffer.
Definition iobuf.c:131
#define iob_put(iobuf, len)
Definition iobuf.h:125
static size_t iob_tailroom(struct io_buffer *iobuf)
Calculate available space at end of an I/O buffer.
Definition iobuf.h:180
void netdev_rx(struct net_device *netdev, struct io_buffer *iobuf)
Add packet to receive queue.
Definition netdevice.c:549
#define SNP_RX_QUOTA
Maximum number of received packets per poll.
Definition snpnet.c:69
#define SNP_RX_PAD
Additional padding for receive buffers.
Definition snpnet.c:88
EFI_SIMPLE_NETWORK_RECEIVE Receive

References alloc_iob(), DBGC, EEFI, EFI_NOT_READY, iob_put, iob_tailroom(), len, netdev, netdev_rx(), netdev_rx_err(), NULL, rc, _EFI_SIMPLE_NETWORK_PROTOCOL::Receive, snp_nic::snp, SNP_RX_PAD, SNP_RX_QUOTA, and strerror().

Referenced by snpnet_poll().

◆ snpnet_poll()

void snpnet_poll ( struct net_device * netdev)
static

Poll for completed packets.

Parameters
netdevNetwork device

Definition at line 318 of file snpnet.c.

318 {
319
320 /* Do nothing if shutdown is in progress */
322 return;
323
324 /* Process any TX completions */
326
327 /* Process any RX completions */
329
330 /* Check for link state changes */
332}
static void snpnet_check_link(struct net_device *netdev)
Check link state.
Definition snpnet.c:162
static void snpnet_poll_tx(struct net_device *netdev)
Poll for completed packets.
Definition snpnet.c:226
static void snpnet_poll_rx(struct net_device *netdev)
Poll for received packets.
Definition snpnet.c:267

References efi_shutdown_in_progress, netdev, snpnet_check_link(), snpnet_poll_rx(), and snpnet_poll_tx().

◆ snpnet_rx_filters()

int snpnet_rx_filters ( struct net_device * netdev)
static

Set receive filters.

Parameters
netdevNetwork device
Return values
rcReturn status code

Definition at line 340 of file snpnet.c.

340 {
341 struct snp_nic *snp = netdev->priv;
342 UINT32 filters[] = {
353 };
354 unsigned int i;
355 EFI_STATUS efirc;
356 int rc;
357
358 /* Try possible receive filters in turn */
359 for ( i = 0; i < ( sizeof ( filters ) / sizeof ( filters[0] ) ); i++ ) {
360 efirc = snp->snp->ReceiveFilters ( snp->snp, filters[i],
362 0, NULL );
363 if ( efirc == 0 )
364 return 0;
365 rc = -EEFI ( efirc );
366 DBGC ( snp, "SNP %s could not set receive filters %#02x (have "
367 "%#02x): %s\n", netdev->name, filters[i],
369 }
370
371 return rc;
372}
#define EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST
#define EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST
#define EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST
#define EFI_SIMPLE_NETWORK_RECEIVE_UNICAST
UINT32 ReceiveFilterMask
The multicast receive filter settings supported by the network interface.
UINT32 ReceiveFilterSetting
The current multicast receive filter settings.
EFI_SIMPLE_NETWORK_RECEIVE_FILTERS ReceiveFilters
#define TRUE
Definition tlan.h:46

References DBGC, EEFI, EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST, EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST, EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST, EFI_SIMPLE_NETWORK_RECEIVE_UNICAST, _EFI_SIMPLE_NETWORK_PROTOCOL::Mode, netdev, NULL, rc, EFI_SIMPLE_NETWORK_MODE::ReceiveFilterMask, _EFI_SIMPLE_NETWORK_PROTOCOL::ReceiveFilters, EFI_SIMPLE_NETWORK_MODE::ReceiveFilterSetting, snp_nic::snp, strerror(), and TRUE.

Referenced by snpnet_open().

◆ snpnet_open()

int snpnet_open ( struct net_device * netdev)
static

Open network device.

Parameters
netdevNetwork device
Return values
rcReturn status code

Definition at line 380 of file snpnet.c.

380 {
381 struct snp_nic *snp = netdev->priv;
382 EFI_MAC_ADDRESS *mac = ( ( void * ) netdev->ll_addr );
384 EFI_STATUS efirc;
385 unsigned int retry;
386 int rc;
387
388 /* Try setting MAC address (before initialising) */
389 if ( ( efirc = snp->snp->StationAddress ( snp->snp, FALSE, mac ) ) !=0){
390 rc = -EEFI ( efirc );
391 DBGC ( snp, "SNP %s could not set station address before "
392 "initialising: %s\n", netdev->name, strerror ( rc ) );
393 /* Ignore error */
394 }
395
396 /* Initialise NIC, retrying multiple times if link stays down */
397 for ( retry = 0 ; ; ) {
398
399 /* Initialise NIC, if not already initialised */
400 if ( ( mode->State != EfiSimpleNetworkInitialized ) &&
401 ( ( efirc = snp->snp->Initialize ( snp->snp,
402 0, 0 ) ) != 0 ) ) {
403 rc = -EEFI ( efirc );
405 DBGC ( snp, "SNP %s could not initialise: %s\n",
406 netdev->name, strerror ( rc ) );
407 return rc;
408 }
409
410 /* Stop if we have link up (or no link detection capability) */
411 if ( ( ! mode->MediaPresentSupported ) || mode->MediaPresent )
412 break;
413
414 /* Stop if we have exceeded our retry count. This is
415 * not a failure; it is plausible that we genuinely do
416 * not have link up.
417 */
418 if ( ++retry >= SNP_INITIALIZE_RETRY_MAX )
419 break;
420 DBGC ( snp, "SNP %s retrying initialisation (retry %d)\n",
421 netdev->name, retry );
422
423 /* Delay to allow time for link to establish */
425
426 /* Shut down and retry (unless device is insomniac);
427 * this is sometimes necessary in order to persuade
428 * the underlying SNP driver to actually update the
429 * link state.
430 */
431 if ( ( ! netdev_insomniac ( netdev ) ) &&
432 ( ( efirc = snp->snp->Shutdown ( snp->snp ) ) != 0 ) ) {
433 rc = -EEFI ( efirc );
435 DBGC ( snp, "SNP %s could not shut down: %s\n",
436 netdev->name, strerror ( rc ) );
437 return rc;
438 }
439 }
440
441 /* Try setting MAC address (after initialising) */
442 if ( ( efirc = snp->snp->StationAddress ( snp->snp, FALSE, mac ) ) !=0){
443 rc = -EEFI ( efirc );
444 DBGC ( snp, "SNP %s could not set station address after "
445 "initialising: %s\n", netdev->name, strerror ( rc ) );
446 /* Ignore error */
447 }
448
449 /* Set receive filters */
450 if ( ( rc = snpnet_rx_filters ( netdev ) ) != 0 ) {
451 /* Ignore error */
452 }
453
454 /* Dump mode information (for debugging) */
456
457 return 0;
458}
@ EfiSimpleNetworkInitialized
static int netdev_insomniac(struct net_device *netdev)
Check whether or not network device must be polled even while closed.
Definition netdevice.h:707
#define SNP_INITIALIZE_RETRY_DELAY_MS
Delay between each initialisation retry.
Definition snpnet.c:75
static void snpnet_dump_mode(struct net_device *netdev)
Dump SNP mode information (for debugging)
Definition snpnet.c:123
#define SNP_INITIALIZE_RETRY_MAX
Maximum initialisation retry count.
Definition snpnet.c:72
static int snpnet_rx_filters(struct net_device *netdev)
Set receive filters.
Definition snpnet.c:340
32-byte buffer containing a network Media Access Control address.
EFI_SIMPLE_NETWORK_INITIALIZE Initialize
EFI_SIMPLE_NETWORK_SHUTDOWN Shutdown
EFI_SIMPLE_NETWORK_STATION_ADDRESS StationAddress
void mdelay(unsigned long msecs)
Delay for a fixed number of milliseconds.
Definition timer.c:79
#define FALSE
Definition tlan.h:45

References DBGC, EEFI, EfiSimpleNetworkInitialized, FALSE, _EFI_SIMPLE_NETWORK_PROTOCOL::Initialize, mac, mdelay(), _EFI_SIMPLE_NETWORK_PROTOCOL::Mode, mode, netdev, netdev_insomniac(), rc, _EFI_SIMPLE_NETWORK_PROTOCOL::Shutdown, snp_nic::snp, SNP_INITIALIZE_RETRY_DELAY_MS, SNP_INITIALIZE_RETRY_MAX, snpnet_dump_mode(), snpnet_rx_filters(), _EFI_SIMPLE_NETWORK_PROTOCOL::StationAddress, and strerror().

◆ snpnet_close()

void snpnet_close ( struct net_device * netdev)
static

Close network device.

Parameters
netdevNetwork device

Definition at line 465 of file snpnet.c.

465 {
466 struct snp_nic *snp = netdev->priv;
467 EFI_STATUS efirc;
468 int rc;
469
470 /* Shut down NIC (unless whole system shutdown is in progress,
471 * or device is insomniac).
472 */
473 if ( ( ! efi_shutdown_in_progress ) &&
474 ( ! netdev_insomniac ( netdev ) ) &&
475 ( ( efirc = snp->snp->Shutdown ( snp->snp ) ) != 0 ) ) {
476 rc = -EEFI ( efirc );
477 DBGC ( snp, "SNP %s could not shut down: %s\n",
478 netdev->name, strerror ( rc ) );
479 /* Nothing we can do about this */
480 }
481
482 /* Discard transmit buffer, if applicable */
483 if ( snp->txbuf ) {
485 snp->txbuf = NULL;
486 }
487
488 /* Discard receive buffer, if applicable */
489 if ( snp->rxbuf ) {
490 free_iob ( snp->rxbuf );
491 snp->rxbuf = NULL;
492 }
493}
void free_iob(struct io_buffer *iobuf)
Free I/O buffer.
Definition iobuf.c:153
void netdev_tx_complete_err(struct net_device *netdev, struct io_buffer *iobuf, int rc)
Complete network transmission.
Definition netdevice.c:471

References DBGC, ECANCELED, EEFI, efi_shutdown_in_progress, free_iob(), netdev, netdev_insomniac(), netdev_tx_complete_err(), NULL, rc, _EFI_SIMPLE_NETWORK_PROTOCOL::Shutdown, snp_nic::snp, and strerror().

◆ snpnet_supported()

int snpnet_supported ( EFI_HANDLE device,
EFI_GUID * protocol,
int inhibit_wifi )

Check to see if driver supports a device.

Parameters
deviceEFI device handle
protocolProtocol GUID
inhibit_wifiInhibit wireless devices
Return values
rcReturn status code

Definition at line 511 of file snpnet.c.

512 {
513 EFI_HANDLE parent;
514 int rc;
515
516 /* Check that this is not a device we are providing ourselves */
517 if ( find_snpdev ( device ) != NULL ) {
518 DBGCP ( device, "HANDLE %s is provided by this binary\n",
520 return -ENOTTY;
521 }
522
523 /* Test for presence of protocol */
524 if ( ( rc = efi_test ( device, protocol ) ) != 0 ) {
525 DBGCP ( device, "HANDLE %s is not a %s device\n",
528 return rc;
529 }
530
531 /* Check that there are no instances of this protocol further
532 * up this device path.
533 */
535 &parent, 1 ) ) == 0 ) {
536 DBGC2 ( device, "HANDLE %s has %s-supporting parent ",
539 DBGC2 ( device, "%s\n", efi_handle_name ( parent ) );
540 return -ENOTTY;
541 }
542 DBGC ( device, "HANDLE %s is a %s device\n",
544
545 /* Check for wireless devices, if applicable */
546 if ( inhibit_wifi &&
547 ( ( efi_test ( device, &efi_wifi2_protocol_guid ) ) == 0 ) ) {
548 DBGC ( device, "HANDLE %s is wireless: assuming vendor %s "
549 "driver is too unreliable to use\n",
552 return -ENOTTY;
553 }
554
555 return 0;
556}
const char * efi_handle_name(EFI_HANDLE handle)
Get name of an EFI handle.
Definition efi_debug.c:652
const char * efi_guid_ntoa(CONST EFI_GUID *guid)
Convert GUID to a printable string.
Definition efi_guid.c:726
EFI_GUID efi_wifi2_protocol_guid
WiFi 2 protocol GUID.
Definition efi_guid.c:437
struct efi_snp_device * find_snpdev(EFI_HANDLE handle)
Find SNP device by EFI device handle.
Definition efi_snp.c:2104
int efi_locate_device(EFI_HANDLE device, EFI_GUID *protocol, EFI_HANDLE *parent, unsigned int skip)
Locate parent device supporting a given protocol.
Definition efi_utils.c:46
#define DBGCP(...)
Definition compiler.h:539
#define ENOTTY
Inappropriate I/O control operation.
Definition errno.h:595
#define EFI_HANDLE
Definition efi.h:53
#define efi_test(handle, protocol)
Test protocol existence.
Definition efi.h:433
uint16_t protocol
Protocol ID.
Definition stp.h:7
A hardware device.
Definition device.h:77

References DBGC, DBGC2, DBGCP, efi_guid_ntoa(), EFI_HANDLE, efi_handle_name(), efi_locate_device(), efi_test, efi_wifi2_protocol_guid, ENOTTY, find_snpdev(), NULL, protocol, and rc.

Referenced by mnp_supported(), nii_supported(), and snp_supported().

◆ snpnet_is_insomniac()

int snpnet_is_insomniac ( EFI_HANDLE device)
static

Check if device must be insomniac.

Parameters
deviceEFI device handle
is_insomniacDevice must be insomniac

Definition at line 564 of file snpnet.c.

564 {
565 int rc;
566
567 /* Check for wireless devices
568 *
569 * The UEFI model for wireless network configuration is
570 * somewhat underdefined. At the time of writing, the EDK2
571 * "UEFI WiFi Connection Manager" driver provides only one way
572 * to configure wireless network credentials, which is to
573 * enter them interactively via an HII form. Credentials are
574 * not stored (or exposed via any protocol interface), and so
575 * any temporary disconnection from the wireless network will
576 * inevitably leave the interface in an unusable state that
577 * cannot be recovered without user intervention.
578 *
579 * Experimentation shows that at least some wireless network
580 * drivers will disconnect from the wireless network when the
581 * SNP Shutdown() method is called, or if the device is not
582 * polled sufficiently frequently to maintain its association
583 * to the network. We therefore inhibit calls to Shutdown()
584 * and Stop() for any such SNP protocol interfaces, and mark
585 * our network device as insomniac so that it will be polled
586 * even when closed.
587 */
588 if ( ( rc = efi_test ( device, &efi_wifi2_protocol_guid ) ) == 0 ) {
589 DBGC ( device, "SNP %s is wireless: assuming insomniac\n",
591 return 1;
592 }
593
594 return 0;
595}

References DBGC, EFI_HANDLE, efi_handle_name(), efi_test, efi_wifi2_protocol_guid, and rc.

Referenced by snpnet_exclude(), and snpnet_start().

◆ snpnet_do_nothing()

EFI_STATUS EFIAPI snpnet_do_nothing ( EFI_SIMPLE_NETWORK_PROTOCOL *snp __unused)
static

Ignore shutdown attempt.

Parameters
snpSNP interface
Return values
efircEFI status code

Definition at line 604 of file snpnet.c.

604 {
605
606 return 0;
607}

References __unused.

Referenced by snpnet_insomniac_patch(), and snpnet_insomniac_restore().

◆ snpnet_insomniac_patch()

int snpnet_insomniac_patch ( EFI_HANDLE device,
struct snp_insomniac_patch * patch )
static

Patch SNP protocol interface to prevent shutdown.

Parameters
deviceEFI device handle
patchInterface patch
Return values
rcReturn status code

Definition at line 616 of file snpnet.c.

617 {
619 int rc;
620
621 /* Open interface for ephemeral use */
623 &interface ) ) != 0 ) {
624 DBGC ( device, "SNP %s cannot open SNP protocol for patching: "
625 "%s\n", efi_handle_name ( device ), strerror ( rc ) );
626 return rc;
627 }
628
629 /* Record original Shutdown() and Stop() methods */
630 patch->shutdown = interface->Shutdown;
631 patch->stop = interface->Stop;
632
633 /* Inhibit other UEFI drivers' calls to Shutdown() and Stop()
634 *
635 * This is necessary since disconnecting the MnpDxe driver
636 * will attempt to shut down the SNP device, which would leave
637 * us with an unusable device.
638 */
639 interface->Shutdown = snpnet_do_nothing;
641 DBGC ( device, "SNP %s patched to inhibit shutdown\n",
643
644 return 0;
645}
struct _EFI_SIMPLE_NETWORK_PROTOCOL EFI_SIMPLE_NETWORK_PROTOCOL
EFI_GUID efi_simple_network_protocol_guid
Simple network protocol GUID.
Definition efi_guid.c:341
#define efi_open(handle, protocol, interface)
Open protocol for ephemeral use.
Definition efi.h:444
static EFI_STATUS EFIAPI snpnet_do_nothing(EFI_SIMPLE_NETWORK_PROTOCOL *snp __unused)
Ignore shutdown attempt.
Definition snpnet.c:604
An object interface.
Definition interface.h:125
EFI_SIMPLE_NETWORK_SHUTDOWN shutdown
Original Shutdown() method.
Definition snpnet.c:93
EFI_SIMPLE_NETWORK_STOP stop
Original Stop() method.
Definition snpnet.c:95

References DBGC, EFI_HANDLE, efi_handle_name(), efi_open, efi_simple_network_protocol_guid, rc, snp_insomniac_patch::shutdown, snpnet_do_nothing(), snp_insomniac_patch::stop, and strerror().

Referenced by snpnet_exclude().

◆ snpnet_insomniac_restore()

int snpnet_insomniac_restore ( EFI_HANDLE device,
struct snp_insomniac_patch * patch )
static

Restore patched SNP protocol interface.

Parameters
deviceEFI device handle
patchInterface patch to fill in
Return values
rcReturn status code

Definition at line 654 of file snpnet.c.

655 {
657 int rc;
658
659 /* Avoid returning uninitialised data on error */
660 memset ( patch, 0, sizeof ( *patch ) );
661
662 /* Open interface for ephemeral use */
664 &interface ) ) != 0 ) {
665 DBGC ( device, "SNP %s cannot open patched SNP protocol: %s\n",
667 return rc;
668 }
669
670 /* Restore original Shutdown() and Stop() methods, if possible */
671 if ( interface->Shutdown == snpnet_do_nothing )
672 interface->Shutdown = patch->shutdown;
673 if ( interface->Stop == snpnet_do_nothing )
674 interface->Stop = patch->stop;
675
676 /* Check that original methods were restored (by us or others) */
677 if ( ( interface->Shutdown != patch->shutdown ) ||
678 ( interface->Stop != patch->stop ) ) {
679 DBGC ( device, "SNP %s could not restore patched SNP "
680 "protocol\n", efi_handle_name ( device ) );
681 return -EBUSY;
682 }
683
684 return 0;
685}
#define EBUSY
Device or resource busy.
Definition errno.h:339
void * memset(void *dest, int character, size_t len) __nonnull

References DBGC, EBUSY, EFI_HANDLE, efi_handle_name(), efi_open, efi_simple_network_protocol_guid, memset(), rc, snp_insomniac_patch::shutdown, snpnet_do_nothing(), snp_insomniac_patch::stop, and strerror().

Referenced by snpnet_exclude().

◆ snpnet_exclude()

int snpnet_exclude ( EFI_HANDLE device)

Exclude existing drivers.

Parameters
deviceEFI device handle
Return values
rcReturn status code

Definition at line 693 of file snpnet.c.

693 {
695 struct snp_insomniac_patch patch;
696 int insomniac;
697 int rc;
698
699 /* Check if this is a device that must not ever be shut down */
700 insomniac = snpnet_is_insomniac ( device );
701
702 /* Inhibit calls to Shutdown() and Stop(), if applicable */
703 if ( insomniac &&
704 ( ( rc = snpnet_insomniac_patch ( device, &patch ) ) != 0 ) ) {
705 goto err_patch;
706 }
707
708 /* Exclude existing SNP drivers */
709 if ( ( rc = efi_driver_exclude ( device, protocol ) ) != 0 ) {
710 DBGC ( device, "SNP %s could not exclude drivers: %s\n",
712 goto err_exclude;
713 }
714
715 err_exclude:
716 if ( insomniac )
718 err_patch:
719 return rc;
720}
GUID EFI_GUID
128-bit buffer containing a unique identifier value.
int efi_driver_exclude(EFI_HANDLE device, EFI_GUID *protocol)
Try to disconnect an existing EFI driver.
Definition efi_driver.c:438
static int snpnet_insomniac_restore(EFI_HANDLE device, struct snp_insomniac_patch *patch)
Restore patched SNP protocol interface.
Definition snpnet.c:654
static int snpnet_is_insomniac(EFI_HANDLE device)
Check if device must be insomniac.
Definition snpnet.c:564
static int snpnet_insomniac_patch(EFI_HANDLE device, struct snp_insomniac_patch *patch)
Patch SNP protocol interface to prevent shutdown.
Definition snpnet.c:616
An SNP interface patch to inhibit shutdown for insomniac devices.
Definition snpnet.c:91

References DBGC, efi_driver_exclude(), EFI_HANDLE, efi_handle_name(), efi_simple_network_protocol_guid, protocol, rc, snpnet_insomniac_patch(), snpnet_insomniac_restore(), snpnet_is_insomniac(), and strerror().

Referenced by __efi_driver().

◆ snpnet_start()

int snpnet_start ( struct efi_device * efidev)

Attach driver to device.

Parameters
efidevEFI device
Return values
rcReturn status code

Definition at line 728 of file snpnet.c.

728 {
729 EFI_HANDLE device = efidev->device;
732 struct net_device *netdev;
733 struct snp_nic *snp;
734 EFI_STATUS efirc;
735 int rc;
736
737 /* Open SNP protocol */
738 if ( ( rc = efi_open_by_driver ( device,
740 &interface ) ) != 0 ) {
741 DBGC ( device, "SNP %s cannot open SNP protocol: %s\n",
745 goto err_open_protocol;
746 }
747
748 /* Allocate and initialise structure */
749 netdev = alloc_etherdev ( sizeof ( *snp ) );
750 if ( ! netdev ) {
751 rc = -ENOMEM;
752 goto err_alloc;
753 }
755 snp = netdev->priv;
756 snp->efidev = efidev;
757 snp->snp = interface;
758 mode = snp->snp->Mode;
760
761 /* Populate underlying device information */
762 efi_device_info ( device, "SNP", &snp->dev );
763 snp->dev.driver_name = "SNP";
764 snp->dev.parent = &efidev->dev;
765 list_add ( &snp->dev.siblings, &efidev->dev.children );
766 INIT_LIST_HEAD ( &snp->dev.children );
767 netdev->dev = &snp->dev;
768
769 /* Check if device is insomniac */
770 if ( snpnet_is_insomniac ( device ) )
771 netdev->state |= NETDEV_INSOMNIAC;
772
773 /* Bring to the correct state for a closed interface */
774 if ( ( mode->State == EfiSimpleNetworkStopped ) &&
775 ( ( efirc = snp->snp->Start ( snp->snp ) ) != 0 ) ) {
776 rc = -EEFI ( efirc );
777 DBGC ( device, "SNP %s could not start: %s\n",
779 goto err_start;
780 }
781 if ( ( mode->State == EfiSimpleNetworkInitialized ) &&
782 ( ! netdev_insomniac ( netdev ) ) &&
783 ( ( efirc = snp->snp->Shutdown ( snp->snp ) ) != 0 ) ) {
784 rc = -EEFI ( efirc );
785 DBGC ( device, "SNP %s could not shut down: %s\n",
787 goto err_shutdown;
788 }
789
790 /* Populate network device parameters */
791 if ( mode->HwAddressSize != netdev->ll_protocol->hw_addr_len ) {
792 DBGC ( device, "SNP %s has invalid hardware address length "
793 "%d\n", efi_handle_name ( device ), mode->HwAddressSize);
794 rc = -ENOTSUP;
795 goto err_hw_addr_len;
796 }
797 memcpy ( netdev->hw_addr, &mode->PermanentAddress,
798 netdev->ll_protocol->hw_addr_len );
799 if ( mode->HwAddressSize != netdev->ll_protocol->ll_addr_len ) {
800 DBGC ( device, "SNP %s has invalid link-layer address length "
801 "%d\n", efi_handle_name ( device ), mode->HwAddressSize);
802 rc = -ENOTSUP;
803 goto err_ll_addr_len;
804 }
805 memcpy ( netdev->ll_addr, &mode->CurrentAddress,
806 netdev->ll_protocol->ll_addr_len );
807 snp->mtu = ( snp->snp->Mode->MaxPacketSize +
808 snp->snp->Mode->MediaHeaderSize );
809
810 /* Register network device */
811 if ( ( rc = register_netdev ( netdev ) ) != 0 )
812 goto err_register_netdev;
813 DBGC ( device, "SNP %s registered as %s\n",
814 efi_handle_name ( device ), netdev->name );
815
816 /* Set initial link state */
817 if ( snp->snp->Mode->MediaPresentSupported ) {
819 } else {
821 }
822
823 return 0;
824
826 err_register_netdev:
827 err_ll_addr_len:
828 err_hw_addr_len:
829 err_shutdown:
830 err_start:
831 list_del ( &snp->dev.siblings );
833 netdev_put ( netdev );
834 err_alloc:
836 err_open_protocol:
837 return rc;
838}
@ EfiSimpleNetworkStopped
static void efidev_set_drvdata(struct efi_device *efidev, void *priv)
Set EFI driver-private data.
Definition efi_driver.h:87
void efi_close_by_driver(EFI_HANDLE handle, EFI_GUID *protocol)
Close protocol opened for persistent use by a driver.
Definition efi_open.c:279
void efi_device_info(EFI_HANDLE device, const char *prefix, struct device *dev)
Get underlying device information.
Definition efi_utils.c:189
struct net_device * alloc_etherdev(size_t priv_size)
Allocate Ethernet device.
Definition ethernet.c:265
#define ENOMEM
Not enough space.
Definition errno.h:535
#define ENOTSUP
Operation not supported.
Definition errno.h:590
#define efi_open_by_driver(handle, protocol, interface)
Open protocol for persistent use by a driver.
Definition efi.h:474
#define DBGC_EFI_OPENERS(...)
Definition efi.h:345
void * memcpy(void *dest, const void *src, size_t len) __nonnull
#define list_del(list)
Delete an entry from a list.
Definition list.h:120
#define INIT_LIST_HEAD(list)
Initialise a list head.
Definition list.h:46
#define list_add(new, head)
Add a new entry to the head of a list.
Definition list.h:70
void unregister_netdev(struct net_device *netdev)
Unregister network device.
Definition netdevice.c:942
int register_netdev(struct net_device *netdev)
Register network device.
Definition netdevice.c:760
#define NETDEV_INSOMNIAC
Network device must be polled even when closed.
Definition netdevice.h:462
static void netdev_init(struct net_device *netdev, struct net_device_operations *op)
Initialise a network device.
Definition netdevice.h:519
static void netdev_nullify(struct net_device *netdev)
Stop using a network device.
Definition netdevice.h:532
static void netdev_put(struct net_device *netdev)
Drop reference to network device.
Definition netdevice.h:576
static struct net_device_operations snpnet_operations
SNP network device operations.
Definition snpnet.c:496
UINT32 MediaHeaderSize
The size, in bytes, of the network interface's media header.
BOOLEAN MediaPresentSupported
TRUE if the presence of media can be determined; otherwise FALSE.
UINT32 MaxPacketSize
The maximum size, in bytes, of the packets supported by the network interface.
EFI_SIMPLE_NETWORK_START Start
struct list_head children
Devices attached to this device.
Definition device.h:87
EFI_HANDLE device
EFI device handle.
Definition efi_driver.h:22
struct device dev
Generic device.
Definition efi_driver.h:20
A network device.
Definition netdevice.h:353
struct efi_device * efidev
EFI device.
Definition snpnet.c:49

References alloc_etherdev(), device::children, DBGC, DBGC_EFI_OPENERS, efi_device::dev, efi_device::device, EEFI, efi_close_by_driver(), efi_device_info(), EFI_HANDLE, efi_handle_name(), efi_open_by_driver, efi_simple_network_protocol_guid, snp_nic::efidev, efidev_set_drvdata(), EfiSimpleNetworkInitialized, EfiSimpleNetworkStopped, ENOMEM, ENOTSUP, INIT_LIST_HEAD, list_add, list_del, EFI_SIMPLE_NETWORK_MODE::MaxPacketSize, EFI_SIMPLE_NETWORK_MODE::MediaHeaderSize, EFI_SIMPLE_NETWORK_MODE::MediaPresentSupported, memcpy(), _EFI_SIMPLE_NETWORK_PROTOCOL::Mode, mode, netdev, netdev_init(), NETDEV_INSOMNIAC, netdev_insomniac(), netdev_link_up(), netdev_nullify(), netdev_put(), rc, register_netdev(), _EFI_SIMPLE_NETWORK_PROTOCOL::Shutdown, snp_nic::snp, snpnet_check_link(), snpnet_is_insomniac(), snpnet_operations, _EFI_SIMPLE_NETWORK_PROTOCOL::Start, strerror(), and unregister_netdev().

Referenced by __efi_driver().

◆ snpnet_stop()

void snpnet_stop ( struct efi_device * efidev)

Detach driver from device.

Parameters
efidevEFI device

Definition at line 845 of file snpnet.c.

845 {
846 struct net_device *netdev = efidev_get_drvdata ( efidev );
847 struct snp_nic *snp = netdev->priv;
849 EFI_STATUS efirc;
850 int rc;
851
852 /* Unregister network device */
854
855 /* Stop SNP protocol (unless whole system shutdown is in progress) */
856 if ( ( ! efi_shutdown_in_progress ) &&
857 ( ( efirc = snp->snp->Stop ( snp->snp ) ) != 0 ) ) {
858 rc = -EEFI ( efirc );
859 DBGC ( device, "SNP %s could not stop: %s\n",
861 /* Nothing we can do about this */
862 }
863
864 /* Free network device */
865 list_del ( &snp->dev.siblings );
867 netdev_put ( netdev );
868
869 /* Close SNP protocol */
871}
static void * efidev_get_drvdata(struct efi_device *efidev)
Get EFI driver-private data.
Definition efi_driver.h:98
EFI_SIMPLE_NETWORK_STOP Stop

References DBGC, efi_device::device, EEFI, efi_close_by_driver(), EFI_HANDLE, efi_handle_name(), efi_shutdown_in_progress, efi_simple_network_protocol_guid, snp_nic::efidev, efidev_get_drvdata(), list_del, netdev, netdev_nullify(), netdev_put(), rc, snp_nic::snp, _EFI_SIMPLE_NETWORK_PROTOCOL::Stop, strerror(), and unregister_netdev().

Referenced by __efi_driver().

Variable Documentation

◆ snpnet_operations

struct net_device_operations snpnet_operations
static
Initial value:
= {
.open = snpnet_open,
.close = snpnet_close,
.transmit = snpnet_transmit,
.poll = snpnet_poll,
}
static int snpnet_open(struct net_device *netdev)
Open network device.
Definition snpnet.c:380
static int snpnet_transmit(struct net_device *netdev, struct io_buffer *iobuf)
Transmit packet.
Definition snpnet.c:185
static void snpnet_poll(struct net_device *netdev)
Poll for completed packets.
Definition snpnet.c:318
static void snpnet_close(struct net_device *netdev)
Close network device.
Definition snpnet.c:465

SNP network device operations.

Definition at line 496 of file snpnet.c.

496 {
497 .open = snpnet_open,
498 .close = snpnet_close,
499 .transmit = snpnet_transmit,
500 .poll = snpnet_poll,
501};

Referenced by snpnet_start().