18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* 28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * WPA Supplicant - Layer2 packet handling with Linux packet sockets 3216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi> 48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 5c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * This software may be distributed under the terms of the BSD license. 6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * See README for more details. 78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "includes.h" 108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <sys/ioctl.h> 118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <netpacket/packet.h> 128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <net/if.h> 136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#include <linux/filter.h> 148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common.h" 168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "eloop.h" 177f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt#include "crypto/sha1.h" 187f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt#include "crypto/crypto.h" 198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "l2_packet.h" 208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct l2_packet_data { 238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int fd; /* packet socket for EAPOL frames */ 248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt char ifname[IFNAMSIZ + 1]; 258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int ifindex; 268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 own_addr[ETH_ALEN]; 278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt void (*rx_callback)(void *ctx, const u8 *src_addr, 288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *buf, size_t len); 298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt void *rx_callback_ctx; 308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int l2_hdr; /* whether to include layer 2 (Ethernet) header data 318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * buffers */ 32216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt 33d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt#ifndef CONFIG_NO_LINUX_PACKET_SOCKET_WAR 34216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt /* For working around Linux packet socket behavior and regression. */ 35216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt int fd_br_rx; 36de47be75037bccd4a11b62eedb3d4aed1b36fa67Dmitry Shmidt int last_from_br, last_from_br_prev; 377f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt u8 last_hash[SHA1_MAC_LEN]; 38de47be75037bccd4a11b62eedb3d4aed1b36fa67Dmitry Shmidt u8 last_hash_prev[SHA1_MAC_LEN]; 39d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt unsigned int num_rx_br; 40d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt#endif /* CONFIG_NO_LINUX_PACKET_SOCKET_WAR */ 418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}; 428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt/* Generated by 'sudo tcpdump -s 3000 -dd greater 278 and ip and udp and 446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * src port bootps and dst port bootpc' 456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt */ 466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic struct sock_filter dhcp_sock_filter_insns[] = { 476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt { 0x80, 0, 0, 0x00000000 }, 486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt { 0x35, 0, 12, 0x00000116 }, 496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt { 0x28, 0, 0, 0x0000000c }, 506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt { 0x15, 0, 10, 0x00000800 }, 516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt { 0x30, 0, 0, 0x00000017 }, 526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt { 0x15, 0, 8, 0x00000011 }, 536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt { 0x28, 0, 0, 0x00000014 }, 546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt { 0x45, 6, 0, 0x00001fff }, 556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt { 0xb1, 0, 0, 0x0000000e }, 566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt { 0x48, 0, 0, 0x0000000e }, 576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt { 0x15, 0, 3, 0x00000043 }, 586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt { 0x48, 0, 0, 0x00000010 }, 596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt { 0x15, 0, 1, 0x00000044 }, 606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt { 0x6, 0, 0, 0x00000bb8 }, 616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt { 0x6, 0, 0, 0x00000000 }, 626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}; 636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic const struct sock_fprog dhcp_sock_filter = { 656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt .len = ARRAY_SIZE(dhcp_sock_filter_insns), 666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt .filter = dhcp_sock_filter_insns, 676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}; 686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt/* Generated by 'sudo tcpdump -dd -s 1500 multicast and ip6[6]=58' */ 716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic struct sock_filter ndisc_sock_filter_insns[] = { 726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt { 0x30, 0, 0, 0x00000000 }, 736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt { 0x45, 0, 5, 0x00000001 }, 746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt { 0x28, 0, 0, 0x0000000c }, 756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt { 0x15, 0, 3, 0x000086dd }, 766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt { 0x30, 0, 0, 0x00000014 }, 776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt { 0x15, 0, 1, 0x0000003a }, 786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt { 0x6, 0, 0, 0x000005dc }, 796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt { 0x6, 0, 0, 0x00000000 }, 806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}; 816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic const struct sock_fprog ndisc_sock_filter = { 836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt .len = ARRAY_SIZE(ndisc_sock_filter_insns), 846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt .filter = ndisc_sock_filter_insns, 856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}; 866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr) 898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(addr, l2->own_addr, ETH_ALEN); 918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto, 968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *buf, size_t len) 978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int ret; 998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (l2 == NULL) 1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (l2->l2_hdr) { 1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret = send(l2->fd, buf, len, 0); 1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ret < 0) 1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "l2_packet_send - send: %s", 1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt strerror(errno)); 1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else { 1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct sockaddr_ll ll; 1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memset(&ll, 0, sizeof(ll)); 1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ll.sll_family = AF_PACKET; 1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ll.sll_ifindex = l2->ifindex; 1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ll.sll_protocol = htons(proto); 1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ll.sll_halen = ETH_ALEN; 1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(ll.sll_addr, dst_addr, ETH_ALEN); 1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret = sendto(l2->fd, buf, len, 0, (struct sockaddr *) &ll, 1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sizeof(ll)); 1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ret < 0) { 1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "l2_packet_send - sendto: %s", 1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt strerror(errno)); 1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return ret; 1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx) 1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct l2_packet_data *l2 = eloop_ctx; 1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 buf[2300]; 1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int res; 1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct sockaddr_ll ll; 1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt socklen_t fromlen; 1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memset(&ll, 0, sizeof(ll)); 1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt fromlen = sizeof(ll); 1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt res = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *) &ll, 1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &fromlen); 1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (res < 0) { 1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "l2_packet_receive - recvfrom: %s", 1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt strerror(errno)); 1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1437f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt wpa_printf(MSG_DEBUG, "%s: src=" MACSTR " len=%d", 1447f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt __func__, MAC2STR(ll.sll_addr), (int) res); 145216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt 146d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt#ifndef CONFIG_NO_LINUX_PACKET_SOCKET_WAR 147216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt if (l2->fd_br_rx >= 0) { 1487f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt u8 hash[SHA1_MAC_LEN]; 1497f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt const u8 *addr[1]; 1507f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt size_t len[1]; 1517f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt 1527f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt /* 1537f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt * Close the workaround socket if the kernel version seems to be 1547f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt * able to deliver packets through the packet socket before 1557f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt * authorization has been completed (in dormant state). 1567f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt */ 1577f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt if (l2->num_rx_br <= 1) { 1587f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt wpa_printf(MSG_DEBUG, 1597f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt "l2_packet_receive: Main packet socket for %s seems to have working RX - close workaround bridge socket", 1607f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt l2->ifname); 1617f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt eloop_unregister_read_sock(l2->fd_br_rx); 1627f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt close(l2->fd_br_rx); 1637f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt l2->fd_br_rx = -1; 1647f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt } 1657f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt 1667f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt addr[0] = buf; 1677f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt len[0] = res; 1687f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt sha1_vector(1, addr, len, hash); 1697f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt if (l2->last_from_br && 1707f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt os_memcmp(hash, l2->last_hash, SHA1_MAC_LEN) == 0) { 1717f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt wpa_printf(MSG_DEBUG, "%s: Drop duplicate RX", 1727f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt __func__); 1737f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt return; 1747f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt } 175de47be75037bccd4a11b62eedb3d4aed1b36fa67Dmitry Shmidt if (l2->last_from_br_prev && 176de47be75037bccd4a11b62eedb3d4aed1b36fa67Dmitry Shmidt os_memcmp(hash, l2->last_hash_prev, SHA1_MAC_LEN) == 0) { 177de47be75037bccd4a11b62eedb3d4aed1b36fa67Dmitry Shmidt wpa_printf(MSG_DEBUG, "%s: Drop duplicate RX(prev)", 178de47be75037bccd4a11b62eedb3d4aed1b36fa67Dmitry Shmidt __func__); 179de47be75037bccd4a11b62eedb3d4aed1b36fa67Dmitry Shmidt return; 180de47be75037bccd4a11b62eedb3d4aed1b36fa67Dmitry Shmidt } 181de47be75037bccd4a11b62eedb3d4aed1b36fa67Dmitry Shmidt os_memcpy(l2->last_hash_prev, l2->last_hash, SHA1_MAC_LEN); 182de47be75037bccd4a11b62eedb3d4aed1b36fa67Dmitry Shmidt l2->last_from_br_prev = l2->last_from_br; 1837f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt os_memcpy(l2->last_hash, hash, SHA1_MAC_LEN); 184216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt } 1857f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt 1867f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt l2->last_from_br = 0; 187d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt#endif /* CONFIG_NO_LINUX_PACKET_SOCKET_WAR */ 1887f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt l2->rx_callback(l2->rx_callback_ctx, ll.sll_addr, buf, res); 189216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt} 190216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt 191216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt 192d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt#ifndef CONFIG_NO_LINUX_PACKET_SOCKET_WAR 193216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidtstatic void l2_packet_receive_br(int sock, void *eloop_ctx, void *sock_ctx) 194216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt{ 195216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt struct l2_packet_data *l2 = eloop_ctx; 196216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt u8 buf[2300]; 197216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt int res; 198216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt struct sockaddr_ll ll; 199216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt socklen_t fromlen; 2007f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt u8 hash[SHA1_MAC_LEN]; 2017f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt const u8 *addr[1]; 2027f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt size_t len[1]; 203216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt 2047f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt l2->num_rx_br++; 205216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt os_memset(&ll, 0, sizeof(ll)); 206216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt fromlen = sizeof(ll); 207216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt res = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *) &ll, 208216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt &fromlen); 209216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt if (res < 0) { 210216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt wpa_printf(MSG_DEBUG, "l2_packet_receive_br - recvfrom: %s", 211216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt strerror(errno)); 212216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt return; 213216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt } 214216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt 2157f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt wpa_printf(MSG_DEBUG, "%s: src=" MACSTR " len=%d", 2167f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt __func__, MAC2STR(ll.sll_addr), (int) res); 2177f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt 218de47be75037bccd4a11b62eedb3d4aed1b36fa67Dmitry Shmidt if (os_memcmp(ll.sll_addr, l2->own_addr, ETH_ALEN) == 0) { 219de47be75037bccd4a11b62eedb3d4aed1b36fa67Dmitry Shmidt wpa_printf(MSG_DEBUG, "%s: Drop RX of own frame", __func__); 220de47be75037bccd4a11b62eedb3d4aed1b36fa67Dmitry Shmidt return; 221de47be75037bccd4a11b62eedb3d4aed1b36fa67Dmitry Shmidt } 222de47be75037bccd4a11b62eedb3d4aed1b36fa67Dmitry Shmidt 2237f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt addr[0] = buf; 2247f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt len[0] = res; 2257f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt sha1_vector(1, addr, len, hash); 2267f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt if (!l2->last_from_br && 2277f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt os_memcmp(hash, l2->last_hash, SHA1_MAC_LEN) == 0) { 2287f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt wpa_printf(MSG_DEBUG, "%s: Drop duplicate RX", __func__); 2297f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt return; 2307f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt } 231de47be75037bccd4a11b62eedb3d4aed1b36fa67Dmitry Shmidt if (!l2->last_from_br_prev && 232de47be75037bccd4a11b62eedb3d4aed1b36fa67Dmitry Shmidt os_memcmp(hash, l2->last_hash_prev, SHA1_MAC_LEN) == 0) { 233de47be75037bccd4a11b62eedb3d4aed1b36fa67Dmitry Shmidt wpa_printf(MSG_DEBUG, "%s: Drop duplicate RX(prev)", __func__); 234de47be75037bccd4a11b62eedb3d4aed1b36fa67Dmitry Shmidt return; 235de47be75037bccd4a11b62eedb3d4aed1b36fa67Dmitry Shmidt } 236de47be75037bccd4a11b62eedb3d4aed1b36fa67Dmitry Shmidt os_memcpy(l2->last_hash_prev, l2->last_hash, SHA1_MAC_LEN); 237de47be75037bccd4a11b62eedb3d4aed1b36fa67Dmitry Shmidt l2->last_from_br_prev = l2->last_from_br; 2387f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt l2->last_from_br = 1; 2397f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt os_memcpy(l2->last_hash, hash, SHA1_MAC_LEN); 240216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt l2->rx_callback(l2->rx_callback_ctx, ll.sll_addr, buf, res); 2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 242d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt#endif /* CONFIG_NO_LINUX_PACKET_SOCKET_WAR */ 2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct l2_packet_data * l2_packet_init( 2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const char *ifname, const u8 *own_addr, unsigned short protocol, 2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt void (*rx_callback)(void *ctx, const u8 *src_addr, 2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *buf, size_t len), 2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt void *rx_callback_ctx, int l2_hdr) 2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 2518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct l2_packet_data *l2; 2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct ifreq ifr; 2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct sockaddr_ll ll; 2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt l2 = os_zalloc(sizeof(struct l2_packet_data)); 2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (l2 == NULL) 2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_strlcpy(l2->ifname, ifname, sizeof(l2->ifname)); 2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt l2->rx_callback = rx_callback; 2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt l2->rx_callback_ctx = rx_callback_ctx; 2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt l2->l2_hdr = l2_hdr; 262d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt#ifndef CONFIG_NO_LINUX_PACKET_SOCKET_WAR 263216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt l2->fd_br_rx = -1; 264d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt#endif /* CONFIG_NO_LINUX_PACKET_SOCKET_WAR */ 2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt l2->fd = socket(PF_PACKET, l2_hdr ? SOCK_RAW : SOCK_DGRAM, 2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt htons(protocol)); 2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (l2->fd < 0) { 2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "%s: socket(PF_PACKET): %s", 2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt __func__, strerror(errno)); 2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(l2); 2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memset(&ifr, 0, sizeof(ifr)); 2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_strlcpy(ifr.ifr_name, l2->ifname, sizeof(ifr.ifr_name)); 2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ioctl(l2->fd, SIOCGIFINDEX, &ifr) < 0) { 2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "%s: ioctl[SIOCGIFINDEX]: %s", 2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt __func__, strerror(errno)); 2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt close(l2->fd); 2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(l2); 2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt l2->ifindex = ifr.ifr_ifindex; 2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memset(&ll, 0, sizeof(ll)); 2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ll.sll_family = PF_PACKET; 2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ll.sll_ifindex = ifr.ifr_ifindex; 2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ll.sll_protocol = htons(protocol); 2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (bind(l2->fd, (struct sockaddr *) &ll, sizeof(ll)) < 0) { 2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "%s: bind[PF_PACKET]: %s", 2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt __func__, strerror(errno)); 2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt close(l2->fd); 2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(l2); 2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ioctl(l2->fd, SIOCGIFHWADDR, &ifr) < 0) { 2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "%s: ioctl[SIOCGIFHWADDR]: %s", 2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt __func__, strerror(errno)); 3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt close(l2->fd); 3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(l2); 3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(l2->own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN); 3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eloop_register_read_sock(l2->fd, l2_packet_receive, l2, NULL); 3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return l2; 3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 312216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidtstruct l2_packet_data * l2_packet_init_bridge( 313216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt const char *br_ifname, const char *ifname, const u8 *own_addr, 314216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt unsigned short protocol, 315216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt void (*rx_callback)(void *ctx, const u8 *src_addr, 316216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt const u8 *buf, size_t len), 317216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt void *rx_callback_ctx, int l2_hdr) 318216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt{ 319216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt struct l2_packet_data *l2; 320d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt#ifndef CONFIG_NO_LINUX_PACKET_SOCKET_WAR 321216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt struct sock_filter ethertype_sock_filter_insns[] = { 322216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt /* Load ethertype */ 323216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt BPF_STMT(BPF_LD | BPF_H | BPF_ABS, 2 * ETH_ALEN), 324216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt /* Jump over next statement if ethertype does not match */ 325216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, protocol, 0, 1), 326216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt /* Ethertype match - return all */ 327216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt BPF_STMT(BPF_RET | BPF_K, ~0), 328216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt /* No match - drop */ 329216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt BPF_STMT(BPF_RET | BPF_K, 0) 330216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt }; 331216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt const struct sock_fprog ethertype_sock_filter = { 332216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt .len = ARRAY_SIZE(ethertype_sock_filter_insns), 333216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt .filter = ethertype_sock_filter_insns, 334216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt }; 335216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt struct sockaddr_ll ll; 336d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt#endif /* CONFIG_NO_LINUX_PACKET_SOCKET_WAR */ 337216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt 338216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt l2 = l2_packet_init(br_ifname, own_addr, protocol, rx_callback, 339216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt rx_callback_ctx, l2_hdr); 340216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt if (!l2) 341216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt return NULL; 342216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt 343d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt#ifndef CONFIG_NO_LINUX_PACKET_SOCKET_WAR 344216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt /* 345216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt * The Linux packet socket behavior has changed over the years and there 346216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt * is an inconvenient regression in it that breaks RX for a specific 347216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt * protocol from interfaces in a bridge when that interface is not in 348216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt * fully operation state (i.e., when in station mode and not completed 349216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt * authorization). To work around this, register ETH_P_ALL version of 350216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt * the packet socket bound to the real netdev and use socket filter to 351216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt * match the ethertype value. This version is less efficient, but 352216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt * required for functionality with many kernel version. If the main 353216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt * packet socket is found to be working, this less efficient version 354216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt * gets closed automatically. 355216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt */ 356216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt 357216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt l2->fd_br_rx = socket(PF_PACKET, l2_hdr ? SOCK_RAW : SOCK_DGRAM, 358216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt htons(ETH_P_ALL)); 359216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt if (l2->fd_br_rx < 0) { 360216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt wpa_printf(MSG_DEBUG, "%s: socket(PF_PACKET-fd_br_rx): %s", 361216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt __func__, strerror(errno)); 362216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt /* try to continue without the workaround RX socket */ 363216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt return l2; 364216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt } 365216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt 366216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt os_memset(&ll, 0, sizeof(ll)); 367216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt ll.sll_family = PF_PACKET; 368216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt ll.sll_ifindex = if_nametoindex(ifname); 369216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt ll.sll_protocol = htons(ETH_P_ALL); 370216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt if (bind(l2->fd_br_rx, (struct sockaddr *) &ll, sizeof(ll)) < 0) { 371216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt wpa_printf(MSG_DEBUG, "%s: bind[PF_PACKET-fd_br_rx]: %s", 372216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt __func__, strerror(errno)); 373216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt /* try to continue without the workaround RX socket */ 374216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt close(l2->fd_br_rx); 375216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt l2->fd_br_rx = -1; 376216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt return l2; 377216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt } 378216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt 379216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt if (setsockopt(l2->fd_br_rx, SOL_SOCKET, SO_ATTACH_FILTER, 380216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt ðertype_sock_filter, sizeof(struct sock_fprog))) { 381216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt wpa_printf(MSG_DEBUG, 382216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt "l2_packet_linux: setsockopt(SO_ATTACH_FILTER) failed: %s", 383216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt strerror(errno)); 384216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt /* try to continue without the workaround RX socket */ 385216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt close(l2->fd_br_rx); 386216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt l2->fd_br_rx = -1; 387216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt return l2; 388216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt } 389216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt 390216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt eloop_register_read_sock(l2->fd_br_rx, l2_packet_receive_br, l2, NULL); 391d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt#endif /* CONFIG_NO_LINUX_PACKET_SOCKET_WAR */ 392216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt 393216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt return l2; 394216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt} 395216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt 396216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt 3978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid l2_packet_deinit(struct l2_packet_data *l2) 3988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 3998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (l2 == NULL) 4008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 4018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (l2->fd >= 0) { 4038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eloop_unregister_read_sock(l2->fd); 4048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt close(l2->fd); 4058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 406216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt 407d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt#ifndef CONFIG_NO_LINUX_PACKET_SOCKET_WAR 408216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt if (l2->fd_br_rx >= 0) { 409216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt eloop_unregister_read_sock(l2->fd_br_rx); 410216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt close(l2->fd_br_rx); 411216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt } 412d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt#endif /* CONFIG_NO_LINUX_PACKET_SOCKET_WAR */ 413216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt 4148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(l2); 4158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 4168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len) 4198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 4208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int s; 4218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct ifreq ifr; 4228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct sockaddr_in *saddr; 4238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t res; 4248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt s = socket(PF_INET, SOCK_DGRAM, 0); 4268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (s < 0) { 4278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "%s: socket: %s", 4288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt __func__, strerror(errno)); 4298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 4308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memset(&ifr, 0, sizeof(ifr)); 4328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_strlcpy(ifr.ifr_name, l2->ifname, sizeof(ifr.ifr_name)); 4338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ioctl(s, SIOCGIFADDR, &ifr) < 0) { 4348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (errno != EADDRNOTAVAIL) 4358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "%s: ioctl[SIOCGIFADDR]: %s", 4368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt __func__, strerror(errno)); 4378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt close(s); 4388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 4398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt close(s); 4418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt saddr = aliasing_hide_typecast(&ifr.ifr_addr, struct sockaddr_in); 4428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (saddr->sin_family != AF_INET) 4438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 4448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt res = os_strlcpy(buf, inet_ntoa(saddr->sin_addr), len); 4458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (res >= len) 4468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 4478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 4488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 4498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid l2_packet_notify_auth_start(struct l2_packet_data *l2) 4528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 4538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 4546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 4556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 4566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtint l2_packet_set_packet_filter(struct l2_packet_data *l2, 4576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt enum l2_packet_filter_type type) 4586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 4596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt const struct sock_fprog *sock_filter; 4606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 4616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt switch (type) { 4626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case L2_PACKET_FILTER_DHCP: 4636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt sock_filter = &dhcp_sock_filter; 4646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 4656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case L2_PACKET_FILTER_NDISC: 4666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt sock_filter = &ndisc_sock_filter; 4676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 4686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt default: 4696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return -1; 4706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 4716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 4726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (setsockopt(l2->fd, SOL_SOCKET, SO_ATTACH_FILTER, 4736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt sock_filter, sizeof(struct sock_fprog))) { 4746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_printf(MSG_ERROR, 4756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt "l2_packet_linux: setsockopt(SO_ATTACH_FILTER) failed: %s", 4766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt strerror(errno)); 4776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return -1; 4786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 4796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 4806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return 0; 4816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 482