1d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt/* 2d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt * hostapd / IEEE 802 OUI Extended EtherType 88-B7 3d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt * Copyright (c) 2016, Jouni Malinen <j@w1.fi> 4d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt * 5d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt * This software may be distributed under the terms of the BSD license. 6d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt * See README for more details. 7d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt */ 8d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt 9d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt#include "utils/includes.h" 10d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt 11d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt#include "utils/common.h" 12d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt#include "utils/eloop.h" 13d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt#include "l2_packet/l2_packet.h" 14d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt#include "hostapd.h" 15d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt#include "eth_p_oui.h" 16d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt 17d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt/* 18d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt * See IEEE Std 802-2014, Clause 9.2.4 for the definition of the OUI Extended 19d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt * EtherType 88-B7. This file implements this with OUI 00:13:74 and 20d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt * vendor-specific subtype 0x0001. 21d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt */ 22d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidtstatic const u8 global_oui[] = { 0x00, 0x13, 0x74, 0x00, 0x01 }; 23d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt 24d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidtstruct eth_p_oui_iface { 25d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt struct dl_list list; 26d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt char ifname[IFNAMSIZ + 1]; 27d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt struct l2_packet_data *l2; 28d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt struct dl_list receiver; 29d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt}; 30d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt 31d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidtstruct eth_p_oui_ctx { 32d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt struct dl_list list; 33d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt struct eth_p_oui_iface *iface; 34d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt /* all data needed to deliver and unregister */ 35d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt u8 oui_suffix; /* last byte of OUI */ 36d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt void (*rx_callback)(void *ctx, const u8 *src_addr, 37d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt const u8 *dst_addr, u8 oui_suffix, 38d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt const u8 *buf, size_t len); 39d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt void *rx_callback_ctx; 40d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt}; 41d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt 42d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt 43d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidtvoid eth_p_oui_deliver(struct eth_p_oui_ctx *ctx, const u8 *src_addr, 44d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt const u8 *dst_addr, const u8 *buf, size_t len) 45d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt{ 46d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt ctx->rx_callback(ctx->rx_callback_ctx, src_addr, dst_addr, 47d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt ctx->oui_suffix, buf, len); 48d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt} 49d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt 50d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt 51d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidtstatic void eth_p_rx(void *ctx, const u8 *src_addr, const u8 *buf, size_t len) 52d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt{ 53d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt struct eth_p_oui_iface *iface = ctx; 54d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt struct eth_p_oui_ctx *receiver; 55d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt const struct l2_ethhdr *ethhdr; 56d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt 57d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt if (len < sizeof(*ethhdr) + sizeof(global_oui) + 1) { 58d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt /* too short packet */ 59d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt return; 60d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt } 61d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt 62d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt ethhdr = (struct l2_ethhdr *) buf; 63d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt /* trim eth_hdr from buf and len */ 64d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt buf += sizeof(*ethhdr); 65d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt len -= sizeof(*ethhdr); 66d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt 67d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt /* verify OUI and vendor-specific subtype match */ 68d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt if (os_memcmp(buf, global_oui, sizeof(global_oui)) != 0) 69d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt return; 70d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt buf += sizeof(global_oui); 71d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt len -= sizeof(global_oui); 72d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt 73d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt dl_list_for_each(receiver, &iface->receiver, 74d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt struct eth_p_oui_ctx, list) { 75d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt if (buf[0] != receiver->oui_suffix) 76d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt continue; 77d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt 78d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt eth_p_oui_deliver(receiver, ethhdr->h_source, ethhdr->h_dest, 79d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt buf + 1, len - 1); 80d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt } 81d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt} 82d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt 83d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt 84d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidtstruct eth_p_oui_ctx * 85d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidteth_p_oui_register(struct hostapd_data *hapd, const char *ifname, u8 oui_suffix, 86d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt void (*rx_callback)(void *ctx, const u8 *src_addr, 87d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt const u8 *dst_addr, u8 oui_suffix, 88d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt const u8 *buf, size_t len), 89d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt void *rx_callback_ctx) 90d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt{ 91d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt struct eth_p_oui_iface *iface; 92d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt struct eth_p_oui_ctx *receiver; 93d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt int found = 0; 94d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt struct hapd_interfaces *interfaces; 95d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt 96d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt receiver = os_zalloc(sizeof(*receiver)); 97d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt if (!receiver) 98d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt goto err; 99d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt 100d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt receiver->oui_suffix = oui_suffix; 101d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt receiver->rx_callback = rx_callback; 102d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt receiver->rx_callback_ctx = rx_callback_ctx; 103d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt 104d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt interfaces = hapd->iface->interfaces; 105d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt 106d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt dl_list_for_each(iface, &interfaces->eth_p_oui, struct eth_p_oui_iface, 107d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt list) { 108d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt if (os_strcmp(iface->ifname, ifname) != 0) 109d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt continue; 110d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt found = 1; 111d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt break; 112d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt } 113d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt 114d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt if (!found) { 115d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt iface = os_zalloc(sizeof(*iface)); 116d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt if (!iface) 117d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt goto err; 118d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt 119d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt os_strlcpy(iface->ifname, ifname, sizeof(iface->ifname)); 120d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt iface->l2 = l2_packet_init(ifname, NULL, ETH_P_OUI, eth_p_rx, 121d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt iface, 1); 122d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt if (!iface->l2) { 123d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt os_free(iface); 124d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt goto err; 125d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt } 126d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt dl_list_init(&iface->receiver); 127d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt 128d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt dl_list_add_tail(&interfaces->eth_p_oui, &iface->list); 129d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt } 130d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt 131d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt dl_list_add_tail(&iface->receiver, &receiver->list); 132d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt receiver->iface = iface; 133d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt 134d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt return receiver; 135d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidterr: 136d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt os_free(receiver); 137d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt return NULL; 138d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt} 139d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt 140d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt 141d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidtvoid eth_p_oui_unregister(struct eth_p_oui_ctx *ctx) 142d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt{ 143d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt struct eth_p_oui_iface *iface; 144d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt 145d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt if (!ctx) 146d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt return; 147d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt 148d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt iface = ctx->iface; 149d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt 150d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt dl_list_del(&ctx->list); 151d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt os_free(ctx); 152d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt 153d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt if (dl_list_empty(&iface->receiver)) { 154d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt dl_list_del(&iface->list); 155d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt l2_packet_deinit(iface->l2); 156d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt os_free(iface); 157d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt } 158d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt} 159d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt 160d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt 161d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidtint eth_p_oui_send(struct eth_p_oui_ctx *ctx, const u8 *src_addr, 162d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt const u8 *dst_addr, const u8 *buf, size_t len) 163d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt{ 164d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt struct eth_p_oui_iface *iface = ctx->iface; 165d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt u8 *packet, *p; 166d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt size_t packet_len; 167d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt int ret; 168d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt struct l2_ethhdr *ethhdr; 169d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt 170d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt packet_len = sizeof(*ethhdr) + sizeof(global_oui) + 1 + len; 171d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt packet = os_zalloc(packet_len); 172d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt if (!packet) 173d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt return -1; 174d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt p = packet; 175d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt 176d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt ethhdr = (struct l2_ethhdr *) packet; 177d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt os_memcpy(ethhdr->h_source, src_addr, ETH_ALEN); 178d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt os_memcpy(ethhdr->h_dest, dst_addr, ETH_ALEN); 179d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt ethhdr->h_proto = host_to_be16(ETH_P_OUI); 180d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt p += sizeof(*ethhdr); 181d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt 182d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt os_memcpy(p, global_oui, sizeof(global_oui)); 183d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt p[sizeof(global_oui)] = ctx->oui_suffix; 184d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt p += sizeof(global_oui) + 1; 185d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt 186d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt os_memcpy(p, buf, len); 187d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt 188d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt ret = l2_packet_send(iface->l2, NULL, 0, packet, packet_len); 189d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt os_free(packet); 190d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt return ret; 191d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt} 192