LCOV - code coverage report
Current view: top level - src/ap - dhcp_snoop.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1443382998 Lines: 69 75 92.0 %
Date: 2015-09-27 Functions: 4 4 100.0 %

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

Generated by: LCOV version 1.10