1209139Srpaulo/* 2209139Srpaulo * WPA Supplicant - Layer2 packet handling with privilege separation 3209139Srpaulo * Copyright (c) 2007, Jouni Malinen <j@w1.fi> 4209139Srpaulo * 5252190Srpaulo * This software may be distributed under the terms of the BSD license. 6252190Srpaulo * See README for more details. 7209139Srpaulo */ 8209139Srpaulo 9209139Srpaulo#include "includes.h" 10209139Srpaulo#include <sys/un.h> 11209139Srpaulo 12209139Srpaulo#include "common.h" 13209139Srpaulo#include "eloop.h" 14209139Srpaulo#include "l2_packet.h" 15214501Srpaulo#include "common/privsep_commands.h" 16209139Srpaulo 17209139Srpaulo 18209139Srpaulostruct l2_packet_data { 19209139Srpaulo int fd; /* UNIX domain socket for privsep access */ 20209139Srpaulo void (*rx_callback)(void *ctx, const u8 *src_addr, 21209139Srpaulo const u8 *buf, size_t len); 22209139Srpaulo void *rx_callback_ctx; 23209139Srpaulo u8 own_addr[ETH_ALEN]; 24209139Srpaulo char *own_socket_path; 25209139Srpaulo struct sockaddr_un priv_addr; 26209139Srpaulo}; 27209139Srpaulo 28209139Srpaulo 29209139Srpaulostatic int wpa_priv_cmd(struct l2_packet_data *l2, int cmd, 30209139Srpaulo const void *data, size_t data_len) 31209139Srpaulo{ 32209139Srpaulo struct msghdr msg; 33209139Srpaulo struct iovec io[2]; 34209139Srpaulo 35209139Srpaulo io[0].iov_base = &cmd; 36209139Srpaulo io[0].iov_len = sizeof(cmd); 37209139Srpaulo io[1].iov_base = (u8 *) data; 38209139Srpaulo io[1].iov_len = data_len; 39209139Srpaulo 40209139Srpaulo os_memset(&msg, 0, sizeof(msg)); 41209139Srpaulo msg.msg_iov = io; 42209139Srpaulo msg.msg_iovlen = data ? 2 : 1; 43209139Srpaulo msg.msg_name = &l2->priv_addr; 44209139Srpaulo msg.msg_namelen = sizeof(l2->priv_addr); 45209139Srpaulo 46209139Srpaulo if (sendmsg(l2->fd, &msg, 0) < 0) { 47281806Srpaulo wpa_printf(MSG_ERROR, "L2: sendmsg(cmd): %s", strerror(errno)); 48209139Srpaulo return -1; 49209139Srpaulo } 50209139Srpaulo 51209139Srpaulo return 0; 52209139Srpaulo} 53209139Srpaulo 54346981Scy 55209139Srpauloint l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr) 56209139Srpaulo{ 57209139Srpaulo os_memcpy(addr, l2->own_addr, ETH_ALEN); 58209139Srpaulo return 0; 59209139Srpaulo} 60209139Srpaulo 61209139Srpaulo 62209139Srpauloint l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto, 63209139Srpaulo const u8 *buf, size_t len) 64209139Srpaulo{ 65209139Srpaulo struct msghdr msg; 66209139Srpaulo struct iovec io[4]; 67209139Srpaulo int cmd = PRIVSEP_CMD_L2_SEND; 68209139Srpaulo 69209139Srpaulo io[0].iov_base = &cmd; 70209139Srpaulo io[0].iov_len = sizeof(cmd); 71209139Srpaulo io[1].iov_base = &dst_addr; 72209139Srpaulo io[1].iov_len = ETH_ALEN; 73209139Srpaulo io[2].iov_base = &proto; 74209139Srpaulo io[2].iov_len = 2; 75209139Srpaulo io[3].iov_base = (u8 *) buf; 76209139Srpaulo io[3].iov_len = len; 77209139Srpaulo 78209139Srpaulo os_memset(&msg, 0, sizeof(msg)); 79209139Srpaulo msg.msg_iov = io; 80209139Srpaulo msg.msg_iovlen = 4; 81209139Srpaulo msg.msg_name = &l2->priv_addr; 82209139Srpaulo msg.msg_namelen = sizeof(l2->priv_addr); 83209139Srpaulo 84209139Srpaulo if (sendmsg(l2->fd, &msg, 0) < 0) { 85281806Srpaulo wpa_printf(MSG_ERROR, "L2: sendmsg(packet_send): %s", 86281806Srpaulo strerror(errno)); 87209139Srpaulo return -1; 88209139Srpaulo } 89209139Srpaulo 90209139Srpaulo return 0; 91209139Srpaulo} 92209139Srpaulo 93209139Srpaulo 94209139Srpaulostatic void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx) 95209139Srpaulo{ 96209139Srpaulo struct l2_packet_data *l2 = eloop_ctx; 97209139Srpaulo u8 buf[2300]; 98209139Srpaulo int res; 99209139Srpaulo struct sockaddr_un from; 100209139Srpaulo socklen_t fromlen = sizeof(from); 101209139Srpaulo 102209139Srpaulo os_memset(&from, 0, sizeof(from)); 103209139Srpaulo res = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *) &from, 104209139Srpaulo &fromlen); 105209139Srpaulo if (res < 0) { 106281806Srpaulo wpa_printf(MSG_ERROR, "l2_packet_receive - recvfrom: %s", 107281806Srpaulo strerror(errno)); 108209139Srpaulo return; 109209139Srpaulo } 110209139Srpaulo if (res < ETH_ALEN) { 111209139Srpaulo wpa_printf(MSG_DEBUG, "L2: Too show packet received"); 112209139Srpaulo return; 113209139Srpaulo } 114209139Srpaulo 115209139Srpaulo if (from.sun_family != AF_UNIX || 116209139Srpaulo os_strncmp(from.sun_path, l2->priv_addr.sun_path, 117209139Srpaulo sizeof(from.sun_path)) != 0) { 118209139Srpaulo wpa_printf(MSG_DEBUG, "L2: Received message from unexpected " 119209139Srpaulo "source"); 120209139Srpaulo return; 121209139Srpaulo } 122209139Srpaulo 123209139Srpaulo l2->rx_callback(l2->rx_callback_ctx, buf, buf + ETH_ALEN, 124209139Srpaulo res - ETH_ALEN); 125209139Srpaulo} 126209139Srpaulo 127209139Srpaulo 128209139Srpaulostruct l2_packet_data * l2_packet_init( 129209139Srpaulo const char *ifname, const u8 *own_addr, unsigned short protocol, 130209139Srpaulo void (*rx_callback)(void *ctx, const u8 *src_addr, 131209139Srpaulo const u8 *buf, size_t len), 132209139Srpaulo void *rx_callback_ctx, int l2_hdr) 133209139Srpaulo{ 134209139Srpaulo struct l2_packet_data *l2; 135209139Srpaulo char *own_dir = "/tmp"; 136209139Srpaulo char *priv_dir = "/var/run/wpa_priv"; 137209139Srpaulo size_t len; 138209139Srpaulo static unsigned int counter = 0; 139209139Srpaulo struct sockaddr_un addr; 140209139Srpaulo fd_set rfds; 141209139Srpaulo struct timeval tv; 142209139Srpaulo int res; 143209139Srpaulo u8 reply[ETH_ALEN + 1]; 144209139Srpaulo int reg_cmd[2]; 145209139Srpaulo 146209139Srpaulo l2 = os_zalloc(sizeof(struct l2_packet_data)); 147209139Srpaulo if (l2 == NULL) 148209139Srpaulo return NULL; 149209139Srpaulo l2->rx_callback = rx_callback; 150209139Srpaulo l2->rx_callback_ctx = rx_callback_ctx; 151209139Srpaulo 152209139Srpaulo len = os_strlen(own_dir) + 50; 153209139Srpaulo l2->own_socket_path = os_malloc(len); 154209139Srpaulo if (l2->own_socket_path == NULL) { 155209139Srpaulo os_free(l2); 156209139Srpaulo return NULL; 157209139Srpaulo } 158209139Srpaulo os_snprintf(l2->own_socket_path, len, "%s/wpa_privsep-l2-%d-%d", 159209139Srpaulo own_dir, getpid(), counter++); 160209139Srpaulo 161209139Srpaulo l2->priv_addr.sun_family = AF_UNIX; 162209139Srpaulo os_snprintf(l2->priv_addr.sun_path, sizeof(l2->priv_addr.sun_path), 163209139Srpaulo "%s/%s", priv_dir, ifname); 164209139Srpaulo 165209139Srpaulo l2->fd = socket(PF_UNIX, SOCK_DGRAM, 0); 166209139Srpaulo if (l2->fd < 0) { 167281806Srpaulo wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno)); 168209139Srpaulo os_free(l2->own_socket_path); 169209139Srpaulo l2->own_socket_path = NULL; 170209139Srpaulo os_free(l2); 171209139Srpaulo return NULL; 172209139Srpaulo } 173209139Srpaulo 174209139Srpaulo os_memset(&addr, 0, sizeof(addr)); 175209139Srpaulo addr.sun_family = AF_UNIX; 176209139Srpaulo os_strlcpy(addr.sun_path, l2->own_socket_path, sizeof(addr.sun_path)); 177209139Srpaulo if (bind(l2->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 178281806Srpaulo wpa_printf(MSG_ERROR, "l2-pkt-privsep: bind(PF_UNIX): %s", 179281806Srpaulo strerror(errno)); 180209139Srpaulo goto fail; 181209139Srpaulo } 182209139Srpaulo 183209139Srpaulo reg_cmd[0] = protocol; 184209139Srpaulo reg_cmd[1] = l2_hdr; 185209139Srpaulo if (wpa_priv_cmd(l2, PRIVSEP_CMD_L2_REGISTER, reg_cmd, sizeof(reg_cmd)) 186209139Srpaulo < 0) { 187209139Srpaulo wpa_printf(MSG_ERROR, "L2: Failed to register with wpa_priv"); 188209139Srpaulo goto fail; 189209139Srpaulo } 190209139Srpaulo 191209139Srpaulo FD_ZERO(&rfds); 192209139Srpaulo FD_SET(l2->fd, &rfds); 193209139Srpaulo tv.tv_sec = 5; 194209139Srpaulo tv.tv_usec = 0; 195209139Srpaulo res = select(l2->fd + 1, &rfds, NULL, NULL, &tv); 196209139Srpaulo if (res < 0 && errno != EINTR) { 197281806Srpaulo wpa_printf(MSG_ERROR, "select: %s", strerror(errno)); 198209139Srpaulo goto fail; 199209139Srpaulo } 200209139Srpaulo 201209139Srpaulo if (FD_ISSET(l2->fd, &rfds)) { 202209139Srpaulo res = recv(l2->fd, reply, sizeof(reply), 0); 203209139Srpaulo if (res < 0) { 204281806Srpaulo wpa_printf(MSG_ERROR, "recv: %s", strerror(errno)); 205209139Srpaulo goto fail; 206209139Srpaulo } 207209139Srpaulo } else { 208209139Srpaulo wpa_printf(MSG_DEBUG, "L2: Timeout while waiting for " 209209139Srpaulo "registration reply"); 210209139Srpaulo goto fail; 211209139Srpaulo } 212209139Srpaulo 213209139Srpaulo if (res != ETH_ALEN) { 214209139Srpaulo wpa_printf(MSG_DEBUG, "L2: Unexpected registration reply " 215209139Srpaulo "(len=%d)", res); 216209139Srpaulo } 217209139Srpaulo os_memcpy(l2->own_addr, reply, ETH_ALEN); 218209139Srpaulo 219209139Srpaulo eloop_register_read_sock(l2->fd, l2_packet_receive, l2, NULL); 220209139Srpaulo 221209139Srpaulo return l2; 222209139Srpaulo 223209139Srpaulofail: 224209139Srpaulo close(l2->fd); 225209139Srpaulo l2->fd = -1; 226209139Srpaulo unlink(l2->own_socket_path); 227209139Srpaulo os_free(l2->own_socket_path); 228209139Srpaulo l2->own_socket_path = NULL; 229209139Srpaulo os_free(l2); 230209139Srpaulo return NULL; 231209139Srpaulo} 232209139Srpaulo 233209139Srpaulo 234281806Srpaulostruct l2_packet_data * l2_packet_init_bridge( 235281806Srpaulo const char *br_ifname, const char *ifname, const u8 *own_addr, 236281806Srpaulo unsigned short protocol, 237281806Srpaulo void (*rx_callback)(void *ctx, const u8 *src_addr, 238281806Srpaulo const u8 *buf, size_t len), 239281806Srpaulo void *rx_callback_ctx, int l2_hdr) 240281806Srpaulo{ 241281806Srpaulo return l2_packet_init(br_ifname, own_addr, protocol, rx_callback, 242281806Srpaulo rx_callback_ctx, l2_hdr); 243281806Srpaulo} 244281806Srpaulo 245281806Srpaulo 246209139Srpaulovoid l2_packet_deinit(struct l2_packet_data *l2) 247209139Srpaulo{ 248209139Srpaulo if (l2 == NULL) 249209139Srpaulo return; 250209139Srpaulo 251209139Srpaulo if (l2->fd >= 0) { 252209139Srpaulo wpa_priv_cmd(l2, PRIVSEP_CMD_L2_UNREGISTER, NULL, 0); 253209139Srpaulo eloop_unregister_read_sock(l2->fd); 254209139Srpaulo close(l2->fd); 255209139Srpaulo } 256209139Srpaulo 257209139Srpaulo if (l2->own_socket_path) { 258209139Srpaulo unlink(l2->own_socket_path); 259209139Srpaulo os_free(l2->own_socket_path); 260209139Srpaulo } 261346981Scy 262209139Srpaulo os_free(l2); 263209139Srpaulo} 264209139Srpaulo 265209139Srpaulo 266209139Srpauloint l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len) 267209139Srpaulo{ 268209139Srpaulo /* TODO */ 269209139Srpaulo return -1; 270209139Srpaulo} 271209139Srpaulo 272209139Srpaulo 273209139Srpaulovoid l2_packet_notify_auth_start(struct l2_packet_data *l2) 274209139Srpaulo{ 275209139Srpaulo wpa_priv_cmd(l2, PRIVSEP_CMD_L2_NOTIFY_AUTH_START, NULL, 0); 276209139Srpaulo} 277281806Srpaulo 278281806Srpaulo 279281806Srpauloint l2_packet_set_packet_filter(struct l2_packet_data *l2, 280281806Srpaulo enum l2_packet_filter_type type) 281281806Srpaulo{ 282281806Srpaulo return -1; 283281806Srpaulo} 284