[netifc] Search all available net interfaces for a link. Change-Id: Ie20a7748701b9428fa151af26101e045b6c8012d
diff --git a/src/netifc.c b/src/netifc.c index 7233091..7916565 100644 --- a/src/netifc.c +++ b/src/netifc.c
@@ -126,49 +126,100 @@ return 0; } +/* Search the available network interfaces via SimpleNetworkProtocol handles + * and find the first valid one with a Link detected */ +EFI_SIMPLE_NETWORK *netifc_find_available(void) { + EFI_BOOT_SERVICES* bs = gSys->BootServices; + EFI_STATUS ret; + EFI_SIMPLE_NETWORK *cur_snp = NULL; + EFI_HANDLE h[32]; + size_t nic_cnt = 0; + size_t sz = sizeof(h); + uint32_t int_sts; + void *tx_buf; + + /* Get the handles of all devices that provide SimpleNetworkProtocol interfaces */ + ret = bs->LocateHandle(ByProtocol, &SimpleNetworkProtocol, NULL, &sz, h); + if (ret != EFI_SUCCESS) { + printf("Failed to locate network interfaces (%ld)\n", ~EFI_ERROR_MASK & ret); + return NULL; + } + + nic_cnt = sz / sizeof(EFI_HANDLE); + printf("Found %zu network interface%c\n", nic_cnt, (nic_cnt == 1) ? ' ' : 's'); + for (size_t i = 0; i < nic_cnt; i++) { + CHAR16 *path = HandleToString(h[i]); + Print(L"%u: %s\n", i, path); + } + + /* Iterate over our SNP list until we find one with an established link */ + for (size_t i = 0; i < nic_cnt; i++) { + printf("net%zu: ", i); + ret = bs->OpenProtocol(h[i], &SimpleNetworkProtocol, (void**)&cur_snp, gImg, NULL, + EFI_OPEN_PROTOCOL_EXCLUSIVE); + if (ret) { + printf("Failed to open (%lu)\n", ~EFI_ERROR_MASK & ret); + continue; + } + + ret = cur_snp->Start(cur_snp); + if (EFI_ERROR(ret)) { + printf("Failed to start (%lu)", ~EFI_ERROR_MASK & ret); + goto link_fail; + } + + /* Additional buffer allocations shouldn't be needed */ + ret = cur_snp->Initialize(cur_snp, 0, 0); + if (EFI_ERROR(ret)) { + printf("Failed to initialize (%lu)\n", ~EFI_ERROR_MASK & ret); + goto link_fail; + } + + /* Prod the driver to cache its current status. We don't need the status or buffer, + * but some drivers appear to require the OPTIONAL parameters. */ + ret = cur_snp->GetStatus(cur_snp, &int_sts, &tx_buf); + if (EFI_ERROR(ret)) { + printf("Failed to read status (%lu)\n", ~EFI_ERROR_MASK & ret); + goto link_fail; + } + + /* With status cached, do we have a Link detected on the netifc? */ + if (!cur_snp->Mode->MediaPresent) { + printf("No link detected\n"); + goto link_fail; + } + + printf("Link detected!\n"); + return cur_snp; + +link_fail: + bs->CloseProtocol(h[i], &SimpleNetworkProtocol, gImg, NULL); + cur_snp = NULL; + } + + return NULL; +} + int netifc_open(void) { EFI_BOOT_SERVICES* bs = gSys->BootServices; - EFI_HANDLE h[32]; - EFI_STATUS r; - int i, j; - UINTN sz; + EFI_STATUS ret; + int j; bs->CreateEvent(EVT_TIMER, TPL_CALLBACK, NULL, NULL, &net_timer); - sz = sizeof(h); - r = bs->LocateHandle(ByProtocol, &SimpleNetworkProtocol, NULL, &sz, h); - if (r != EFI_SUCCESS) { - printf("Failed to locate SNP handle(s) %ld\n", r); + snp = netifc_find_available(); + if (!snp) { + printf("Failed to find a usable network interface\n"); return -1; } - r = bs->OpenProtocol(h[0], &SimpleNetworkProtocol, (void**)&snp, gImg, NULL, - EFI_OPEN_PROTOCOL_EXCLUSIVE); - if (r) { - printf("Failed to open SNP exclusively %ld\n", r); - return -1; - } - - if (snp->Mode->State != EfiSimpleNetworkStarted) { - snp->Start(snp); - if (snp->Mode->State != EfiSimpleNetworkStarted) { - printf("Failed to start SNP\n"); - return -1; - } - r = snp->Initialize(snp, 32768, 32768); - if (r) { - printf("Failed to initialize SNP\n"); - return -1; - } - } - if (bs->AllocatePages(AllocateAnyPages, EfiLoaderData, NUM_BUFFER_PAGES, ð_buffers_base)) { printf("Failed to allocate net buffers\n"); return -1; } uint8_t* ptr = (void*)eth_buffers_base; - for (r = 0; r < (NUM_BUFFER_PAGES * 2); r++) { + for (ret = 0; ret < (NUM_BUFFER_PAGES * 2); ret++) { eth_buffer* buf = (void*)ptr; buf->magic = ETH_BUFFER_MAGIC; eth_put_buffer(buf); @@ -177,12 +228,12 @@ ip6_init(snp->Mode->CurrentAddress.Addr); - r = snp->ReceiveFilters(snp, + ret = snp->ReceiveFilters(snp, EFI_SIMPLE_NETWORK_RECEIVE_UNICAST | EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST, 0, 0, mcast_filter_count, (void*)mcast_filters); - if (r) { - printf("Failed to install multicast filters %lx\n", r); + if (ret) { + printf("Failed to install multicast filters %lx\n", ret); return -1; } @@ -193,7 +244,7 @@ mcast_filter_count, snp->Mode->MCastFilterCount); goto force_promisc; } - for (i = 0; i < mcast_filter_count; i++) { + for (size_t i = 0; i < mcast_filter_count; i++) { //uint8_t *m = (void*) &mcast_filters[i]; //printf("i=%d %02x %02x %02x %02x %02x %02x\n", i, m[0], m[1], m[2], m[3], m[4], m[5]); for (j = 0; j < mcast_filter_count; j++) { @@ -203,7 +254,7 @@ goto found_it; } } - printf("OOPS: filter #%d missing\n", i); + printf("OOPS: filter #%zu missing\n", i); goto force_promisc; found_it:; } @@ -211,13 +262,13 @@ return 0; force_promisc: - r = snp->ReceiveFilters(snp, + ret = snp->ReceiveFilters(snp, EFI_SIMPLE_NETWORK_RECEIVE_UNICAST | EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS | EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST, 0, 0, 0, NULL); - if (r) { - printf("Failed to set promiscuous mode %lx\n", r); + if (ret) { + printf("Failed to set promiscuous mode %lx\n", ret); return -1; } return 0; @@ -249,19 +300,17 @@ eth_put_buffer(txdone); } - if (irq & EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT) { - hsz = 0; - bsz = sizeof(data); - r = snp->Receive(snp, &hsz, &bsz, data, NULL, NULL, NULL); - if (r != EFI_SUCCESS) { - return; - } -#if TRACE - printf("RX %02x:%02x:%02x:%02x:%02x:%02x < %02x:%02x:%02x:%02x:%02x:%02x %02x%02x %d\n", - data[0], data[1], data[2], data[3], data[4], data[5], - data[6], data[7], data[8], data[9], data[10], data[11], - data[12], data[13], (int)(bsz - hsz)); -#endif - eth_recv(data, bsz); + hsz = 0; + bsz = sizeof(data); + r = snp->Receive(snp, &hsz, &bsz, data, NULL, NULL, NULL); + if (r != EFI_SUCCESS) { + return; } +#if TRACE + printf("RX %02x:%02x:%02x:%02x:%02x:%02x < %02x:%02x:%02x:%02x:%02x:%02x %02x%02x %d\n", + data[0], data[1], data[2], data[3], data[4], data[5], + data[6], data[7], data[8], data[9], data[10], data[11], + data[12], data[13], (int)(bsz - hsz)); +#endif + eth_recv(data, bsz); }