blob: 74ea30b1821248b76ca402b64a2388c1a6942151 [file] [log] [blame]
Ankita Bajaj1bde7942018-01-09 19:15:01 +05301/*
2 * Sigma Control API DUT (station/AP)
3 * Copyright (c) 2018, The Linux Foundation
4 * All Rights Reserved.
5 * Licensed under the Clear BSD license. See README for more details.
6 */
7
8#include "sigma_dut.h"
9#include "wpa_helpers.h"
10#include <netinet/if_ether.h>
11#include <netinet/ip.h>
12#include <netinet/udp.h>
13#include <pcap.h>
14#include <signal.h>
15
16#define DHCP_SERVER_PORT 67
17#define DHCP_CLIENT_PORT 68
18#define DHCP_ACK 5
19
20#define UDP_PROTOCOL 17
21
22static pcap_t *pcap = NULL;
23
24struct dhcp_pkt {
25 struct iphdr iph;
26 struct udphdr udph;
27 u8 op;
28 u8 htype;
29 u8 hlen;
30 u8 hops;
31 u32 xid;
32 u16 secs;
33 u16 flags;
34 u32 client_ip;
35 u32 your_ip;
36 u32 server_ip;
37 u32 relay_ip;
38 u8 hw_addr[16];
39 u8 serv_name[64];
40 u8 boot_file[128];
41 u32 magic_cookie;
42 u8 options[314];
43} __attribute__ ((packed));
44
45enum dhcp_options {
46 DHCP_OPT_SUBNET_MASK = 1,
47 DHCP_OPT_ROUTER = 3,
48 DHCP_OPT_MSG_TYPE = 53,
49 DHCP_OPT_END = 255
50};
51
52
53static u8 * get_dhcp_option(u8 *options, u8 type, int len)
54{
55 u8 *pos = options;
56 u8 *end = pos + len;
57
58 while (pos < end && pos + 1 < end && pos + 2 + pos[1] <= end) {
59 if (*pos == type)
60 return pos;
61 pos += 2 + pos[1];
62 }
63 return NULL;
64}
65
66
67/**
68 * 1. Open UDP socket
69 * 2. read_msg
70 * 3. Process DHCP_ACK
71 */
72static void * process_dhcp_ack(void *ptr)
73{
74 struct bpf_program pcap_fp;
75 char pcap_filter[200], pcap_err[PCAP_ERRBUF_SIZE];
76 struct sigma_dut *dut = ptr;
77 int nbytes = 0;
78 u8 buf[1024];
79 struct dhcp_pkt *dhcp;
80 int option_len;
81 u8 *msg_type, *val;
82 struct in_addr ip;
83 char your_ip[16], mask[16], router[16];
84 unsigned short protocol, port_no;
85 bpf_u_int32 pcap_maskp, pcap_netp;
86 char ifname[20];
87
88 protocol = UDP_PROTOCOL;
89 port_no = DHCP_SERVER_PORT;
90
91 strlcpy(ifname, get_main_ifname(), sizeof(ifname));
92
93 /* gives the network mask for ifname essential for applying filter */
94 pcap_lookupnet(ifname, &pcap_netp, &pcap_maskp, pcap_err);
95
96 sigma_dut_print(dut, DUT_MSG_INFO, "DHCP: ifname = %s", ifname);
97
98 /* creates a session for sniffing */
99 pcap = pcap_open_live(ifname, 2500, 0, 10, pcap_err);
100 if (!pcap)
101 sigma_dut_print(dut, DUT_MSG_INFO, "pcap_open_live: %s",
102 pcap_err);
103
104 snprintf(pcap_filter, sizeof(pcap_filter),
105 "ip proto 0x%x and udp src port 0x%x",
106 protocol, port_no);
107 sigma_dut_print(dut, DUT_MSG_INFO, "pcap_flter %s", pcap_filter);
108
109 if (pcap_compile(pcap, &pcap_fp, pcap_filter, 1, pcap_netp) < 0)
110 sigma_dut_print(dut, DUT_MSG_INFO, "pcap_compile: %s",
111 pcap_geterr(pcap));
112
113 if (pcap_setfilter(pcap, &pcap_fp) < 0)
114 sigma_dut_print(dut, DUT_MSG_INFO, "pcap_setfilter: %s",
115 pcap_geterr(pcap));
116
117 pcap_freecode(&pcap_fp);
118
119 while (1) {
120 memset(buf, 0, sizeof(buf));
121 sigma_dut_print(dut, DUT_MSG_DEBUG,
122 "HLP: Waiting for message to receive");
123 nbytes = recvfrom(pcap_get_selectable_fd(pcap), &buf,
124 sizeof(buf), 0, NULL, NULL);
125 if (nbytes == -1) {
126 sigma_dut_print(dut, DUT_MSG_ERROR, "HLP: failed: %s",
127 strerror(errno));
128 goto exit;
129 }
130
131 sigma_dut_print(dut, DUT_MSG_INFO, "HLP: Received %d bytes",
132 nbytes);
133 hex_dump(dut, buf, nbytes);
134
135 if (nbytes < 314) {
136 sigma_dut_print(dut, DUT_MSG_DEBUG,
137 "HLP: Ignore MSG, Too short message received");
138 continue;
139 }
140 nbytes -= 14;
141
142 /*
143 * Process DHCP packet
144 * skip ethernet header from buf and then process the ack
145 */
146 dhcp = (struct dhcp_pkt *) (buf + ETH_HLEN);
147
148 option_len = nbytes - ((char *) dhcp->options - (char *) dhcp);
149
150 sigma_dut_print(dut, DUT_MSG_DEBUG,
151 "option_len %d, First option : %02x",
152 option_len, *(dhcp->options));
153
154 /* Check for DHCP_ACK */
155 msg_type = get_dhcp_option(dhcp->options, DHCP_OPT_MSG_TYPE,
156 option_len);
157 if (!msg_type) {
158 sigma_dut_print(dut, DUT_MSG_ERROR,
159 "Ignore MSG, DHCP OPT MSG_TYPE missing");
160 continue;
161 }
162
163 if (msg_type[2] != DHCP_ACK) {
164 sigma_dut_print(dut, DUT_MSG_ERROR,
165 "Ignore MSG, DHCP message type : %02x",
166 msg_type[2]);
167 continue;
168 }
169
170 ip.s_addr = dhcp->your_ip;
171 strlcpy(your_ip, inet_ntoa(ip), sizeof(your_ip));
172
173 val = get_dhcp_option(dhcp->options, DHCP_OPT_SUBNET_MASK,
174 option_len);
175 if (!val) {
176 sigma_dut_print(dut, DUT_MSG_ERROR,
177 "DHCP option SUBNET_MASK missing");
178 continue;
179 }
180
181 memcpy(&(ip.s_addr), (val + 2), val[1]);
182 strlcpy(mask, inet_ntoa(ip), sizeof(mask));
183
184 val = get_dhcp_option(dhcp->options, DHCP_OPT_ROUTER,
185 option_len);
186 if (!val) {
187 sigma_dut_print(dut, DUT_MSG_ERROR,
188 "DHCP option DHCP_OPT_ROUTER missing");
189 continue;
190 }
191 memcpy(&(ip.s_addr), val + 2, val[1]);
192 strlcpy(router, inet_ntoa(ip), sizeof(router));
193
194 sigma_dut_print(dut, DUT_MSG_DEBUG,
195 "OP: %d, your_ip: %s, netmask: %s, router: %s",
196 dhcp->op, your_ip, mask, router);
197 /* set ip configuration */
198 if (!set_ipv4_addr(dut, ifname, your_ip, mask)) {
199 sigma_dut_print(dut, DUT_MSG_ERROR,
200 "Failed to set IP address");
201 continue;
202 }
203 if (set_ipv4_gw(dut, router) < 1) {
204 sigma_dut_print(dut, DUT_MSG_ERROR,
205 "Failed to set Gateway address");
206 continue;
207 }
208
209 sigma_dut_print(dut, DUT_MSG_DEBUG,
210 "IP configuration completed");
211 }
212
213exit:
214 sigma_dut_print(dut, DUT_MSG_INFO, "HLP: Received failed in exit");
215 if (pcap) {
216 pcap_close(pcap);
217 pcap = NULL;
218 }
219 dut->hlp_thread = 0;
220 return NULL;
221}
222
223
224static void hlp_thread_exit(int signum)
225{
226 pthread_exit(0);
227}
228
229
230void hlp_thread_cleanup(struct sigma_dut *dut)
231{
232 if (pcap) {
233 pcap_close(pcap);
234 pcap = NULL;
235 }
236 if (dut->hlp_thread) {
237 sigma_dut_print(dut, DUT_MSG_DEBUG, "Kill thread: %ld",
238 dut->hlp_thread);
239 pthread_kill(dut->hlp_thread, SIGUSR1);
240 dut->hlp_thread = 0;
241 }
242}
243
244
245void process_fils_hlp(struct sigma_dut *dut)
246{
247 static pthread_t hlp_thread;
248
249 if (dut->hlp_thread) {
250 sigma_dut_print(dut, DUT_MSG_ERROR,
251 "FILS-HLP DHCP thread already running");
252 return;
253 }
254
255 signal(SIGUSR1, hlp_thread_exit);
256
257 sigma_dut_print(dut, DUT_MSG_DEBUG, "Creating FILS_HLP thread-->");
258
259 /* create FILS_HLP thread */
260 if (!pthread_create(&hlp_thread, NULL, &process_dhcp_ack,
261 (void *) dut)) {
262 dut->hlp_thread = hlp_thread;
263 } else {
264 sigma_dut_print(dut, DUT_MSG_DEBUG,
265 "FILS_HLP thread creation failed");
266 }
267
268}