// SPDX-License-Identifier: GPL-2.0 /* Copyright (C) 2024 Linaro Ltd. */ #include #include #include #include #include #include #include #include #include #include #include /* xx:xx:xx:xx:xx:xx\0 */ #define MAC_ADDR_STRLEN 18 #if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER) void (*push_packet)(void *, int len) = 0; #endif int net_restart_wrap; static uchar net_pkt_buf[(PKTBUFSRX) * PKTSIZE_ALIGN + PKTALIGN]; uchar *net_rx_packets[PKTBUFSRX]; uchar *net_rx_packet; const u8 net_bcast_ethaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; char *pxelinux_configfile; /* Our IP addr (0 = unknown) */ struct in_addr net_ip; static err_t linkoutput(struct netif *netif, struct pbuf *p) { struct udevice *udev = netif->state; void *pp = NULL; int err; if ((unsigned long)p->payload % PKTALIGN) { /* * Some net drivers have strict alignment requirements and may * fail or output invalid data if the packet is not aligned. */ pp = memalign(PKTALIGN, p->len); if (!pp) return ERR_ABRT; memcpy(pp, p->payload, p->len); } err = eth_get_ops(udev)->send(udev, pp ? pp : p->payload, p->len); free(pp); if (err) { log_err("send error %d\n", err); return ERR_ABRT; } return ERR_OK; } static err_t net_lwip_if_init(struct netif *netif) { netif->output = etharp_output; netif->linkoutput = linkoutput; netif->mtu = 1500; netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP; return ERR_OK; } static void eth_init_rings(void) { int i; for (i = 0; i < PKTBUFSRX; i++) net_rx_packets[i] = net_pkt_buf + i * PKTSIZE_ALIGN; } struct netif *net_lwip_get_netif(void) { struct netif *netif, *found = NULL; NETIF_FOREACH(netif) { if (!found) found = netif; else printf("Error: more than one netif in lwIP\n"); } return found; } static int get_udev_ipv4_info(struct udevice *dev, ip4_addr_t *ip, ip4_addr_t *mask, ip4_addr_t *gw) { char *ipstr = "ipaddr\0\0"; char *maskstr = "netmask\0\0"; char *gwstr = "gatewayip\0\0"; int idx = dev_seq(dev); char *env; if (idx < 0 || idx > 99) { log_err("unexpected idx %d\n", idx); return -1; } if (idx) { sprintf(ipstr, "ipaddr%d", idx); sprintf(maskstr, "netmask%d", idx); sprintf(gwstr, "gatewayip%d", idx); } ip4_addr_set_zero(ip); ip4_addr_set_zero(mask); ip4_addr_set_zero(gw); env = env_get(ipstr); if (env) ip4addr_aton(env, ip); env = env_get(maskstr); if (env) ip4addr_aton(env, mask); env = env_get(gwstr); if (env) ip4addr_aton(env, gw); return 0; } static struct netif *new_netif(struct udevice *udev, bool with_ip) { unsigned char enetaddr[ARP_HLEN]; char hwstr[MAC_ADDR_STRLEN]; ip4_addr_t ip, mask, gw; struct netif *netif; int ret = 0; static bool first_call = true; if (!udev) return NULL; if (first_call) { eth_init_rings(); /* Pick a valid active device, if any */ eth_init(); lwip_init(); first_call = false; } if (eth_start_udev(udev) < 0) { log_err("Could not start %s\n", udev->name); return NULL; } netif_remove(net_lwip_get_netif()); ip4_addr_set_zero(&ip); ip4_addr_set_zero(&mask); ip4_addr_set_zero(&gw); if (with_ip) if (get_udev_ipv4_info(udev, &ip, &mask, &gw) < 0) return NULL; eth_env_get_enetaddr_by_index("eth", dev_seq(udev), enetaddr); ret = snprintf(hwstr, MAC_ADDR_STRLEN, "%pM", enetaddr); if (ret < 0 || ret >= MAC_ADDR_STRLEN) return NULL; netif = calloc(1, sizeof(struct netif)); if (!netif) return NULL; netif->name[0] = 'e'; netif->name[1] = 't'; string_to_enetaddr(hwstr, netif->hwaddr); netif->hwaddr_len = ETHARP_HWADDR_LEN; debug("adding lwIP netif for %s with hwaddr:%s ip:%s ", udev->name, hwstr, ip4addr_ntoa(&ip)); debug("mask:%s ", ip4addr_ntoa(&mask)); debug("gw:%s\n", ip4addr_ntoa(&gw)); if (!netif_add(netif, &ip, &mask, &gw, udev, net_lwip_if_init, netif_input)) { printf("error: netif_add() failed\n"); free(netif); return NULL; } netif_set_up(netif); netif_set_link_up(netif); /* Routing: use this interface to reach the default gateway */ netif_set_default(netif); return netif; } struct netif *net_lwip_new_netif(struct udevice *udev) { return new_netif(udev, true); } struct netif *net_lwip_new_netif_noip(struct udevice *udev) { return new_netif(udev, false); } void net_lwip_remove_netif(struct netif *netif) { netif_remove(netif); free(netif); } int net_init(void) { eth_set_current(); net_lwip_new_netif(eth_get_dev()); return 0; } static struct pbuf *alloc_pbuf_and_copy(uchar *data, int len) { struct pbuf *p, *q; /* We allocate a pbuf chain of pbufs from the pool. */ p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL); if (!p) { LINK_STATS_INC(link.memerr); LINK_STATS_INC(link.drop); return NULL; } for (q = p; q != NULL; q = q->next) { memcpy(q->payload, data, q->len); data += q->len; } LINK_STATS_INC(link.recv); return p; } int net_lwip_rx(struct udevice *udev, struct netif *netif) { struct pbuf *pbuf; uchar *packet; int flags; int len; int i; if (!eth_is_active(udev)) return -EINVAL; flags = ETH_RECV_CHECK_DEVICE; for (i = 0; i < ETH_PACKETS_BATCH_RECV; i++) { len = eth_get_ops(udev)->recv(udev, flags, &packet); flags = 0; if (len > 0) { pbuf = alloc_pbuf_and_copy(packet, len); if (pbuf) netif->input(pbuf, netif); } if (len >= 0 && eth_get_ops(udev)->free_pkt) eth_get_ops(udev)->free_pkt(udev, packet, len); if (len <= 0) break; } if (len == -EAGAIN) len = 0; return len; } void net_process_received_packet(uchar *in_packet, int len) { #if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER) if (push_packet) (*push_packet)(in_packet, len); #endif } u32_t sys_now(void) { return get_timer(0); }