developer | 3abe1ad | 2022-01-24 11:13:32 +0800 | [diff] [blame] | 1 | #include <sys/ioctl.h> |
| 2 | #include <sys/socket.h> |
| 3 | |
| 4 | #include "atenl.h" |
| 5 | |
| 6 | int atenl_eth_init(struct atenl *an) |
| 7 | { |
| 8 | struct sockaddr_ll addr = {}; |
| 9 | struct ifreq ifr = {}; |
| 10 | int ret; |
| 11 | |
| 12 | memcpy(ifr.ifr_name, BRIDGE_NAME, strlen(BRIDGE_NAME)); |
| 13 | ret = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_RACFG)); |
| 14 | if (ret < 0) { |
| 15 | perror("socket"); |
| 16 | goto out; |
| 17 | } |
| 18 | an->sock_eth = ret; |
| 19 | |
| 20 | addr.sll_family = AF_PACKET; |
| 21 | addr.sll_ifindex = if_nametoindex(BRIDGE_NAME); |
| 22 | |
| 23 | ret = bind(an->sock_eth, (struct sockaddr *)&addr, sizeof(addr)); |
| 24 | if (ret < 0) { |
| 25 | perror("bind"); |
| 26 | goto out; |
| 27 | } |
| 28 | |
| 29 | ret = ioctl(an->sock_eth, SIOCGIFHWADDR, &ifr); |
| 30 | if (ret < 0) { |
| 31 | perror("ioctl(SIOCGIFHWADDR)"); |
| 32 | goto out; |
| 33 | } |
| 34 | |
| 35 | memcpy(an->mac_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN); |
| 36 | atenl_info("Open Ethernet socket success on %s, mac addr = " MACSTR "\n", |
| 37 | BRIDGE_NAME, MAC2STR(an->mac_addr)); |
| 38 | |
| 39 | ret = 0; |
| 40 | out: |
| 41 | return ret; |
| 42 | } |
| 43 | |
| 44 | int atenl_eth_recv(struct atenl *an, struct atenl_data *data) |
| 45 | { |
developer | 5698c9c | 2022-05-30 16:40:23 +0800 | [diff] [blame^] | 46 | struct ethhdr *hdr; |
| 47 | int len; |
developer | 3abe1ad | 2022-01-24 11:13:32 +0800 | [diff] [blame] | 48 | |
developer | 5698c9c | 2022-05-30 16:40:23 +0800 | [diff] [blame^] | 49 | len = recvfrom(an->sock_eth, data->buf, sizeof(data->buf), 0, NULL, NULL); |
developer | 3abe1ad | 2022-01-24 11:13:32 +0800 | [diff] [blame] | 50 | |
developer | 5698c9c | 2022-05-30 16:40:23 +0800 | [diff] [blame^] | 51 | if (len < ETH_HLEN + RACFG_HLEN) { |
| 52 | atenl_err("packet len is too short: %d\n", len); |
| 53 | return -EINVAL; |
| 54 | } |
| 55 | |
| 56 | hdr = (struct ethhdr *)data->buf; |
| 57 | if (hdr->h_proto != htons(ETH_P_RACFG)) { |
| 58 | atenl_err("invalid protocol type\n"); |
| 59 | return -EINVAL; |
| 60 | } |
developer | 3abe1ad | 2022-01-24 11:13:32 +0800 | [diff] [blame] | 61 | |
developer | 5698c9c | 2022-05-30 16:40:23 +0800 | [diff] [blame^] | 62 | if (!ether_addr_equal(an->mac_addr, hdr->h_dest) && |
| 63 | !is_broadcast_ether_addr(hdr->h_dest)) { |
| 64 | atenl_err("invalid dest MAC\n"); |
| 65 | return -EINVAL; |
developer | 3abe1ad | 2022-01-24 11:13:32 +0800 | [diff] [blame] | 66 | } |
| 67 | |
developer | 5698c9c | 2022-05-30 16:40:23 +0800 | [diff] [blame^] | 68 | data->len = len; |
| 69 | |
| 70 | return 0; |
developer | 3abe1ad | 2022-01-24 11:13:32 +0800 | [diff] [blame] | 71 | } |
| 72 | |
| 73 | int atenl_eth_send(struct atenl *an, struct atenl_data *data) |
| 74 | { |
| 75 | struct ethhdr *ehdr = (struct ethhdr *)data->buf; |
| 76 | struct sockaddr_ll addr = {}; |
| 77 | int ret, len = data->len; |
| 78 | |
| 79 | if (an->unicast) |
| 80 | ether_addr_copy(ehdr->h_dest, ehdr->h_source); |
| 81 | else |
| 82 | eth_broadcast_addr(ehdr->h_dest); |
| 83 | |
| 84 | ether_addr_copy(ehdr->h_source, an->mac_addr); |
| 85 | ehdr->h_proto = htons(ETH_P_RACFG); |
| 86 | |
| 87 | if (len < 60) |
| 88 | len = 60; |
| 89 | else if (len > 1514) { |
developer | 5698c9c | 2022-05-30 16:40:23 +0800 | [diff] [blame^] | 90 | atenl_err("response ethernet length is too long\n"); |
developer | 3abe1ad | 2022-01-24 11:13:32 +0800 | [diff] [blame] | 91 | return -1; |
| 92 | } |
| 93 | |
developer | 5698c9c | 2022-05-30 16:40:23 +0800 | [diff] [blame^] | 94 | atenl_dbg_print_data(data->buf, __func__, len); |
developer | 3abe1ad | 2022-01-24 11:13:32 +0800 | [diff] [blame] | 95 | |
| 96 | addr.sll_family = PF_PACKET; |
| 97 | addr.sll_protocol = htons(ETH_P_RACFG); |
| 98 | addr.sll_ifindex = if_nametoindex(BRIDGE_NAME); |
| 99 | addr.sll_pkttype = PACKET_BROADCAST; |
| 100 | addr.sll_hatype = ARPHRD_ETHER; |
| 101 | addr.sll_halen = ETH_ALEN; |
| 102 | memset(addr.sll_addr, 0, 8); |
| 103 | eth_broadcast_addr(addr.sll_addr); |
| 104 | |
| 105 | ret = sendto(an->sock_eth, data->buf, len, 0, |
| 106 | (struct sockaddr *)&addr, sizeof(addr)); |
| 107 | if (ret < 0) { |
| 108 | perror("sendto"); |
| 109 | return ret; |
| 110 | } |
| 111 | |
developer | 3abe1ad | 2022-01-24 11:13:32 +0800 | [diff] [blame] | 112 | return 0; |
| 113 | } |