2 * Copyright (c) 2001 Doug Rabson
3 * Copyright (c) 2002, 2006 Marcel Moolenaar
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 #include <sys/cdefs.h>
30 #include <sys/param.h>
31 #include <net/ethernet.h>
32 #include <netinet/in.h>
33 #include <netinet/in_systm.h>
42 static EFI_GUID sn_guid
= EFI_SIMPLE_NETWORK_PROTOCOL
;
44 static void efinet_end(struct netif
*);
45 static ssize_t
efinet_get(struct iodesc
*, void **, time_t);
46 static void efinet_init(struct iodesc
*, void *);
47 static int efinet_match(struct netif
*, void *);
48 static int efinet_probe(struct netif
*, void *);
49 static ssize_t
efinet_put(struct iodesc
*, void *, size_t);
51 struct netif_driver efinetif
= {
52 .netif_bname
= "efinet",
53 .netif_match
= efinet_match
,
54 .netif_probe
= efinet_probe
,
55 .netif_init
= efinet_init
,
56 .netif_get
= efinet_get
,
57 .netif_put
= efinet_put
,
58 .netif_end
= efinet_end
,
65 dump_mode(EFI_SIMPLE_NETWORK_MODE
*mode
)
69 printf("State = %x\n", mode
->State
);
70 printf("HwAddressSize = %u\n", mode
->HwAddressSize
);
71 printf("MediaHeaderSize = %u\n", mode
->MediaHeaderSize
);
72 printf("MaxPacketSize = %u\n", mode
->MaxPacketSize
);
73 printf("NvRamSize = %u\n", mode
->NvRamSize
);
74 printf("NvRamAccessSize = %u\n", mode
->NvRamAccessSize
);
75 printf("ReceiveFilterMask = %x\n", mode
->ReceiveFilterMask
);
76 printf("ReceiveFilterSetting = %u\n", mode
->ReceiveFilterSetting
);
77 printf("MaxMCastFilterCount = %u\n", mode
->MaxMCastFilterCount
);
78 printf("MCastFilterCount = %u\n", mode
->MCastFilterCount
);
79 printf("MCastFilter = {");
80 for (i
= 0; i
< mode
->MCastFilterCount
; i
++)
81 printf(" %s", ether_sprintf(mode
->MCastFilter
[i
].Addr
));
83 printf("CurrentAddress = %s\n",
84 ether_sprintf(mode
->CurrentAddress
.Addr
));
85 printf("BroadcastAddress = %s\n",
86 ether_sprintf(mode
->BroadcastAddress
.Addr
));
87 printf("PermanentAddress = %s\n",
88 ether_sprintf(mode
->PermanentAddress
.Addr
));
89 printf("IfType = %u\n", mode
->IfType
);
90 printf("MacAddressChangeable = %d\n", mode
->MacAddressChangeable
);
91 printf("MultipleTxSupported = %d\n", mode
->MultipleTxSupported
);
92 printf("MediaPresentSupported = %d\n", mode
->MediaPresentSupported
);
93 printf("MediaPresent = %d\n", mode
->MediaPresent
);
98 efinet_match(struct netif
*nif
, void *machdep_hint
)
100 struct devdesc
*dev
= machdep_hint
;
102 if (dev
->d_unit
== nif
->nif_unit
)
108 efinet_probe(struct netif
*nif
, void *machdep_hint
)
115 efinet_put(struct iodesc
*desc
, void *pkt
, size_t len
)
117 struct netif
*nif
= desc
->io_netif
;
118 EFI_SIMPLE_NETWORK
*net
;
122 net
= nif
->nif_devdata
;
126 status
= net
->Transmit(net
, 0, len
, pkt
, NULL
, NULL
, NULL
);
127 if (status
!= EFI_SUCCESS
)
130 /* Wait for the buffer to be transmitted */
132 buf
= NULL
; /* XXX Is this needed? */
133 status
= net
->GetStatus(net
, NULL
, &buf
);
135 * XXX EFI1.1 and the E1000 card returns a different
136 * address than we gave. Sigh.
138 } while (status
== EFI_SUCCESS
&& buf
== NULL
);
140 /* XXX How do we deal with status != EFI_SUCCESS now? */
141 return ((status
== EFI_SUCCESS
) ? len
: -1);
145 efinet_get(struct iodesc
*desc
, void **pkt
, time_t timeout
)
147 struct netif
*nif
= desc
->io_netif
;
148 EFI_SIMPLE_NETWORK
*net
;
155 net
= nif
->nif_devdata
;
159 bufsz
= net
->Mode
->MaxPacketSize
+ ETHER_HDR_LEN
+ ETHER_CRC_LEN
;
160 buf
= malloc(bufsz
+ ETHER_ALIGN
);
163 ptr
= buf
+ ETHER_ALIGN
;
166 while ((getsecs() - t
) < timeout
) {
167 status
= net
->Receive(net
, NULL
, &bufsz
, ptr
, NULL
, NULL
, NULL
);
168 if (status
== EFI_SUCCESS
) {
170 ret
= (ssize_t
)bufsz
;
173 if (status
!= EFI_NOT_READY
)
183 efinet_init(struct iodesc
*desc
, void *machdep_hint
)
185 struct netif
*nif
= desc
->io_netif
;
186 EFI_SIMPLE_NETWORK
*net
;
191 if (nif
->nif_driver
->netif_ifs
[nif
->nif_unit
].dif_unit
< 0) {
192 printf("Invalid network interface %d\n", nif
->nif_unit
);
196 h
= nif
->nif_driver
->netif_ifs
[nif
->nif_unit
].dif_private
;
197 status
= BS
->HandleProtocol(h
, &sn_guid
, (VOID
**)&nif
->nif_devdata
);
198 if (status
!= EFI_SUCCESS
) {
199 printf("net%d: cannot fetch interface data (status=%lu)\n",
200 nif
->nif_unit
, EFI_ERROR_CODE(status
));
204 net
= nif
->nif_devdata
;
205 if (net
->Mode
->State
== EfiSimpleNetworkStopped
) {
206 status
= net
->Start(net
);
207 if (status
!= EFI_SUCCESS
) {
208 printf("net%d: cannot start interface (status=%lu)\n",
209 nif
->nif_unit
, EFI_ERROR_CODE(status
));
214 if (net
->Mode
->State
!= EfiSimpleNetworkInitialized
) {
215 status
= net
->Initialize(net
, 0, 0);
216 if (status
!= EFI_SUCCESS
) {
217 printf("net%d: cannot init. interface (status=%lu)\n",
218 nif
->nif_unit
, EFI_ERROR_CODE(status
));
223 mask
= EFI_SIMPLE_NETWORK_RECEIVE_UNICAST
|
224 EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST
;
226 status
= net
->ReceiveFilters(net
, mask
, 0, FALSE
, 0, NULL
);
227 if (status
!= EFI_SUCCESS
) {
228 printf("net%d: cannot set rx. filters (status=%lu)\n",
229 nif
->nif_unit
, EFI_ERROR_CODE(status
));
234 dump_mode(net
->Mode
);
237 bcopy(net
->Mode
->CurrentAddress
.Addr
, desc
->myea
, 6);
242 efinet_end(struct netif
*nif
)
244 EFI_SIMPLE_NETWORK
*net
= nif
->nif_devdata
;
252 static int efinet_dev_init(void);
253 static int efinet_dev_print(int);
255 struct devsw efinet_dev
= {
258 .dv_init
= efinet_dev_init
,
259 .dv_strategy
= NULL
, /* Will be set in efinet_dev_init */
260 .dv_open
= NULL
, /* Will be set in efinet_dev_init */
261 .dv_close
= NULL
, /* Will be set in efinet_dev_init */
263 .dv_print
= efinet_dev_print
,
270 struct netif_dif
*dif
;
271 struct netif_stats
*stats
;
272 EFI_DEVICE_PATH
*devpath
, *node
;
273 EFI_SIMPLE_NETWORK
*net
;
274 EFI_HANDLE
*handles
, *handles2
;
278 extern struct devsw netdev
;
282 status
= BS
->LocateHandle(ByProtocol
, &sn_guid
, NULL
, &sz
, NULL
);
283 if (status
== EFI_BUFFER_TOO_SMALL
) {
284 handles
= (EFI_HANDLE
*)malloc(sz
);
285 status
= BS
->LocateHandle(ByProtocol
, &sn_guid
, NULL
, &sz
,
287 if (EFI_ERROR(status
))
290 if (EFI_ERROR(status
))
291 return (efi_status_to_errno(status
));
292 handles2
= (EFI_HANDLE
*)malloc(sz
);
293 if (handles2
== NULL
) {
298 for (i
= 0; i
< sz
/ sizeof(EFI_HANDLE
); i
++) {
299 devpath
= efi_lookup_devpath(handles
[i
]);
302 if ((node
= efi_devpath_last_node(devpath
)) == NULL
)
305 if (DevicePathType(node
) != MESSAGING_DEVICE_PATH
||
306 DevicePathSubType(node
) != MSG_MAC_ADDR_DP
)
310 * Open the network device in exclusive mode. Without this
311 * we will be racing with the UEFI network stack. It will
312 * pull packets off the network leading to lost packets.
314 status
= BS
->OpenProtocol(handles
[i
], &sn_guid
, (void **)&net
,
315 IH
, NULL
, EFI_OPEN_PROTOCOL_EXCLUSIVE
);
316 if (status
!= EFI_SUCCESS
) {
317 printf("Unable to open network interface %d for "
318 "exclusive access: %lu\n", i
,
319 EFI_ERROR_CODE(status
));
322 handles2
[nifs
] = handles
[i
];
331 err
= efi_register_handles(&efinet_dev
, handles2
, NULL
, nifs
);
335 efinetif
.netif_ifs
= calloc(nifs
, sizeof(struct netif_dif
));
336 stats
= calloc(nifs
, sizeof(struct netif_stats
));
337 if (efinetif
.netif_ifs
== NULL
|| stats
== NULL
) {
338 free(efinetif
.netif_ifs
);
340 efinetif
.netif_ifs
= NULL
;
344 efinetif
.netif_nifs
= nifs
;
346 for (i
= 0; i
< nifs
; i
++) {
348 dif
= &efinetif
.netif_ifs
[i
];
351 dif
->dif_stats
= &stats
[i
];
352 dif
->dif_private
= handles2
[i
];
355 efinet_dev
.dv_open
= netdev
.dv_open
;
356 efinet_dev
.dv_close
= netdev
.dv_close
;
357 efinet_dev
.dv_strategy
= netdev
.dv_strategy
;
365 efinet_dev_print(int verbose
)
371 printf("%s devices:", efinet_dev
.dv_name
);
372 if ((ret
= pager_output("\n")) != 0)
375 for (unit
= 0, h
= efi_find_handle(&efinet_dev
, 0);
376 h
!= NULL
; h
= efi_find_handle(&efinet_dev
, ++unit
)) {
377 printf(" %s%d:", efinet_dev
.dv_name
, unit
);
379 text
= efi_devpath_name(efi_lookup_devpath(h
));
382 efi_free_devpath_name(text
);
385 if ((ret
= pager_output("\n")) != 0)