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
27 * $FreeBSD: head/sys/boot/efi/libefi/efinet.c 295210 2016-02-03 14:34:25Z andrew $
30 #include <sys/param.h>
31 #include <netinet/in.h>
32 #include <netinet/in_systm.h>
44 static EFI_GUID sn_guid
= EFI_SIMPLE_NETWORK_PROTOCOL_GUID
;
46 static void efinet_end(struct netif
*);
47 static int efinet_get(struct iodesc
*, void *, size_t, time_t);
48 static void efinet_init(struct iodesc
*, void *);
49 static int efinet_match(struct netif
*, void *);
50 static int efinet_probe(struct netif
*, void *);
51 static int efinet_put(struct iodesc
*, void *, size_t);
53 struct netif_driver efinetif
= {
54 .netif_bname
= "efinet",
55 .netif_match
= efinet_match
,
56 .netif_probe
= efinet_probe
,
57 .netif_init
= efinet_init
,
58 .netif_get
= efinet_get
,
59 .netif_put
= efinet_put
,
60 .netif_end
= efinet_end
,
67 dump_mode(EFI_SIMPLE_NETWORK_MODE
*mode
)
71 printf("State = %x\n", mode
->State
);
72 printf("HwAddressSize = %u\n", mode
->HwAddressSize
);
73 printf("MediaHeaderSize = %u\n", mode
->MediaHeaderSize
);
74 printf("MaxPacketSize = %u\n", mode
->MaxPacketSize
);
75 printf("NvRamSize = %u\n", mode
->NvRamSize
);
76 printf("NvRamAccessSize = %u\n", mode
->NvRamAccessSize
);
77 printf("ReceiveFilterMask = %x\n", mode
->ReceiveFilterMask
);
78 printf("ReceiveFilterSetting = %u\n", mode
->ReceiveFilterSetting
);
79 printf("MaxMCastFilterCount = %u\n", mode
->MaxMCastFilterCount
);
80 printf("MCastFilterCount = %u\n", mode
->MCastFilterCount
);
81 printf("MCastFilter = {");
82 for (i
= 0; i
< mode
->MCastFilterCount
; i
++)
83 printf(" %s", ether_sprintf(mode
->MCastFilter
[i
].Addr
));
85 printf("CurrentAddress = %s\n",
86 ether_sprintf(mode
->CurrentAddress
.Addr
));
87 printf("BroadcastAddress = %s\n",
88 ether_sprintf(mode
->BroadcastAddress
.Addr
));
89 printf("PermanentAddress = %s\n",
90 ether_sprintf(mode
->PermanentAddress
.Addr
));
91 printf("IfType = %u\n", mode
->IfType
);
92 printf("MacAddressChangeable = %d\n", mode
->MacAddressChangeable
);
93 printf("MultipleTxSupported = %d\n", mode
->MultipleTxSupported
);
94 printf("MediaPresentSupported = %d\n", mode
->MediaPresentSupported
);
95 printf("MediaPresent = %d\n", mode
->MediaPresent
);
100 efinet_match(struct netif
*nif
, void *machdep_hint
)
102 struct efi_devdesc
*dev
= machdep_hint
;
104 if (dev
->d_kind
.efidisk
.unit
- 1 == nif
->nif_unit
)
110 efinet_probe(struct netif
*nif
, void *machdep_hint
)
117 efinet_put(struct iodesc
*desc
, void *pkt
, size_t len
)
119 struct netif
*nif
= desc
->io_netif
;
120 EFI_SIMPLE_NETWORK
*net
;
124 net
= nif
->nif_devdata
;
126 status
= net
->Transmit(net
, 0, len
, pkt
, 0, 0, 0);
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
, 0, &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
, size_t len
, time_t timeout
)
147 struct netif
*nif
= desc
->io_netif
;
148 EFI_SIMPLE_NETWORK
*net
;
154 net
= nif
->nif_devdata
;
157 while ((time(0) - t
) < timeout
) {
159 status
= net
->Receive(net
, 0, &bufsz
, buf
, 0, 0, 0);
160 if (status
== EFI_SUCCESS
) {
162 * XXX EFI1.1 and the E1000 card trash our
163 * workspace if we do not do this silly copy.
164 * Either they are not respecting the len
165 * value or do not like the alignment.
169 bcopy(buf
, pkt
, bufsz
);
172 if (status
!= EFI_NOT_READY
)
180 efinet_init(struct iodesc
*desc
, void *machdep_hint
)
182 struct netif
*nif
= desc
->io_netif
;
183 EFI_SIMPLE_NETWORK
*net
;
187 if (nif
->nif_driver
->netif_ifs
[nif
->nif_unit
].dif_unit
< 0) {
188 printf("Invalid network interface %d\n", nif
->nif_unit
);
192 h
= nif
->nif_driver
->netif_ifs
[nif
->nif_unit
].dif_private
;
193 status
= OpenProtocolByHandle(h
, &sn_guid
, (VOID
**)&nif
->nif_devdata
);
194 if (status
!= EFI_SUCCESS
) {
195 printf("net%d: cannot start interface (status=%llu)\n",
196 nif
->nif_unit
, status
);
200 net
= nif
->nif_devdata
;
201 if (net
->Mode
->State
== EfiSimpleNetworkStopped
) {
202 status
= net
->Start(net
);
203 if (status
!= EFI_SUCCESS
) {
204 printf("net%d: cannot start interface (status=%llu)\n",
205 nif
->nif_unit
, status
);
210 if (net
->Mode
->State
!= EfiSimpleNetworkInitialized
) {
211 status
= net
->Initialize(net
, 0, 0);
212 if (status
!= EFI_SUCCESS
) {
213 printf("net%d: cannot init. interface (status=%llu)\n",
214 nif
->nif_unit
, status
);
219 if (net
->Mode
->ReceiveFilterSetting
== 0) {
220 UINT32 mask
= EFI_SIMPLE_NETWORK_RECEIVE_UNICAST
|
221 EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST
;
223 status
= net
->ReceiveFilters(net
, mask
, 0, FALSE
, 0, 0);
224 if (status
!= EFI_SUCCESS
) {
225 printf("net%d: cannot set rx. filters (status=%llu)\n",
226 nif
->nif_unit
, status
);
232 dump_mode(net
->Mode
);
235 bcopy(net
->Mode
->CurrentAddress
.Addr
, desc
->myea
, 6);
240 efinet_end(struct netif
*nif
)
242 EFI_SIMPLE_NETWORK
*net
= nif
->nif_devdata
;
247 static int efinet_dev_init(void);
248 static void efinet_dev_print(int);
250 struct devsw efinet_dev
= {
253 .dv_init
= efinet_dev_init
,
254 .dv_strategy
= net_strategy
,
256 .dv_close
= net_close
,
258 .dv_print
= efinet_dev_print
,
263 efinet_dev_init(void)
265 struct netif_dif
*dif
;
266 struct netif_stats
*stats
;
274 status
= BS
->LocateHandle(ByProtocol
, &sn_guid
, 0, &sz
, 0);
275 if (status
== EFI_BUFFER_TOO_SMALL
) {
276 handles
= (EFI_HANDLE
*)malloc(sz
);
277 status
= BS
->LocateHandle(ByProtocol
, &sn_guid
, 0, &sz
,
279 if (EFI_ERROR(status
))
282 if (EFI_ERROR(status
))
283 return (efi_status_to_errno(status
));
284 nifs
= sz
/ sizeof(EFI_HANDLE
);
285 err
= efi_register_handles(&efinet_dev
, handles
, NULL
, nifs
);
290 efinetif
.netif_nifs
= nifs
;
291 efinetif
.netif_ifs
= calloc(nifs
, sizeof(struct netif_dif
));
293 stats
= calloc(nifs
, sizeof(struct netif_stats
));
295 for (i
= 0; i
< nifs
; i
++) {
296 EFI_SIMPLE_NETWORK
*net
;
299 dif
= &efinetif
.netif_ifs
[i
];
302 h
= efi_find_handle(&efinet_dev
, i
);
305 * Open the network device in exclusive mode. Without this
306 * we will be racing with the UEFI network stack. It will
307 * pull packets off the network leading to lost packets.
309 status
= BS
->OpenProtocol(h
, &sn_guid
, (void **)&net
,
310 IH
, 0, EFI_OPEN_PROTOCOL_EXCLUSIVE
);
311 if (status
!= EFI_SUCCESS
) {
312 printf("Unable to open network interface %d for "
313 "exclusive access\n", i
);
318 dif
->dif_stats
= &stats
[i
];
319 dif
->dif_private
= h
;
326 efinet_dev_print(int verbose
)
332 for (unit
= 0, h
= efi_find_handle(&efinet_dev
, 0);
333 h
!= NULL
; h
= efi_find_handle(&efinet_dev
, ++unit
)) {
334 sprintf(line
, " %s%d:\n", efinet_dev
.dv_name
, unit
);