1 // Copyright 2017 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 <ddk/protocol/ethernet.h>
6 #include <fbl/algorithm.h>
7 #include <fbl/auto_call.h>
8 #include <fbl/intrusive_single_list.h>
9 #include <fbl/unique_ptr.h>
10 #include <fbl/vector.h>
11 #include <fuchsia/hardware/ethernet/c/fidl.h>
12 #include <lib/fdio/util.h>
13 #include <lib/fdio/watcher.h>
14 #include <lib/fzl/fdio.h>
15 #include <lib/fzl/fifo.h>
16 #include <lib/zx/channel.h>
17 #include <lib/zx/socket.h>
18 #include <lib/zx/time.h>
19 #include <lib/zx/vmar.h>
20 #include <lib/zx/vmo.h>
21 #include <unittest/unittest.h>
22 #include <zircon/compiler.h>
23 #include <zircon/device/device.h>
24 #include <zircon/device/ethertap.h>
25 #include <zircon/status.h>
26 #include <zircon/types.h>
27 
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <inttypes.h>
31 #include <stdint.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <unistd.h>
36 
37 #include <utility>
38 
39 // Delay for data to work through the system. The test will pause this long, so it's best
40 // to keep it fairly short. If it's too short, the test will occasionally be flaky,
41 // especially on qemu.
42 static constexpr zx::duration kPropagateDuration = zx::msec(200);
43 #define PROPAGATE_TIME (zx::deadline_after(kPropagateDuration))
44 
45 // We expect something to happen prior to timeout, and the test will fail if it doesn't. So
46 // wait longer to further reduce the likelihood of test flakiness.
47 #define FAIL_TIMEOUT (zx::deadline_after(kPropagateDuration * 50))
48 
49 // Because of test flakiness if a previous test case's ethertap device isn't cleaned up, we put a
50 // delay at the end of each test to give devmgr time to clean up the ethertap devices.
51 #define ETHTEST_CLEANUP_DELAY zx::nanosleep(PROPAGATE_TIME)
52 
53 namespace {
54 
55 const char kEthernetDir[] = "/dev/class/ethernet";
56 const char kTapctl[] = "/dev/misc/tapctl";
57 const uint8_t kTapMac[] = { 0x12, 0x20, 0x30, 0x40, 0x50, 0x60 };
58 
mxstrerror(zx_status_t status)59 const char* mxstrerror(zx_status_t status) {
60     return zx_status_get_string(status);
61 }
62 
CreateEthertapWithOption(uint32_t mtu,const char * name,zx::socket * sock,uint32_t options)63 zx_status_t CreateEthertapWithOption(uint32_t mtu, const char* name, zx::socket* sock,
64                                      uint32_t options) {
65     if (sock == nullptr) {
66         return ZX_ERR_INVALID_ARGS;
67     }
68 
69     fbl::unique_fd ctlfd(open(kTapctl, O_RDONLY));
70     if (!ctlfd.is_valid()) {
71         fprintf(stderr, "could not open %s: %s\n", kTapctl, strerror(errno));
72         return ZX_ERR_IO;
73     }
74 
75     ethertap_ioctl_config_t config = {};
76     strlcpy(config.name, name, ETHERTAP_MAX_NAME_LEN);
77     config.options = options;
78     // Uncomment this to trace ETHERTAP events
79     //config.options |= ETHERTAP_OPT_TRACE;
80     config.mtu = mtu;
81     memcpy(config.mac, kTapMac, 6);
82     ssize_t rc = ioctl_ethertap_config(ctlfd.get(), &config, sock->reset_and_get_address());
83     if (rc < 0) {
84         zx_status_t status = static_cast<zx_status_t>(rc);
85         fprintf(stderr, "could not configure ethertap device: %s\n", mxstrerror(status));
86         return status;
87     }
88     return ZX_OK;
89 }
90 
CreateEthertap(uint32_t mtu,const char * name,zx::socket * sock)91 zx_status_t CreateEthertap(uint32_t mtu, const char* name, zx::socket* sock) {
92     return CreateEthertapWithOption(mtu, name, sock, 0);
93 }
94 
WatchCb(int dirfd,int event,const char * fn,void * cookie)95 zx_status_t WatchCb(int dirfd, int event, const char* fn, void* cookie) {
96     if (event != WATCH_EVENT_ADD_FILE) return ZX_OK;
97     if (!strcmp(fn, ".") || !strcmp(fn, "..")) return ZX_OK;
98 
99     zx::channel svc;
100     {
101         int devfd = openat(dirfd, fn, O_RDONLY);
102         if (devfd < 0) {
103             return ZX_OK;
104         }
105 
106         zx_status_t status = fdio_get_service_handle(devfd, svc.reset_and_get_address());
107         if (status != ZX_OK) {
108             return status;
109         }
110     }
111 
112     // See if this device is our ethertap device
113     fuchsia_hardware_ethernet_Info info;
114     zx_status_t status = fuchsia_hardware_ethernet_DeviceGetInfo(svc.get(), &info);
115     if (status != ZX_OK) {
116         fprintf(stderr, "could not get ethernet info for %s/%s: %s\n", kEthernetDir, fn,
117                 mxstrerror(status));
118         // Return ZX_OK to keep watching for devices.
119         return ZX_OK;
120     }
121     if (!(info.features & fuchsia_hardware_ethernet_INFO_FEATURE_SYNTH)) {
122         // Not a match, keep looking.
123         return ZX_OK;
124     }
125 
126     // Found it!
127     // TODO(tkilbourn): this might not be the test device we created; need a robust way of getting
128     // the name of the tap device to check. Note that ioctl_device_get_device_name just returns
129     // "ethernet" since that's the child of the tap device that we've opened here.
130     auto svcp = reinterpret_cast<zx_handle_t*>(cookie);
131     *svcp = svc.release();
132     return ZX_ERR_STOP;
133 }
134 
OpenEthertapDev(zx::channel * svc)135 zx_status_t OpenEthertapDev(zx::channel* svc) {
136     if (svc == nullptr) {
137         return ZX_ERR_INVALID_ARGS;
138     }
139 
140     int ethdir = open(kEthernetDir, O_RDONLY);
141     if (ethdir < 0) {
142         fprintf(stderr, "could not open %s: %s\n", kEthernetDir, strerror(errno));
143         return ZX_ERR_IO;
144     }
145 
146     zx_status_t status;
147     status = fdio_watch_directory(ethdir, WatchCb, zx_deadline_after(ZX_SEC(2)),
148                                   reinterpret_cast<void*>(svc->reset_and_get_address()));
149     if (status == ZX_ERR_STOP) {
150         return ZX_OK;
151     } else {
152         return status;
153     }
154 }
155 
156 struct FifoEntry : public fbl::SinglyLinkedListable<fbl::unique_ptr<FifoEntry>> {
157     fuchsia_hardware_ethernet_FifoEntry e;
158 };
159 
160 struct EthernetOpenInfo {
EthernetOpenInfo__anonc51515c10111::EthernetOpenInfo161     EthernetOpenInfo(const char* name) : name(name) {}
162     // Special setup until we have IGMP: turn off multicast-promisc in init.
163     bool multicast = false;
164     const char* name;
165     bool online = true;
166     uint32_t options = 0;
167 };
168 
169 class EthernetClient {
170 public:
EthernetClient()171     EthernetClient() {}
~EthernetClient()172     ~EthernetClient() {
173         Cleanup();
174     }
175 
Cleanup()176     void Cleanup() {
177         if (mapped_ > 0) {
178             zx::vmar::root_self()->unmap(mapped_, vmo_size_);
179         }
180         svc_.reset();
181     }
182 
Register(zx::channel svc,const char * name,uint32_t nbufs,uint16_t bufsize)183     zx_status_t Register(zx::channel svc, const char* name, uint32_t nbufs, uint16_t bufsize) {
184         svc_ = std::move(svc);
185         zx_status_t call_status = ZX_OK;
186         size_t name_len =
187             fbl::min<size_t>(strlen(name), fuchsia_hardware_ethernet_MAX_CLIENT_NAME_LEN);
188         zx_status_t status =
189             fuchsia_hardware_ethernet_DeviceSetClientName(svc_.get(), name, name_len, &call_status);
190         if (status != ZX_OK || call_status != ZX_OK) {
191             fprintf(stderr, "could not set client name to %s: %d, %d\n", name, status, call_status);
192             return status == ZX_OK ? call_status : status;
193         }
194 
195         fuchsia_hardware_ethernet_Fifos fifos;
196         status = fuchsia_hardware_ethernet_DeviceGetFifos(svc_.get(), &call_status, &fifos);
197         if (status != ZX_OK || call_status != ZX_OK) {
198             fprintf(stderr, "could not get fifos: %d, %d\n", status, call_status);
199             return status == ZX_OK ? call_status : status;
200         }
201 
202         tx_.reset(fifos.tx);
203         rx_.reset(fifos.rx);
204         tx_depth_ = fifos.tx_depth;
205         rx_depth_ = fifos.rx_depth;
206 
207         nbufs_ = nbufs;
208         bufsize_ = bufsize;
209 
210         vmo_size_ = 2 * nbufs_ * bufsize_;
211         status = zx::vmo::create(vmo_size_, ZX_VMO_NON_RESIZABLE, &buf_);
212         if (status != ZX_OK) {
213             fprintf(stderr, "could not create a vmo of size %" PRIu64 ": %s\n", vmo_size_,
214                     mxstrerror(status));
215             return status;
216         }
217 
218         status = zx::vmar::root_self()->map(0, buf_, 0, vmo_size_,
219                                             ZX_VM_PERM_READ | ZX_VM_PERM_WRITE,
220                                             &mapped_);
221         if (status != ZX_OK) {
222             fprintf(stderr, "failed to map vmo: %s\n", mxstrerror(status));
223             return status;
224         }
225 
226         zx::vmo buf_copy;
227         status = buf_.duplicate(ZX_RIGHT_SAME_RIGHTS, &buf_copy);
228         if (status != ZX_OK) {
229             fprintf(stderr, "failed to duplicate vmo: %s\n", mxstrerror(status));
230             return status;
231         }
232 
233         zx_handle_t bufh = buf_copy.release();
234         status = fuchsia_hardware_ethernet_DeviceSetIOBuffer(svc_.get(), bufh, &call_status);
235         if (status != ZX_OK || call_status != ZX_OK) {
236             fprintf(stderr, "failed to set eth iobuf: %d, %d\n", status, call_status);
237             return status == ZX_OK ? call_status : status;
238         }
239 
240         uint32_t idx = 0;
241         for (; idx < nbufs; idx++) {
242             fuchsia_hardware_ethernet_FifoEntry entry = {
243                 .offset = idx * bufsize_,
244                 .length = bufsize_,
245                 .flags = 0,
246                 .cookie = 0,
247             };
248             status = rx_.write_one(entry);
249             if (status != ZX_OK) {
250                 fprintf(stderr, "failed call to write(): %s\n", mxstrerror(status));
251                 return status;
252             }
253         }
254 
255         for (; idx < 2 * nbufs; idx++) {
256             auto entry = fbl::unique_ptr<FifoEntry>(new FifoEntry);
257             entry->e.offset = idx * bufsize_;
258             entry->e.length = bufsize_;
259             entry->e.flags = 0;
260             entry->e.cookie = reinterpret_cast<uintptr_t>(mapped_) + entry->e.offset;
261             tx_available_.push_front(std::move(entry));
262         }
263 
264         return ZX_OK;
265     }
266 
Start()267     zx_status_t Start() {
268         zx_status_t call_status = ZX_OK;
269         zx_status_t status = fuchsia_hardware_ethernet_DeviceStart(svc_.get(), &call_status);
270         if (status != ZX_OK) {
271             return status;
272         }
273         return call_status;
274     }
275 
Stop()276     zx_status_t Stop() { return fuchsia_hardware_ethernet_DeviceStop(svc_.get()); }
277 
GetStatus(uint32_t * eth_status)278     zx_status_t GetStatus(uint32_t* eth_status) {
279         return fuchsia_hardware_ethernet_DeviceGetStatus(svc_.get(), eth_status);
280     }
281 
SetPromisc(bool on)282     zx_status_t SetPromisc(bool on) {
283         zx_status_t call_status = ZX_OK;
284         zx_status_t status =
285             fuchsia_hardware_ethernet_DeviceSetPromiscuousMode(svc_.get(), on, &call_status);
286         if (status != ZX_OK) {
287             return status;
288         }
289         return call_status;
290     }
291 
SetMulticastPromisc(bool on)292     zx_status_t SetMulticastPromisc(bool on) {
293         zx_status_t call_status, status;
294         status = fuchsia_hardware_ethernet_DeviceConfigMulticastSetPromiscuousMode(svc_.get(), on,
295                                                                                    &call_status);
296         if (status != ZX_OK) {
297             return status;
298         }
299         return call_status;
300     }
301 
MulticastAddressAdd(uint8_t * mac_addr)302     zx_status_t MulticastAddressAdd(uint8_t* mac_addr) {
303         fuchsia_hardware_ethernet_MacAddress mac;
304         memcpy(mac.octets, mac_addr, 6);
305 
306         zx_status_t call_status, status;
307         status =
308             fuchsia_hardware_ethernet_DeviceConfigMulticastAddMac(svc_.get(), &mac, &call_status);
309         if (status != ZX_OK) {
310             return status;
311         }
312         return call_status;
313     }
314 
MulticastAddressDel(uint8_t * mac_addr)315     zx_status_t MulticastAddressDel(uint8_t* mac_addr) {
316         fuchsia_hardware_ethernet_MacAddress mac;
317         memcpy(mac.octets, mac_addr, 6);
318 
319         zx_status_t call_status, status;
320         status = fuchsia_hardware_ethernet_DeviceConfigMulticastDeleteMac(svc_.get(), &mac,
321                                                                           &call_status);
322         if (status != ZX_OK) {
323             return status;
324         }
325         return call_status;
326     }
327 
328     // Delete this along with other "multicast_" related code once we have IGMP.
329     // This tells the driver to turn off the on-by-default multicast-promisc.
MulticastInitForTest()330     zx_status_t MulticastInitForTest() {
331         zx_status_t call_status, status;
332         status =
333             fuchsia_hardware_ethernet_DeviceConfigMulticastTestFilter(svc_.get(), &call_status);
334         if (status != ZX_OK) {
335             return status;
336         }
337         return call_status;
338     }
339 
tx_fifo()340     fzl::fifo<fuchsia_hardware_ethernet_FifoEntry>* tx_fifo() { return &tx_; }
rx_fifo()341     fzl::fifo<fuchsia_hardware_ethernet_FifoEntry>* rx_fifo() { return &rx_; }
tx_depth()342     uint32_t tx_depth() { return tx_depth_; }
rx_depth()343     uint32_t rx_depth() { return rx_depth_; }
344 
GetRxBuffer(uint32_t offset)345     uint8_t* GetRxBuffer(uint32_t offset) {
346         return reinterpret_cast<uint8_t*>(mapped_) + offset;
347     }
348 
GetTxBuffer()349     fuchsia_hardware_ethernet_FifoEntry* GetTxBuffer() {
350         auto entry_ptr = tx_available_.pop_front();
351         fuchsia_hardware_ethernet_FifoEntry* entry = nullptr;
352         if (entry_ptr != nullptr) {
353             entry = &entry_ptr->e;
354             tx_pending_.push_front(std::move(entry_ptr));
355         }
356         return entry;
357     }
358 
ReturnTxBuffer(fuchsia_hardware_ethernet_FifoEntry * entry)359     void ReturnTxBuffer(fuchsia_hardware_ethernet_FifoEntry* entry) {
360         auto entry_ptr = tx_pending_.erase_if(
361                 [entry](const FifoEntry& tx_entry) { return tx_entry.e.cookie == entry->cookie; });
362         if (entry_ptr != nullptr) {
363             tx_available_.push_front(std::move(entry_ptr));
364         }
365     }
366 
367   private:
368     zx::channel svc_;
369 
370     uint64_t vmo_size_ = 0;
371     zx::vmo buf_;
372     uintptr_t mapped_ = 0;
373     uint32_t nbufs_ = 0;
374     uint16_t bufsize_ = 0;
375 
376     fzl::fifo<fuchsia_hardware_ethernet_FifoEntry> tx_;
377     fzl::fifo<fuchsia_hardware_ethernet_FifoEntry> rx_;
378     uint32_t tx_depth_ = 0;
379     uint32_t rx_depth_ = 0;
380 
381     using FifoEntryPtr = fbl::unique_ptr<FifoEntry>;
382     fbl::SinglyLinkedList<FifoEntryPtr> tx_available_;
383     fbl::SinglyLinkedList<FifoEntryPtr> tx_pending_;
384 };
385 
386 }  // namespace
387 
388 #define HEADER_SIZE (sizeof(ethertap_socket_header_t))
389 #define READBUF_SIZE (ETHERTAP_MAX_MTU + HEADER_SIZE)
390 
391 // Returns the number of reads
DrainSocket(zx::socket * sock)392 static int DrainSocket(zx::socket* sock) {
393     zx_signals_t obs;
394     uint8_t read_buf[READBUF_SIZE];
395     size_t actual_sz = 0;
396     int reads = 0;
397     zx_status_t status = ZX_OK;
398 
399     while (ZX_OK == (status = sock->wait_one(ZX_SOCKET_READABLE, PROPAGATE_TIME, &obs))) {
400         status = sock->read(0u, static_cast<void*>(read_buf), READBUF_SIZE, &actual_sz);
401         ASSERT_EQ(ZX_OK, status);
402         reads++;
403     }
404     ASSERT_EQ(status, ZX_ERR_TIMED_OUT);
405     return reads;
406 }
407 
ExpectSockRead(zx::socket * sock,uint32_t type,size_t size,void * data,const char * msg)408 static bool ExpectSockRead(zx::socket* sock, uint32_t type, size_t size, void* data,
409                            const char* msg) {
410     zx_signals_t obs;
411     uint8_t read_buf[READBUF_SIZE];
412     // The socket should be readable
413     ASSERT_EQ(ZX_OK, sock->wait_one(ZX_SOCKET_READABLE, FAIL_TIMEOUT, &obs), msg);
414     ASSERT_TRUE(obs & ZX_SOCKET_READABLE, msg);
415 
416     // Read the data from the socket, which should match what was written to the fifo
417     size_t actual_sz = 0;
418     ASSERT_EQ(ZX_OK, sock->read(0u, static_cast<void*>(read_buf), READBUF_SIZE, &actual_sz), msg);
419     ASSERT_EQ(size, actual_sz - HEADER_SIZE, msg);
420     auto header = reinterpret_cast<ethertap_socket_header*>(read_buf);
421     ASSERT_EQ(type, header->type, msg);
422     if (size > 0) {
423         ASSERT_NONNULL(data, msg);
424         ASSERT_BYTES_EQ(static_cast<uint8_t*>(data), read_buf + HEADER_SIZE, size, msg);
425     }
426     return true;
427 }
428 
ExpectPacketRead(zx::socket * sock,size_t size,void * data,const char * msg)429 static bool ExpectPacketRead(zx::socket* sock, size_t size, void* data, const char* msg) {
430     return ExpectSockRead(sock, ETHERTAP_MSG_PACKET, size, data, msg);
431 }
432 
ExpectSetParamRead(zx::socket * sock,uint32_t param,int32_t value,size_t data_length,uint8_t * data,const char * msg)433 static bool ExpectSetParamRead(zx::socket* sock, uint32_t param, int32_t value,
434                                size_t data_length, uint8_t* data, const char* msg) {
435     ethertap_setparam_report_t report = {};
436     report.param = param;
437     report.value = value;
438     report.data_length = data_length;
439     ASSERT_LE(data_length, SETPARAM_REPORT_DATA_SIZE, "Report can't return that much data");
440     if (data_length > 0 && data != nullptr) {
441         memcpy(report.data, data, data_length);
442     }
443     return ExpectSockRead(sock, ETHERTAP_MSG_PARAM_REPORT, sizeof(report), &report, msg);
444 }
445 
446 // Functions named ...Helper are intended to be called from every test function for
447 // setup and teardown of the ethdevs.
448 // To generate informative error messages in case they fail, use ASSERT_TRUE() when
449 // calling them.
450 
451 // Note that the test framework will not return false from a helper function upon failure
452 // of an EXPECT_ unless the BEGIN_HELPER / END_HELPER macros are used in that function.
453 // See zircon/system/ulib/unittest/include/unittest/unittest.h and read carefully!
454 
AddClientHelper(zx::socket * sock,EthernetClient * client,const EthernetOpenInfo & openInfo)455 static bool AddClientHelper(zx::socket* sock,
456                             EthernetClient* client,
457                             const EthernetOpenInfo& openInfo) {
458     // Open the ethernet device
459     zx::channel svc;
460     ASSERT_EQ(ZX_OK, OpenEthertapDev(&svc));
461     ASSERT_TRUE(svc.is_valid());
462 
463     // Initialize the ethernet client
464     ASSERT_EQ(ZX_OK, client->Register(std::move(svc), openInfo.name, 32, 2048));
465     if (openInfo.online) {
466         // Start the ethernet client
467         ASSERT_EQ(ZX_OK, client->Start());
468     }
469     if (openInfo.multicast) {
470         ASSERT_EQ(ZX_OK, client->MulticastInitForTest());
471     }
472     if (openInfo.options & ETHERTAP_OPT_REPORT_PARAM) {
473         DrainSocket(sock); // internal driver setup probably has caused some reports
474     }
475     return true;
476 }
477 
OpenFirstClientHelper(zx::socket * sock,EthernetClient * client,const EthernetOpenInfo & openInfo)478 static bool OpenFirstClientHelper(zx::socket* sock,
479                                EthernetClient* client,
480                                const EthernetOpenInfo& openInfo) {
481     // Create the ethertap device
482     ASSERT_EQ(ZX_OK, CreateEthertapWithOption(1500, openInfo.name, sock, openInfo.options));
483 
484     if (openInfo.online) {
485         // Set the link status to online
486         sock->signal_peer(0, ETHERTAP_SIGNAL_ONLINE);
487         // Sleep for just long enough to let the signal propagate
488         zx::nanosleep(PROPAGATE_TIME);
489     }
490 
491     ASSERT_TRUE(AddClientHelper(sock, client, openInfo));
492     return true;
493 }
494 
EthernetCleanupHelper(zx::socket * sock,EthernetClient * client,EthernetClient * client2=nullptr)495 static bool EthernetCleanupHelper(zx::socket* sock,
496                                   EthernetClient* client,
497                                   EthernetClient* client2 = nullptr) {
498     // Note: Don't keep adding client params; find another way if more than 2 clients.
499 
500     // Shutdown the ethernet client(s)
501     ASSERT_EQ(ZX_OK, client->Stop());
502     if (client2 != nullptr) {
503         ASSERT_EQ(ZX_OK, client->Stop());
504     }
505 
506     // Clean up the ethertap device
507     sock->reset();
508 
509     ETHTEST_CLEANUP_DELAY;
510     return true;
511 }
512 
EthernetStartTest()513 static bool EthernetStartTest() {
514     BEGIN_TEST;
515 
516     zx::socket sock;
517     EthernetClient client;
518     EthernetOpenInfo info(__func__);
519     info.online = false;
520     ASSERT_TRUE(OpenFirstClientHelper(&sock, &client, info));
521 
522     // Verify no signals asserted on the rx fifo
523     zx_signals_t obs = 0;
524     client.rx_fifo()->wait_one(fuchsia_hardware_ethernet_SIGNAL_STATUS, zx::time(), &obs);
525     EXPECT_FALSE(obs & fuchsia_hardware_ethernet_SIGNAL_STATUS);
526 
527     // Start the ethernet client
528     EXPECT_EQ(ZX_OK, client.Start());
529 
530     // Verify that the ethernet driver signaled a status change for the initial state.
531     obs = 0;
532     EXPECT_EQ(ZX_OK, client.rx_fifo()->wait_one(fuchsia_hardware_ethernet_SIGNAL_STATUS,
533                                                 FAIL_TIMEOUT, &obs));
534     EXPECT_TRUE(obs & fuchsia_hardware_ethernet_SIGNAL_STATUS);
535 
536     // Default link status should be OFFLINE
537     uint32_t eth_status = 0;
538     EXPECT_EQ(ZX_OK, client.GetStatus(&eth_status));
539     EXPECT_EQ(0, eth_status);
540 
541     // Set the link status to online and verify
542     sock.signal_peer(0, ETHERTAP_SIGNAL_ONLINE);
543 
544     EXPECT_EQ(ZX_OK, client.rx_fifo()->wait_one(fuchsia_hardware_ethernet_SIGNAL_STATUS,
545                                                 FAIL_TIMEOUT, &obs));
546     EXPECT_TRUE(obs & fuchsia_hardware_ethernet_SIGNAL_STATUS);
547 
548     EXPECT_EQ(ZX_OK, client.GetStatus(&eth_status));
549     EXPECT_EQ(fuchsia_hardware_ethernet_DEVICE_STATUS_ONLINE, eth_status);
550 
551     ASSERT_TRUE(EthernetCleanupHelper(&sock, &client));
552     END_TEST;
553 }
554 
EthernetLinkStatusTest()555 static bool EthernetLinkStatusTest() {
556     BEGIN_TEST;
557     // Create the ethertap device
558     zx::socket sock;
559     EthernetClient client;
560     EthernetOpenInfo info(__func__);
561     ASSERT_TRUE(OpenFirstClientHelper(&sock, &client, info));
562 
563     // Verify that the ethernet driver signaled a status change for the initial state.
564     zx_signals_t obs = 0;
565     EXPECT_EQ(ZX_OK, client.rx_fifo()->wait_one(fuchsia_hardware_ethernet_SIGNAL_STATUS,
566                                                 FAIL_TIMEOUT, &obs));
567     EXPECT_TRUE(obs & fuchsia_hardware_ethernet_SIGNAL_STATUS);
568 
569     // Link status should be ONLINE since it's set in OpenFirstClientHelper
570     uint32_t eth_status = 0;
571     EXPECT_EQ(ZX_OK, client.GetStatus(&eth_status));
572     EXPECT_EQ(fuchsia_hardware_ethernet_DEVICE_STATUS_ONLINE, eth_status);
573 
574     // Now the device goes offline
575     sock.signal_peer(0, ETHERTAP_SIGNAL_OFFLINE);
576 
577     // Verify the link status
578     obs = 0;
579     EXPECT_EQ(ZX_OK, client.rx_fifo()->wait_one(fuchsia_hardware_ethernet_SIGNAL_STATUS,
580                                                 FAIL_TIMEOUT, &obs));
581     EXPECT_TRUE(obs & fuchsia_hardware_ethernet_SIGNAL_STATUS);
582 
583     EXPECT_EQ(ZX_OK, client.GetStatus(&eth_status));
584     EXPECT_EQ(0, eth_status);
585 
586     ASSERT_TRUE(EthernetCleanupHelper(&sock, &client));
587     END_TEST;
588 }
589 
EthernetSetPromiscMultiClientTest()590 static bool EthernetSetPromiscMultiClientTest() {
591     BEGIN_TEST;
592 
593     zx::socket sock;
594     EthernetClient clientA;
595     EthernetOpenInfo info("SetPromiscA");
596     info.options = ETHERTAP_OPT_REPORT_PARAM;
597     ASSERT_TRUE(OpenFirstClientHelper(&sock, &clientA, info));
598     EthernetClient clientB;
599     info.name = "SetPromiscB";
600     ASSERT_TRUE(AddClientHelper(&sock, &clientB, info));
601 
602     ASSERT_EQ(ZX_OK, clientA.SetPromisc(true));
603 
604     ExpectSetParamRead(&sock, ETHMAC_SETPARAM_PROMISC, 1, 0, nullptr, "Promisc on (1)");
605 
606     // None of these should cause a change in promisc commands to ethermac.
607     ASSERT_EQ(ZX_OK, clientA.SetPromisc(true)); // It was already requested by A.
608     ASSERT_EQ(ZX_OK, clientB.SetPromisc(true));
609     ASSERT_EQ(ZX_OK, clientA.SetPromisc(false)); // A should now not want it, but B still does.
610     EXPECT_EQ(0, DrainSocket(&sock));
611 
612     // After the next line, no one wants promisc, so I should get a command to turn it off.
613     ASSERT_EQ(ZX_OK, clientB.SetPromisc(false));
614     ExpectSetParamRead(&sock, ETHMAC_SETPARAM_PROMISC, 0, 0, nullptr, "Promisc should be off (2)");
615 
616     ASSERT_TRUE(EthernetCleanupHelper(&sock, &clientA, &clientB));
617     END_TEST;
618 }
619 
EthernetSetPromiscClearOnCloseTest()620 static bool EthernetSetPromiscClearOnCloseTest() {
621     BEGIN_TEST;
622     zx::socket sock;
623     EthernetClient client;
624     EthernetOpenInfo info(__func__);
625     info.options = ETHERTAP_OPT_REPORT_PARAM;
626     ASSERT_TRUE(OpenFirstClientHelper(&sock, &client, info));
627 
628     ASSERT_EQ(ZX_OK, client.SetPromisc(true));
629 
630     ExpectSetParamRead(&sock, ETHMAC_SETPARAM_PROMISC, 1, 0, nullptr, "Promisc on (1)");
631 
632     // Shutdown the ethernet client.
633     EXPECT_EQ(ZX_OK, client.Stop());
634     client.Cleanup(); // This will free devfd
635 
636     // That should have caused promisc to turn off.
637     ExpectSetParamRead(&sock, ETHMAC_SETPARAM_PROMISC, 0, 0, nullptr, "Closed: promisc off (2)");
638 
639     // Clean up the ethertap device.
640     sock.reset();
641 
642     ETHTEST_CLEANUP_DELAY;
643     END_TEST;
644 }
645 
646 // Since we don't have IGMP, multicast promiscuous is on by default. Multicast-related tests
647 // need to turn it off. This test establishes that this is happening correctly. When IGMP is
648 // added and promisc-by-default is turned off, this test will fail. When that happens, delete
649 // the code related to EthernetOpenInfo.multicast.
EthernetClearMulticastPromiscTest()650 static bool EthernetClearMulticastPromiscTest() {
651     BEGIN_TEST;
652     zx::socket sock;
653     EthernetClient client;
654     EthernetOpenInfo info(__func__);
655     info.options = ETHERTAP_OPT_REPORT_PARAM;
656     ASSERT_TRUE(OpenFirstClientHelper(&sock, &client, info));
657 
658     ASSERT_EQ(ZX_OK, client.MulticastInitForTest());
659     ExpectSetParamRead(&sock, ETHMAC_SETPARAM_MULTICAST_PROMISC, 0, 0, nullptr, "promisc off");
660 
661     ASSERT_TRUE(EthernetCleanupHelper(&sock, &client));
662     END_TEST;
663 }
664 
EthernetMulticastRejectsUnicastAddress()665 static bool EthernetMulticastRejectsUnicastAddress() {
666     BEGIN_TEST;
667     zx::socket sock;
668     EthernetClient client;
669     EthernetOpenInfo info(__func__);
670     info.options = ETHERTAP_OPT_REPORT_PARAM;
671     info.multicast = true;
672     ASSERT_TRUE(OpenFirstClientHelper(&sock, &client, info));
673 
674     uint8_t unicastMac[] = {2, 4, 6, 8, 10, 12}; // For multicast, LSb of MSB should be 1
675     ASSERT_EQ(ZX_ERR_INVALID_ARGS, client.MulticastAddressAdd(unicastMac));
676 
677     ASSERT_TRUE(EthernetCleanupHelper(&sock, &client));
678     END_TEST;
679 }
680 
EthernetMulticastSetsAddresses()681 static bool EthernetMulticastSetsAddresses() {
682     BEGIN_TEST;
683     zx::socket sock;
684     EthernetClient clientA;
685     EthernetOpenInfo info("MultiAdrTestA");
686     info.options = ETHERTAP_OPT_REPORT_PARAM;
687     info.multicast = true;
688     ASSERT_TRUE(OpenFirstClientHelper(&sock, &clientA, info));
689     info.name = "MultiAdrTestB";
690     EthernetClient clientB;
691     ASSERT_TRUE(AddClientHelper(&sock, &clientB, info));
692 
693     uint8_t macA[] = {1,2,3,4,5,6};
694     uint8_t macB[] = {7,8,9,10,11,12};
695     uint8_t data[] = {6, 12};
696     ASSERT_EQ(ZX_OK, clientA.MulticastAddressAdd(macA));
697     ExpectSetParamRead(&sock, ETHMAC_SETPARAM_MULTICAST_FILTER, 1, 1, data, "first addr");
698     ASSERT_EQ(ZX_OK, clientB.MulticastAddressAdd(macB));
699     ExpectSetParamRead(&sock, ETHMAC_SETPARAM_MULTICAST_FILTER, 2, 2, data, "second addr");
700 
701     ASSERT_TRUE(EthernetCleanupHelper(&sock, &clientA, &clientB));
702     END_TEST;
703 }
704 
705 // This value is implementation dependent, set in zircon/system/dev/ethernet/ethernet/ethernet.c
706 #define MULTICAST_LIST_LIMIT 32
707 
EthernetMulticastPromiscOnOverflow()708 static bool EthernetMulticastPromiscOnOverflow() {
709     BEGIN_TEST;
710     zx::socket sock;
711     EthernetClient clientA;
712     EthernetOpenInfo info("McPromOvA");
713     info.options = ETHERTAP_OPT_REPORT_PARAM;
714     info.multicast = true;
715     ASSERT_TRUE(OpenFirstClientHelper(&sock, &clientA, info));
716     EthernetClient clientB;
717     info.name = "McPromOvB";
718     ASSERT_TRUE(AddClientHelper(&sock, &clientB, info));
719     uint8_t mac[] = {1,2,3,4,5,0};
720     uint8_t data[MULTICAST_LIST_LIMIT];
721     ASSERT_LT(MULTICAST_LIST_LIMIT, 255); // If false, add code to avoid duplicate mac addresses
722     uint8_t next_val = 0x11; // Any value works; starting at 0x11 makes the dump extra readable.
723     uint32_t n_data = 0;
724     for (uint32_t i = 0; i < MULTICAST_LIST_LIMIT-1; i++) {
725         mac[5] = next_val;
726         data[n_data++] = next_val++;
727         ASSERT_EQ(ZX_OK, clientA.MulticastAddressAdd(mac));
728         ASSERT_TRUE(ExpectSetParamRead(&sock, ETHMAC_SETPARAM_MULTICAST_FILTER,
729                                        n_data, n_data, data, "loading filter"));
730     }
731     ASSERT_EQ(n_data, MULTICAST_LIST_LIMIT-1); // There should be 1 space left
732     mac[5] = next_val;
733     data[n_data++] = next_val++;
734     ASSERT_EQ(ZX_OK, clientB.MulticastAddressAdd(mac));
735     ASSERT_TRUE(ExpectSetParamRead(&sock, ETHMAC_SETPARAM_MULTICAST_FILTER, n_data, n_data, data,
736                                    "b - filter should be full"));
737     mac[5] = next_val++;
738     ASSERT_EQ(ZX_OK, clientB.MulticastAddressAdd(mac));
739     ASSERT_TRUE(ExpectSetParamRead(&sock, ETHMAC_SETPARAM_MULTICAST_FILTER, -1, 0, nullptr,
740                                    "overloaded B"));
741     ASSERT_EQ(ZX_OK, clientB.Stop());
742     n_data--;
743     ASSERT_TRUE(ExpectSetParamRead(&sock, ETHMAC_SETPARAM_MULTICAST_FILTER, n_data, n_data, data,
744                                    "deleted B - filter should have 31"));
745     mac[5] = next_val;
746     data[n_data++] = next_val++;
747     ASSERT_EQ(ZX_OK, clientA.MulticastAddressAdd(mac));
748     ASSERT_TRUE(ExpectSetParamRead(&sock, ETHMAC_SETPARAM_MULTICAST_FILTER, n_data, n_data, data,
749                                    "a - filter should be full"));
750     mac[5] = next_val++;
751     ASSERT_EQ(ZX_OK, clientA.MulticastAddressAdd(mac));
752     ASSERT_TRUE(ExpectSetParamRead(&sock, ETHMAC_SETPARAM_MULTICAST_FILTER, -1, 0, nullptr,
753                                    "overloaded A"));
754     ASSERT_TRUE(EthernetCleanupHelper(&sock, &clientA));
755     END_TEST;
756 }
757 
EthernetSetMulticastPromiscMultiClientTest()758 static bool EthernetSetMulticastPromiscMultiClientTest() {
759     BEGIN_TEST;
760     zx::socket sock;
761     EthernetClient clientA;
762     EthernetOpenInfo info("MultiPromiscA");
763     info.options = ETHERTAP_OPT_REPORT_PARAM;
764     info.multicast = true;
765     ASSERT_TRUE(OpenFirstClientHelper(&sock, &clientA, info));
766     EthernetClient clientB;
767     info.name = "MultiPromiscB";
768     ASSERT_TRUE(AddClientHelper(&sock, &clientB, info));
769 
770     clientA.SetMulticastPromisc(true);
771     ExpectSetParamRead(&sock, ETHMAC_SETPARAM_MULTICAST_PROMISC, 1, 0, nullptr, "Promisc on (1)");
772 
773     // None of these should cause a change in promisc commands to ethermac.
774     clientA.SetMulticastPromisc(true); // It was already requested by A.
775     clientB.SetMulticastPromisc(true);
776     clientA.SetMulticastPromisc(false); // A should now not want it, but B still does.
777     EXPECT_EQ(0, DrainSocket(&sock));
778 
779     // After the next line, no one wants promisc, so I should get a command to turn it off.
780     clientB.SetMulticastPromisc(false);
781     // That should have caused promisc to turn off.
782     ExpectSetParamRead(&sock, ETHMAC_SETPARAM_MULTICAST_PROMISC, 0, 0, nullptr,
783                        "Closed: promisc off (2)");
784 
785     ASSERT_TRUE(EthernetCleanupHelper(&sock, &clientA, &clientB));
786     END_TEST;
787 }
788 
EthernetSetMulticastPromiscClearOnCloseTest()789 static bool EthernetSetMulticastPromiscClearOnCloseTest() {
790     BEGIN_TEST;
791     zx::socket sock;
792     EthernetClient client;
793     EthernetOpenInfo info(__func__);
794     info.options = ETHERTAP_OPT_REPORT_PARAM;
795     info.multicast = true;
796     ASSERT_TRUE(OpenFirstClientHelper(&sock, &client, info));
797 
798     ASSERT_EQ(ZX_OK, client.SetPromisc(true));
799 
800     ExpectSetParamRead(&sock, ETHMAC_SETPARAM_PROMISC, 1, 0, nullptr, "Promisc on (1)");
801 
802     // Shutdown the ethernet client.
803     EXPECT_EQ(ZX_OK, client.Stop());
804     client.Cleanup(); // This will free devfd
805 
806     // That should have caused promisc to turn off.
807     ExpectSetParamRead(&sock, ETHMAC_SETPARAM_PROMISC, 0, 0, nullptr, "Closed: promisc off (2)");
808 
809     // Clean up the ethertap device.
810     sock.reset();
811 
812     ETHTEST_CLEANUP_DELAY;
813     END_TEST;
814 }
815 
EthernetDataTest_Send()816 static bool EthernetDataTest_Send() {
817     BEGIN_TEST;
818     zx::socket sock;
819     EthernetClient client;
820     EthernetOpenInfo info(__func__);
821     ASSERT_TRUE(OpenFirstClientHelper(&sock, &client, info));
822 
823     // Ensure that the fifo is writable
824     zx_signals_t obs;
825     EXPECT_EQ(ZX_OK, client.tx_fifo()->wait_one(ZX_FIFO_WRITABLE, zx::time(), &obs));
826     ASSERT_TRUE(obs & ZX_FIFO_WRITABLE);
827 
828     // Grab an available TX fifo entry
829     auto entry = client.GetTxBuffer();
830     ASSERT_TRUE(entry != nullptr);
831 
832     // Populate some data
833     uint8_t* buf = reinterpret_cast<uint8_t*>(entry->cookie);
834     for (int i = 0; i < 32; i++) {
835         buf[i] = static_cast<uint8_t>(i & 0xff);
836     }
837     entry->length = 32;
838 
839     // Write to the TX fifo
840     ASSERT_EQ(ZX_OK, client.tx_fifo()->write_one(*entry));
841 
842     ExpectPacketRead(&sock, 32, buf, "");
843 
844     // Now the TX completion entry should be available to read from the TX fifo
845     EXPECT_EQ(ZX_OK, client.tx_fifo()->wait_one(ZX_FIFO_READABLE, FAIL_TIMEOUT, &obs));
846     ASSERT_TRUE(obs & ZX_FIFO_READABLE);
847 
848     fuchsia_hardware_ethernet_FifoEntry return_entry;
849     ASSERT_EQ(ZX_OK, client.tx_fifo()->read_one(&return_entry));
850 
851     // Check the flags on the returned entry
852     EXPECT_TRUE(return_entry.flags & fuchsia_hardware_ethernet_FIFO_TX_OK);
853     return_entry.flags = 0;
854 
855     // Verify the bytes from the rest of the entry match what we wrote
856     auto expected_entry = reinterpret_cast<uint8_t*>(entry);
857     auto actual_entry = reinterpret_cast<uint8_t*>(&return_entry);
858     EXPECT_BYTES_EQ(expected_entry, actual_entry, sizeof(fuchsia_hardware_ethernet_FifoEntry), "");
859 
860     // Return the buffer to our client; the client destructor will make sure no TXs are still
861     // pending at the end of te test.
862     client.ReturnTxBuffer(&return_entry);
863 
864     ASSERT_TRUE(EthernetCleanupHelper(&sock, &client));
865     END_TEST;
866 }
867 
EthernetDataTest_Recv()868 static bool EthernetDataTest_Recv() {
869     BEGIN_TEST;
870     zx::socket sock;
871     EthernetClient client;
872     EthernetOpenInfo info(__func__);
873     ASSERT_TRUE(OpenFirstClientHelper(&sock, &client, info));
874 
875     // The socket should be writable
876     zx_signals_t obs;
877     EXPECT_EQ(ZX_OK, sock.wait_one(ZX_SOCKET_WRITABLE, zx::time(), &obs));
878     ASSERT_TRUE(obs & ZX_SOCKET_WRITABLE);
879 
880     // Send a buffer through the socket
881     uint8_t buf[32];
882     for (int i = 0; i < 32; i++) {
883         buf[i] = static_cast<uint8_t>(i & 0xff);
884     }
885     size_t actual = 0;
886     EXPECT_EQ(ZX_OK, sock.write(0, static_cast<void*>(buf), 32, &actual));
887     EXPECT_EQ(32, actual);
888 
889     // The fifo should be readable
890     EXPECT_EQ(ZX_OK, client.rx_fifo()->wait_one(ZX_FIFO_READABLE, FAIL_TIMEOUT, &obs));
891     ASSERT_TRUE(obs & ZX_FIFO_READABLE);
892 
893     // Read the RX fifo
894     fuchsia_hardware_ethernet_FifoEntry entry;
895     EXPECT_EQ(ZX_OK, client.rx_fifo()->read_one(&entry));
896 
897     // Check the bytes in the VMO compared to what we sent through the socket
898     auto return_buf = client.GetRxBuffer(entry.offset);
899     EXPECT_BYTES_EQ(buf, return_buf, entry.length, "");
900 
901     // RX fifo should be readable, and we can return the buffer to the driver
902     EXPECT_EQ(ZX_OK, client.rx_fifo()->wait_one(ZX_FIFO_WRITABLE, zx::time(), &obs));
903     ASSERT_TRUE(obs & ZX_FIFO_WRITABLE);
904 
905     entry.length = 2048;
906     EXPECT_EQ(ZX_OK, client.rx_fifo()->write_one(entry));
907 
908     ASSERT_TRUE(EthernetCleanupHelper(&sock, &client));
909     END_TEST;
910 }
911 
912 BEGIN_TEST_CASE(EthernetSetupTests)
RUN_TEST_MEDIUM(EthernetStartTest)913 RUN_TEST_MEDIUM(EthernetStartTest)
914 RUN_TEST_MEDIUM(EthernetLinkStatusTest)
915 END_TEST_CASE(EthernetSetupTests)
916 
917 BEGIN_TEST_CASE(EthernetConfigTests)
918 RUN_TEST_MEDIUM(EthernetSetPromiscMultiClientTest)
919 RUN_TEST_MEDIUM(EthernetSetPromiscClearOnCloseTest)
920 RUN_TEST_MEDIUM(EthernetClearMulticastPromiscTest)
921 RUN_TEST_MEDIUM(EthernetMulticastRejectsUnicastAddress)
922 RUN_TEST_MEDIUM(EthernetMulticastSetsAddresses)
923 RUN_TEST_MEDIUM(EthernetMulticastPromiscOnOverflow)
924 RUN_TEST_MEDIUM(EthernetSetMulticastPromiscMultiClientTest)
925 RUN_TEST_MEDIUM(EthernetSetMulticastPromiscClearOnCloseTest)
926 END_TEST_CASE(EthernetConfigTests)
927 
928 BEGIN_TEST_CASE(EthernetDataTests)
929 RUN_TEST_MEDIUM(EthernetDataTest_Send)
930 RUN_TEST_MEDIUM(EthernetDataTest_Recv)
931 END_TEST_CASE(EthernetDataTests)
932 
933 int main(int argc, char* argv[]) {
934     bool success = unittest_run_all_tests(argc, argv);
935     return success ? 0 : -1;
936 }
937