1fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt/* 2fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * DHCP snooping for Proxy ARP 3fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * Copyright (c) 2014, Qualcomm Atheros, Inc. 4fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * 5fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * This software may be distributed under the terms of the BSD license. 6fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * See README for more details. 7fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt */ 8fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 9fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt#include "utils/includes.h" 10fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 11fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt#include "utils/common.h" 12ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt#include "common/dhcp.h" 13fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt#include "l2_packet/l2_packet.h" 14fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt#include "hostapd.h" 15fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt#include "sta_info.h" 16fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt#include "ap_drv_ops.h" 17fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt#include "x_snoop.h" 18fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt#include "dhcp_snoop.h" 19fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 20fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 21aff761db795db8b506c6f6af7ff607856cf85a81Dmitry Shmidtstatic const char * ipaddr_str(u32 addr) 22aff761db795db8b506c6f6af7ff607856cf85a81Dmitry Shmidt{ 23aff761db795db8b506c6f6af7ff607856cf85a81Dmitry Shmidt static char buf[17]; 24aff761db795db8b506c6f6af7ff607856cf85a81Dmitry Shmidt 25aff761db795db8b506c6f6af7ff607856cf85a81Dmitry Shmidt os_snprintf(buf, sizeof(buf), "%u.%u.%u.%u", 26aff761db795db8b506c6f6af7ff607856cf85a81Dmitry Shmidt (addr >> 24) & 0xff, (addr >> 16) & 0xff, 27aff761db795db8b506c6f6af7ff607856cf85a81Dmitry Shmidt (addr >> 8) & 0xff, addr & 0xff); 28aff761db795db8b506c6f6af7ff607856cf85a81Dmitry Shmidt return buf; 29aff761db795db8b506c6f6af7ff607856cf85a81Dmitry Shmidt} 30aff761db795db8b506c6f6af7ff607856cf85a81Dmitry Shmidt 31aff761db795db8b506c6f6af7ff607856cf85a81Dmitry Shmidt 32fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtstatic void handle_dhcp(void *ctx, const u8 *src_addr, const u8 *buf, 33fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt size_t len) 34fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt{ 35fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt struct hostapd_data *hapd = ctx; 36fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt const struct bootp_pkt *b; 37fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt struct sta_info *sta; 38fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt int exten_len; 39fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt const u8 *end, *pos; 40fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt int res, msgtype = 0, prefixlen = 32; 41fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt u32 subnet_mask = 0; 42fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt u16 tot_len; 43fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 44fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt exten_len = len - ETH_HLEN - (sizeof(*b) - sizeof(b->exten)); 45fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (exten_len < 4) 46fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return; 47fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 48fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt b = (const struct bootp_pkt *) &buf[ETH_HLEN]; 49fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt tot_len = ntohs(b->iph.tot_len); 50fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (tot_len > (unsigned int) (len - ETH_HLEN)) 51fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return; 52fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 53ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt if (WPA_GET_BE32(b->exten) != DHCP_MAGIC) 54fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return; 55fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 56fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt /* Parse DHCP options */ 57fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt end = (const u8 *) b + tot_len; 58fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt pos = &b->exten[4]; 59ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt while (pos < end && *pos != DHCP_OPT_END) { 60fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt const u8 *opt = pos++; 61fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 62ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt if (*opt == DHCP_OPT_PAD) 63fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt continue; 64fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 65ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt if (pos >= end || 1 + *pos > end - pos) 66ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt break; 67fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt pos += *pos + 1; 68fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (pos >= end) 69fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt break; 70fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 71fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt switch (*opt) { 72ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt case DHCP_OPT_SUBNET_MASK: 73fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (opt[1] == 4) 74fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt subnet_mask = WPA_GET_BE32(&opt[2]); 75fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (subnet_mask == 0) 76fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return; 77fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt while (!(subnet_mask & 0x1)) { 78fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt subnet_mask >>= 1; 79fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt prefixlen--; 80fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 81fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt break; 82ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt case DHCP_OPT_MSG_TYPE: 83fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (opt[1]) 84fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt msgtype = opt[2]; 85fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt break; 86fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt default: 87fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt break; 88fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 89fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 90fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 91fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (msgtype == DHCPACK) { 92fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (b->your_ip == 0) 93fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return; 94fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 95fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt /* DHCPACK for DHCPREQUEST */ 96fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt sta = ap_get_sta(hapd, b->hw_addr); 97fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (!sta) 98fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return; 99fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 100fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, "dhcp_snoop: Found DHCPACK for " MACSTR 101aff761db795db8b506c6f6af7ff607856cf85a81Dmitry Shmidt " @ IPv4 address %s/%d", 1024ae50e65ef0eefe6d5c356acbc1839f8eac68af5Dmitry Shmidt MAC2STR(sta->addr), 1034ae50e65ef0eefe6d5c356acbc1839f8eac68af5Dmitry Shmidt ipaddr_str(be_to_host32(b->your_ip)), 104aff761db795db8b506c6f6af7ff607856cf85a81Dmitry Shmidt prefixlen); 105fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 106fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (sta->ipaddr == b->your_ip) 107fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return; 108fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 109fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (sta->ipaddr != 0) { 110fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, 111aff761db795db8b506c6f6af7ff607856cf85a81Dmitry Shmidt "dhcp_snoop: Removing IPv4 address %s from the ip neigh table", 112aff761db795db8b506c6f6af7ff607856cf85a81Dmitry Shmidt ipaddr_str(be_to_host32(sta->ipaddr))); 113fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt hostapd_drv_br_delete_ip_neigh(hapd, 4, 114fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt (u8 *) &sta->ipaddr); 115fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 116fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 117fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt res = hostapd_drv_br_add_ip_neigh(hapd, 4, (u8 *) &b->your_ip, 118fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt prefixlen, sta->addr); 119fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (res) { 120fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, 121fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt "dhcp_snoop: Adding ip neigh table failed: %d", 122fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt res); 123fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return; 124fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 125fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt sta->ipaddr = b->your_ip; 126fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 127fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 128fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (hapd->conf->disable_dgaf && is_broadcast_ether_addr(buf)) { 129fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt for (sta = hapd->sta_list; sta; sta = sta->next) { 130fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (!(sta->flags & WLAN_STA_AUTHORIZED)) 131fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt continue; 132fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt x_snoop_mcast_to_ucast_convert_send(hapd, sta, 133fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt (u8 *) buf, len); 134fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 135fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 136fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt} 137fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 138fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 139fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtint dhcp_snoop_init(struct hostapd_data *hapd) 140fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt{ 141fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt hapd->sock_dhcp = x_snoop_get_l2_packet(hapd, handle_dhcp, 142fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt L2_PACKET_FILTER_DHCP); 143fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (hapd->sock_dhcp == NULL) { 144fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, 145fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt "dhcp_snoop: Failed to initialize L2 packet processing for DHCP packet: %s", 146fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt strerror(errno)); 147fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return -1; 148fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 149fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 150fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return 0; 151fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt} 152fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 153fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 154fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtvoid dhcp_snoop_deinit(struct hostapd_data *hapd) 155fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt{ 156fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt l2_packet_deinit(hapd->sock_dhcp); 157fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt} 158