[][atenl: add package]
[Description]
Add atenl package, a userspace daemon for mt76 testmode.
atenl acts as an intermediate for HQADLL command and mt76 testmode
(implemented with NL80211_CMD_TESTMODE), which provides transparency for
the usage of QA-tool and Litepoint on mt76.
[Release-log]
N/A
Change-Id: If11e67b36dd7c3ef9629e824bc26ed4f16f34dca
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/5553443
diff --git a/feed/atenl/src/eth.c b/feed/atenl/src/eth.c
new file mode 100644
index 0000000..a58add3
--- /dev/null
+++ b/feed/atenl/src/eth.c
@@ -0,0 +1,109 @@
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include "atenl.h"
+
+int atenl_eth_init(struct atenl *an)
+{
+ struct sockaddr_ll addr = {};
+ struct ifreq ifr = {};
+ int ret;
+
+ memcpy(ifr.ifr_name, BRIDGE_NAME, strlen(BRIDGE_NAME));
+ ret = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_RACFG));
+ if (ret < 0) {
+ perror("socket");
+ goto out;
+ }
+ an->sock_eth = ret;
+
+ addr.sll_family = AF_PACKET;
+ addr.sll_ifindex = if_nametoindex(BRIDGE_NAME);
+
+ ret = bind(an->sock_eth, (struct sockaddr *)&addr, sizeof(addr));
+ if (ret < 0) {
+ perror("bind");
+ goto out;
+ }
+
+ ret = ioctl(an->sock_eth, SIOCGIFHWADDR, &ifr);
+ if (ret < 0) {
+ perror("ioctl(SIOCGIFHWADDR)");
+ goto out;
+ }
+
+ memcpy(an->mac_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
+ atenl_info("Open Ethernet socket success on %s, mac addr = " MACSTR "\n",
+ BRIDGE_NAME, MAC2STR(an->mac_addr));
+
+ ret = 0;
+out:
+ return ret;
+}
+
+int atenl_eth_recv(struct atenl *an, struct atenl_data *data)
+{
+ char buf[RACFG_PKT_MAX_SIZE];
+ int len = recvfrom(an->sock_eth, buf, sizeof(buf), 0, NULL, NULL);
+ struct ethhdr *hdr = (struct ethhdr *)buf;
+
+ atenl_dbg("[%d]%s: recv len = %d\n", getpid(), __func__, len);
+
+ if (len >= ETH_HLEN + RACFG_HLEN) {
+ if (hdr->h_proto == htons(ETH_P_RACFG) &&
+ (ether_addr_equal(an->mac_addr, hdr->h_dest) ||
+ is_broadcast_ether_addr(hdr->h_dest))) {
+ data->len = len;
+ memcpy(data->buf, buf, len);
+
+ return 0;
+ }
+ }
+
+ atenl_err("%s: packet len is too short\n", __func__);
+ return -EINVAL;
+}
+
+int atenl_eth_send(struct atenl *an, struct atenl_data *data)
+{
+ struct ethhdr *ehdr = (struct ethhdr *)data->buf;
+ struct sockaddr_ll addr = {};
+ int ret, len = data->len;
+
+ if (an->unicast)
+ ether_addr_copy(ehdr->h_dest, ehdr->h_source);
+ else
+ eth_broadcast_addr(ehdr->h_dest);
+
+ ether_addr_copy(ehdr->h_source, an->mac_addr);
+ ehdr->h_proto = htons(ETH_P_RACFG);
+
+ if (len < 60)
+ len = 60;
+ else if (len > 1514) {
+ atenl_err("%s: response ethernet length is too long\n", __func__);
+ return -1;
+ }
+
+ atenl_dbg_print_data(data, __func__, len);
+
+ addr.sll_family = PF_PACKET;
+ addr.sll_protocol = htons(ETH_P_RACFG);
+ addr.sll_ifindex = if_nametoindex(BRIDGE_NAME);
+ addr.sll_pkttype = PACKET_BROADCAST;
+ addr.sll_hatype = ARPHRD_ETHER;
+ addr.sll_halen = ETH_ALEN;
+ memset(addr.sll_addr, 0, 8);
+ eth_broadcast_addr(addr.sll_addr);
+
+ ret = sendto(an->sock_eth, data->buf, len, 0,
+ (struct sockaddr *)&addr, sizeof(addr));
+ if (ret < 0) {
+ perror("sendto");
+ return ret;
+ }
+
+ atenl_dbg("[%d]%s: send length = %d\n", getpid(), __func__, len);
+
+ return 0;
+}