1 // Copyright 2016 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <efi/protocol/simple-network.h>
6 
7 #include <inttypes.h>
8 #include <stdio.h>
9 #include <string.h>
10 
11 #include <xefi.h>
12 
13 #include "inet6.h"
14 #include "netifc.h"
15 #include "osboot.h"
16 
17 static efi_simple_network_protocol* snp;
18 
19 #define MAX_FILTER 8
20 static efi_mac_addr mcast_filters[MAX_FILTER];
21 static unsigned mcast_filter_count = 0;
22 
23 // if nonzero, drop 1 in DROP_PACKETS packets at random
24 #define DROP_PACKETS 0
25 
26 #if DROP_PACKETS > 0
27 
28 //TODO: use libc random() once it's actually random
29 
30 // Xorshift32 prng
31 typedef struct {
32     uint32_t n;
33 } rand32_t;
34 
rand32(rand32_t * state)35 static inline uint32_t rand32(rand32_t* state) {
36     uint32_t n = state->n;
37     n ^= (n << 13);
38     n ^= (n >> 17);
39     n ^= (n << 5);
40     return (state->n = n);
41 }
42 
43 rand32_t rstate = {.n = 0x8716253};
44 #define random() rand32(&rstate)
45 
46 static int txc;
47 static int rxc;
48 #endif
49 
50 #define NUM_BUFFER_PAGES 8
51 #define ETH_BUFFER_SIZE 1516
52 #define ETH_HEADER_SIZE 16
53 #define ETH_BUFFER_MAGIC 0x424201020304A7A7UL
54 
55 typedef struct eth_buffer_t eth_buffer;
56 struct eth_buffer_t {
57     uint64_t magic;
58     eth_buffer* next;
59     uint8_t data[0];
60 };
61 
62 static efi_physical_addr eth_buffers_base = 0;
63 static eth_buffer* eth_buffers = NULL;
64 static int num_eth_buffers = 0;
65 static int eth_buffers_avail = 0;
66 
eth_get_buffer(size_t sz)67 void* eth_get_buffer(size_t sz) {
68     eth_buffer* buf;
69     if (sz > ETH_BUFFER_SIZE) {
70         return NULL;
71     }
72     if (eth_buffers == NULL) {
73         return NULL;
74     }
75     buf = eth_buffers;
76     eth_buffers = buf->next;
77     buf->next = NULL;
78     eth_buffers_avail--;
79     return buf->data;
80 }
81 
eth_put_buffer(void * data)82 void eth_put_buffer(void* data) {
83     efi_physical_addr buf_paddr = (efi_physical_addr)data;
84     if ((buf_paddr < eth_buffers_base)
85         || (buf_paddr >= (eth_buffers_base + (NUM_BUFFER_PAGES * PAGE_SIZE)))) {
86         printf("fatal: attempt to use buffer outside of allocated range\n");
87         for (;;)
88             ;
89     }
90 
91     eth_buffer* buf = (void*)(buf_paddr & (~2047));
92     if (buf->magic != ETH_BUFFER_MAGIC) {
93         printf("fatal: eth buffer %p (from %p) bad magic %" PRIx64 "\n",
94                buf, data, buf->magic);
95         for (;;)
96             ;
97     }
98 
99     buf->next = eth_buffers;
100     eth_buffers_avail++;
101     eth_buffers = buf;
102 }
103 
eth_send(void * data,size_t len)104 int eth_send(void* data, size_t len) {
105 #if DROP_PACKETS
106     txc++;
107     if ((random() % DROP_PACKETS) == 0) {
108         printf("tx drop %d\n", txc);
109         eth_put_buffer(data);
110         return 0;
111     }
112 #endif
113     efi_status r;
114     if ((r = snp->Transmit(snp, 0, len, (void*)data, NULL, NULL, NULL))) {
115         eth_put_buffer(data);
116         return -1;
117     } else {
118         return 0;
119     }
120 }
121 
eth_dump_status(void)122 void eth_dump_status(void) {
123 #ifdef VERBOSE
124     printf("State/HwAdSz/HdrSz/MaxSz %d %d %d %d\n",
125            snp->Mode->State, snp->Mode->HwAddressSize,
126            snp->Mode->MediaHeaderSize, snp->Mode->MaxPacketSize);
127     printf("RcvMask/RcvCfg/MaxMcast/NumMcast %d %d %d %d\n",
128            snp->Mode->ReceiveFilterMask, snp->Mode->ReceiveFilterSetting,
129            snp->Mode->MaxMCastFilterCount, snp->Mode->MCastFilterCount);
130     uint8_t* x = snp->Mode->CurrentAddress.addr;
131     printf("MacAddr %02x:%02x:%02x:%02x:%02x:%02x\n",
132            x[0], x[1], x[2], x[3], x[4], x[5]);
133     printf("SetMac/MultiTx/LinkDetect/Link %d %d %d %d\n",
134            snp->Mode->MacAddressChangeable, snp->Mode->MultipleTxSupported,
135            snp->Mode->MediaPresentSupported, snp->Mode->MediaPresent);
136 #endif
137 }
138 
eth_add_mcast_filter(const mac_addr * addr)139 int eth_add_mcast_filter(const mac_addr* addr) {
140     if (mcast_filter_count >= MAX_FILTER)
141         return -1;
142     if (mcast_filter_count >= snp->Mode->MaxMCastFilterCount)
143         return -1;
144     memcpy(mcast_filters + mcast_filter_count, addr, ETH_ADDR_LEN);
145     mcast_filter_count++;
146     return 0;
147 }
148 
149 static efi_event net_timer = NULL;
150 
151 #define TIMER_MS(n) (((uint64_t)(n)) * 10000UL)
152 
netifc_set_timer(uint32_t ms)153 void netifc_set_timer(uint32_t ms) {
154     if (net_timer == 0) {
155         return;
156     }
157     gBS->SetTimer(net_timer, TimerRelative, TIMER_MS(ms));
158 }
159 
netifc_timer_expired(void)160 int netifc_timer_expired(void) {
161     if (net_timer == 0) {
162         return 0;
163     }
164     if (gBS->CheckEvent(net_timer) == EFI_SUCCESS) {
165         return 1;
166     }
167     return 0;
168 }
169 
170 /* Search the available network interfaces via SimpleNetworkProtocol handles
171  * and find the first valid one with a Link detected */
netifc_find_available(void)172 efi_simple_network_protocol* netifc_find_available(void) {
173     efi_boot_services* bs = gSys->BootServices;
174     efi_status ret;
175     efi_simple_network_protocol* cur_snp = NULL;
176     efi_handle handles[32];
177     char16_t *paths[32];
178     size_t nic_cnt = 0;
179     size_t sz = sizeof(handles);
180     uint32_t last_parent = 0;
181     uint32_t int_sts;
182     void *tx_buf;
183 
184     /* Get the handles of all devices that provide SimpleNetworkProtocol interfaces */
185     ret = bs->LocateHandle(ByProtocol, &SimpleNetworkProtocol, NULL, &sz, handles);
186     if (ret != EFI_SUCCESS) {
187         printf("Failed to locate network interfaces (%s)\n", xefi_strerror(ret));
188         return NULL;
189     }
190 
191     nic_cnt = sz / sizeof(efi_handle);
192     for (size_t i = 0; i < nic_cnt; i++) {
193         paths[i] = xefi_handle_to_str(handles[i]);
194     }
195 
196     /* Iterate over our SNP list until we find one with an established link */
197     for (size_t i = 0; i < nic_cnt; i++) {
198          /* Check each interface once, but ignore any additional device paths a given interface
199           * may provide. e1000 tends to add a path for ipv4 and ipv6 configuration information
200           * for instance */
201         if (i != last_parent) {
202             if (memcmp(paths[i], paths[last_parent], strlen_16(paths[last_parent])) == 0) {
203                 continue;
204             } else {
205                 last_parent = i;
206             }
207         }
208 
209         puts16(paths[i]);
210         printf(": ");
211         ret = bs->HandleProtocol(handles[i], &SimpleNetworkProtocol, (void**)&cur_snp);
212         if (ret) {
213             printf("Failed to open (%s)\n", xefi_strerror(ret));
214             continue;
215         }
216 
217         /* If a driver is provided by the firmware then it should be started already, but check
218          * to make sure. This also covers the case where we're providing the AX88772 driver in-line
219          * during this boot itself */
220         ret = cur_snp->Start(cur_snp);
221         if (EFI_ERROR(ret) && ret != EFI_ALREADY_STARTED) {
222             printf("Failed to start (%s)", xefi_strerror(ret));
223             goto link_fail;
224         }
225 
226         if (ret != EFI_ALREADY_STARTED) {
227             ret = cur_snp->Initialize(cur_snp, 0, 0);
228             if (EFI_ERROR(ret)) {
229                 printf("Failed to initialize (%s)\n", xefi_strerror(ret));
230                 goto link_fail;
231             }
232         }
233 
234         /* Prod the driver to cache its current status. We don't need the status or buffer,
235          * but some drivers appear to require the OPTIONAL parameters. */
236         ret = cur_snp->GetStatus(cur_snp, &int_sts, &tx_buf);
237         if (EFI_ERROR(ret)) {
238             printf("Failed to read status (%s)\n", xefi_strerror(ret));
239             goto link_fail;
240         }
241 
242         /* With status cached, do we have a Link detected on the netifc? */
243         if (!cur_snp->Mode->MediaPresent) {
244             printf("No link detected\n");
245             goto link_fail;
246         }
247 
248         printf("Link detected!\n");
249         return cur_snp;
250 
251 link_fail:
252         bs->CloseProtocol(handles[i], &SimpleNetworkProtocol, gImg, NULL);
253         cur_snp = NULL;
254     }
255 
256     return NULL;
257 }
258 
netifc_open(void)259 int netifc_open(void) {
260     efi_boot_services* bs = gSys->BootServices;
261     efi_status ret;
262 
263     bs->CreateEvent(EVT_TIMER, TPL_CALLBACK, NULL, NULL, &net_timer);
264 
265     snp = netifc_find_available();
266     if (!snp) {
267         printf("Failed to find a usable network interface\n");
268         return -1;
269     }
270 
271     if (bs->AllocatePages(AllocateAnyPages, EfiLoaderData, NUM_BUFFER_PAGES, &eth_buffers_base)) {
272         printf("Failed to allocate net buffers\n");
273         return -1;
274     }
275 
276     num_eth_buffers = NUM_BUFFER_PAGES * 2;
277     uint8_t* ptr = (void*)eth_buffers_base;
278     for (int i = 0; i < num_eth_buffers; ++i) {
279         eth_buffer* buf = (void*)ptr;
280         buf->magic = ETH_BUFFER_MAGIC;
281         eth_put_buffer(buf);
282         ptr += 2048;
283     }
284 
285     ip6_init(snp->Mode->CurrentAddress.addr);
286 
287     ret = snp->ReceiveFilters(snp,
288                             EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |
289                                 EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST,
290                             0, 0, mcast_filter_count, (void*)mcast_filters);
291     if (ret) {
292         printf("Failed to install multicast filters %s\n", xefi_strerror(ret));
293         return -1;
294     }
295 
296     eth_dump_status();
297 
298     if (snp->Mode->MCastFilterCount != mcast_filter_count) {
299         printf("OOPS: expected %d filters, found %d\n",
300                mcast_filter_count, snp->Mode->MCastFilterCount);
301         goto force_promisc;
302     }
303     for (size_t i = 0; i < mcast_filter_count; i++) {
304         //uint8_t *m = (void*) &mcast_filters[i];
305         //printf("i=%d %02x %02x %02x %02x %02x %02x\n", i, m[0], m[1], m[2], m[3], m[4], m[5]);
306         for (size_t j = 0; j < mcast_filter_count; j++) {
307             //m = (void*) &snp->Mode->MCastFilter[j];
308             //printf("j=%d %02x %02x %02x %02x %02x %02x\n", j, m[0], m[1], m[2], m[3], m[4], m[5]);
309             if (!memcmp(mcast_filters + i, &snp->Mode->MCastFilter[j], 6)) {
310                 goto found_it;
311             }
312         }
313         printf("OOPS: filter #%zu missing\n", i);
314         goto force_promisc;
315     found_it:;
316     }
317 
318     return 0;
319 
320 force_promisc:
321     ret = snp->ReceiveFilters(snp,
322                             EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |
323                                 EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS |
324                                 EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST,
325                             0, 0, 0, NULL);
326     if (ret) {
327         printf("Failed to set promiscuous mode (%s)\n", xefi_strerror(ret));
328         return -1;
329     }
330     return 0;
331 }
332 
netifc_close(void)333 void netifc_close(void) {
334     gBS->SetTimer(net_timer, TimerCancel, 0);
335     gBS->CloseEvent(net_timer);
336     snp->Shutdown(snp);
337     snp->Stop(snp);
338 }
339 
netifc_active(void)340 int netifc_active(void) {
341     return (snp != 0);
342 }
343 
netifc_poll(void)344 void netifc_poll(void) {
345     uint8_t data[1514];
346     efi_status r;
347     size_t hsz, bsz;
348     uint32_t irq;
349     void* txdone;
350 
351     if (eth_buffers_avail < num_eth_buffers) {
352         // Only check for completion if we have operations in progress.
353         // Otherwise, the result of GetStatus is unreliable. See ZX-759.
354         if ((r = snp->GetStatus(snp, &irq, &txdone))) {
355             return;
356         }
357         if (txdone) {
358             // Check to make sure this is one of our buffers (see ZX-1516)
359             efi_physical_addr buf_paddr = (efi_physical_addr)txdone;
360             if ((buf_paddr >= eth_buffers_base)
361                 && (buf_paddr < (eth_buffers_base + (NUM_BUFFER_PAGES * PAGE_SIZE)))) {
362                 eth_put_buffer(txdone);
363             }
364         }
365     }
366 
367     hsz = 0;
368     bsz = sizeof(data);
369     r = snp->Receive(snp, &hsz, &bsz, data, NULL, NULL, NULL);
370     if (r != EFI_SUCCESS) {
371         return;
372     }
373 
374 #if DROP_PACKETS
375     rxc++;
376     if ((random() % DROP_PACKETS) == 0) {
377         printf("rx drop %d\n", rxc);
378         return;
379     }
380 #endif
381 
382 #if TRACE
383     printf("RX %02x:%02x:%02x:%02x:%02x:%02x < %02x:%02x:%02x:%02x:%02x:%02x %02x%02x %d\n",
384             data[0], data[1], data[2], data[3], data[4], data[5],
385             data[6], data[7], data[8], data[9], data[10], data[11],
386             data[12], data[13], (int)(bsz - hsz));
387 #endif
388     eth_recv(data, bsz);
389 }
390