xref: /wlan-dirver/utils/sigma-dut/dhcp.c (revision 016ae6c8cafcbfd03dc69ed0eb43e252fb93e347)
11bde7947SAnkita Bajaj /*
21bde7947SAnkita Bajaj  * Sigma Control API DUT (station/AP)
31bde7947SAnkita Bajaj  * Copyright (c) 2018, The Linux Foundation
41bde7947SAnkita Bajaj  * All Rights Reserved.
51bde7947SAnkita Bajaj  * Licensed under the Clear BSD license. See README for more details.
61bde7947SAnkita Bajaj  */
71bde7947SAnkita Bajaj 
81bde7947SAnkita Bajaj #include "sigma_dut.h"
91bde7947SAnkita Bajaj #include "wpa_helpers.h"
101bde7947SAnkita Bajaj #include <netinet/if_ether.h>
111bde7947SAnkita Bajaj #include <netinet/ip.h>
121bde7947SAnkita Bajaj #include <netinet/udp.h>
131bde7947SAnkita Bajaj #include <pcap.h>
141bde7947SAnkita Bajaj #include <signal.h>
151bde7947SAnkita Bajaj 
161bde7947SAnkita Bajaj #define DHCP_SERVER_PORT 67
171bde7947SAnkita Bajaj #define DHCP_CLIENT_PORT 68
181bde7947SAnkita Bajaj #define DHCP_ACK         5
191bde7947SAnkita Bajaj 
201bde7947SAnkita Bajaj #define UDP_PROTOCOL 17
211bde7947SAnkita Bajaj 
221bde7947SAnkita Bajaj static pcap_t *pcap = NULL;
231bde7947SAnkita Bajaj 
241bde7947SAnkita Bajaj struct dhcp_pkt {
251bde7947SAnkita Bajaj 	struct iphdr iph;
261bde7947SAnkita Bajaj 	struct udphdr udph;
271bde7947SAnkita Bajaj 	u8 op;
281bde7947SAnkita Bajaj 	u8 htype;
291bde7947SAnkita Bajaj 	u8 hlen;
301bde7947SAnkita Bajaj 	u8 hops;
311bde7947SAnkita Bajaj 	u32 xid;
321bde7947SAnkita Bajaj 	u16 secs;
331bde7947SAnkita Bajaj 	u16 flags;
341bde7947SAnkita Bajaj 	u32 client_ip;
351bde7947SAnkita Bajaj 	u32 your_ip;
361bde7947SAnkita Bajaj 	u32 server_ip;
371bde7947SAnkita Bajaj 	u32 relay_ip;
381bde7947SAnkita Bajaj 	u8 hw_addr[16];
391bde7947SAnkita Bajaj 	u8 serv_name[64];
401bde7947SAnkita Bajaj 	u8 boot_file[128];
411bde7947SAnkita Bajaj 	u32 magic_cookie;
421bde7947SAnkita Bajaj 	u8 options[314];
431bde7947SAnkita Bajaj } __attribute__ ((packed));
441bde7947SAnkita Bajaj 
451bde7947SAnkita Bajaj enum dhcp_options {
461bde7947SAnkita Bajaj 	DHCP_OPT_SUBNET_MASK = 1,
471bde7947SAnkita Bajaj 	DHCP_OPT_ROUTER = 3,
481bde7947SAnkita Bajaj 	DHCP_OPT_MSG_TYPE = 53,
491bde7947SAnkita Bajaj 	DHCP_OPT_END = 255
501bde7947SAnkita Bajaj };
511bde7947SAnkita Bajaj 
521bde7947SAnkita Bajaj 
get_dhcp_option(u8 * options,u8 type,int len)531bde7947SAnkita Bajaj static u8 * get_dhcp_option(u8 *options, u8 type, int len)
541bde7947SAnkita Bajaj {
551bde7947SAnkita Bajaj 	u8 *pos = options;
561bde7947SAnkita Bajaj 	u8 *end = pos + len;
571bde7947SAnkita Bajaj 
581bde7947SAnkita Bajaj 	while (pos < end && pos + 1 < end && pos + 2 + pos[1] <= end) {
591bde7947SAnkita Bajaj 		if (*pos == type)
601bde7947SAnkita Bajaj 			return pos;
611bde7947SAnkita Bajaj 		pos += 2 + pos[1];
621bde7947SAnkita Bajaj 	}
631bde7947SAnkita Bajaj 	return NULL;
641bde7947SAnkita Bajaj }
651bde7947SAnkita Bajaj 
661bde7947SAnkita Bajaj 
671bde7947SAnkita Bajaj /**
681bde7947SAnkita Bajaj  * 1. Open UDP socket
691bde7947SAnkita Bajaj  * 2. read_msg
701bde7947SAnkita Bajaj  * 3. Process DHCP_ACK
711bde7947SAnkita Bajaj  */
process_dhcp_ack(void * ptr)721bde7947SAnkita Bajaj static void * process_dhcp_ack(void *ptr)
731bde7947SAnkita Bajaj {
741bde7947SAnkita Bajaj 	struct bpf_program pcap_fp;
751bde7947SAnkita Bajaj 	char pcap_filter[200], pcap_err[PCAP_ERRBUF_SIZE];
761bde7947SAnkita Bajaj 	struct sigma_dut *dut = ptr;
771bde7947SAnkita Bajaj 	int nbytes = 0;
781bde7947SAnkita Bajaj 	u8 buf[1024];
791bde7947SAnkita Bajaj 	struct dhcp_pkt *dhcp;
801bde7947SAnkita Bajaj 	int option_len;
811bde7947SAnkita Bajaj 	u8 *msg_type, *val;
821bde7947SAnkita Bajaj 	struct in_addr ip;
831bde7947SAnkita Bajaj 	char your_ip[16], mask[16], router[16];
841bde7947SAnkita Bajaj 	unsigned short protocol, port_no;
851bde7947SAnkita Bajaj 	bpf_u_int32 pcap_maskp, pcap_netp;
861bde7947SAnkita Bajaj 	char ifname[20];
871bde7947SAnkita Bajaj 
881bde7947SAnkita Bajaj 	protocol = UDP_PROTOCOL;
891bde7947SAnkita Bajaj 	port_no = DHCP_SERVER_PORT;
901bde7947SAnkita Bajaj 
91*016ae6c8SJouni Malinen 	strlcpy(ifname, get_main_ifname(dut), sizeof(ifname));
921bde7947SAnkita Bajaj 
931bde7947SAnkita Bajaj 	/* gives the network mask for ifname essential for applying filter */
941bde7947SAnkita Bajaj 	pcap_lookupnet(ifname, &pcap_netp, &pcap_maskp, pcap_err);
951bde7947SAnkita Bajaj 
961bde7947SAnkita Bajaj 	sigma_dut_print(dut, DUT_MSG_INFO, "DHCP: ifname = %s", ifname);
971bde7947SAnkita Bajaj 
981bde7947SAnkita Bajaj 	/* creates a session for sniffing */
991bde7947SAnkita Bajaj 	pcap = pcap_open_live(ifname, 2500, 0, 10, pcap_err);
1001d79b3a6SAnkita Bajaj 	if (!pcap) {
1011bde7947SAnkita Bajaj 		sigma_dut_print(dut, DUT_MSG_INFO, "pcap_open_live: %s",
1021bde7947SAnkita Bajaj 				pcap_err);
1031d79b3a6SAnkita Bajaj 		goto exit;
1041d79b3a6SAnkita Bajaj 	}
1051bde7947SAnkita Bajaj 
1061bde7947SAnkita Bajaj 	snprintf(pcap_filter, sizeof(pcap_filter),
1071bde7947SAnkita Bajaj 		 "ip proto 0x%x and udp src port 0x%x",
1081bde7947SAnkita Bajaj 		 protocol, port_no);
1091bde7947SAnkita Bajaj 	sigma_dut_print(dut, DUT_MSG_INFO, "pcap_flter %s", pcap_filter);
1101bde7947SAnkita Bajaj 
1111bde7947SAnkita Bajaj 	if (pcap_compile(pcap, &pcap_fp, pcap_filter, 1, pcap_netp) < 0)
1121bde7947SAnkita Bajaj 		sigma_dut_print(dut, DUT_MSG_INFO, "pcap_compile: %s",
1131bde7947SAnkita Bajaj 				pcap_geterr(pcap));
1141bde7947SAnkita Bajaj 
1151bde7947SAnkita Bajaj 	if (pcap_setfilter(pcap, &pcap_fp) < 0)
1161bde7947SAnkita Bajaj 		sigma_dut_print(dut, DUT_MSG_INFO, "pcap_setfilter: %s",
1171bde7947SAnkita Bajaj 				pcap_geterr(pcap));
1181bde7947SAnkita Bajaj 
1191bde7947SAnkita Bajaj 	pcap_freecode(&pcap_fp);
1201bde7947SAnkita Bajaj 
1211bde7947SAnkita Bajaj 	while (1) {
1221bde7947SAnkita Bajaj 		memset(buf, 0, sizeof(buf));
1231bde7947SAnkita Bajaj 		sigma_dut_print(dut, DUT_MSG_DEBUG,
1241bde7947SAnkita Bajaj 				"HLP: Waiting for message to receive");
1251bde7947SAnkita Bajaj 		nbytes = recvfrom(pcap_get_selectable_fd(pcap), &buf,
1261bde7947SAnkita Bajaj 				  sizeof(buf), 0, NULL, NULL);
1271bde7947SAnkita Bajaj 		if (nbytes == -1) {
1281bde7947SAnkita Bajaj 			sigma_dut_print(dut, DUT_MSG_ERROR, "HLP: failed: %s",
1291bde7947SAnkita Bajaj 					strerror(errno));
1301bde7947SAnkita Bajaj 			goto exit;
1311bde7947SAnkita Bajaj 		}
1321bde7947SAnkita Bajaj 
1331bde7947SAnkita Bajaj 		sigma_dut_print(dut, DUT_MSG_INFO, "HLP: Received %d bytes",
1341bde7947SAnkita Bajaj 				nbytes);
1351bde7947SAnkita Bajaj 		hex_dump(dut, buf, nbytes);
1361bde7947SAnkita Bajaj 
1371bde7947SAnkita Bajaj 		if (nbytes < 314) {
1381bde7947SAnkita Bajaj 			sigma_dut_print(dut, DUT_MSG_DEBUG,
1391bde7947SAnkita Bajaj 					"HLP: Ignore MSG, Too short message received");
1401bde7947SAnkita Bajaj 			continue;
1411bde7947SAnkita Bajaj 		}
1421bde7947SAnkita Bajaj 		nbytes -= 14;
1431bde7947SAnkita Bajaj 
1441bde7947SAnkita Bajaj 		/*
1451bde7947SAnkita Bajaj 		 * Process DHCP packet
1461bde7947SAnkita Bajaj 		 * skip ethernet header from buf and then process the ack
1471bde7947SAnkita Bajaj 		 */
1481bde7947SAnkita Bajaj 		dhcp = (struct dhcp_pkt *) (buf + ETH_HLEN);
1491bde7947SAnkita Bajaj 
1501bde7947SAnkita Bajaj 		option_len = nbytes - ((char *) dhcp->options - (char *) dhcp);
1511bde7947SAnkita Bajaj 
1521bde7947SAnkita Bajaj 		sigma_dut_print(dut, DUT_MSG_DEBUG,
1531bde7947SAnkita Bajaj 				"option_len %d, First option : %02x",
1541bde7947SAnkita Bajaj 				option_len, *(dhcp->options));
1551bde7947SAnkita Bajaj 
1561bde7947SAnkita Bajaj 		/* Check for DHCP_ACK */
1571bde7947SAnkita Bajaj 		msg_type = get_dhcp_option(dhcp->options, DHCP_OPT_MSG_TYPE,
1581bde7947SAnkita Bajaj 					   option_len);
1591bde7947SAnkita Bajaj 		if (!msg_type) {
1601bde7947SAnkita Bajaj 			sigma_dut_print(dut, DUT_MSG_ERROR,
1611bde7947SAnkita Bajaj 					"Ignore MSG, DHCP OPT MSG_TYPE missing");
1621bde7947SAnkita Bajaj 			continue;
1631bde7947SAnkita Bajaj 		}
1641bde7947SAnkita Bajaj 
1651bde7947SAnkita Bajaj 		if (msg_type[2] != DHCP_ACK) {
1661bde7947SAnkita Bajaj 			sigma_dut_print(dut, DUT_MSG_ERROR,
1671bde7947SAnkita Bajaj 					"Ignore MSG, DHCP message type : %02x",
1681bde7947SAnkita Bajaj 					msg_type[2]);
1691bde7947SAnkita Bajaj 			continue;
1701bde7947SAnkita Bajaj 		}
1711bde7947SAnkita Bajaj 
1721bde7947SAnkita Bajaj 		ip.s_addr = dhcp->your_ip;
1731bde7947SAnkita Bajaj 		strlcpy(your_ip, inet_ntoa(ip), sizeof(your_ip));
1741bde7947SAnkita Bajaj 
1751bde7947SAnkita Bajaj 		val = get_dhcp_option(dhcp->options, DHCP_OPT_SUBNET_MASK,
1761bde7947SAnkita Bajaj 				      option_len);
1771bde7947SAnkita Bajaj 		if (!val) {
1781bde7947SAnkita Bajaj 			sigma_dut_print(dut, DUT_MSG_ERROR,
1791bde7947SAnkita Bajaj 					"DHCP option SUBNET_MASK missing");
1801bde7947SAnkita Bajaj 			continue;
1811bde7947SAnkita Bajaj 		}
1821bde7947SAnkita Bajaj 
1831bde7947SAnkita Bajaj 		memcpy(&(ip.s_addr), (val + 2), val[1]);
1841bde7947SAnkita Bajaj 		strlcpy(mask, inet_ntoa(ip), sizeof(mask));
1851bde7947SAnkita Bajaj 
1861bde7947SAnkita Bajaj 		val = get_dhcp_option(dhcp->options, DHCP_OPT_ROUTER,
1871bde7947SAnkita Bajaj 				      option_len);
1881bde7947SAnkita Bajaj 		if (!val) {
1891bde7947SAnkita Bajaj 			sigma_dut_print(dut, DUT_MSG_ERROR,
1901bde7947SAnkita Bajaj 					"DHCP option DHCP_OPT_ROUTER missing");
1911bde7947SAnkita Bajaj 			continue;
1921bde7947SAnkita Bajaj 		}
1931bde7947SAnkita Bajaj 		memcpy(&(ip.s_addr), val + 2, val[1]);
1941bde7947SAnkita Bajaj 		strlcpy(router, inet_ntoa(ip), sizeof(router));
1951bde7947SAnkita Bajaj 
1961bde7947SAnkita Bajaj 		sigma_dut_print(dut, DUT_MSG_DEBUG,
1971bde7947SAnkita Bajaj 				"OP: %d, your_ip: %s, netmask: %s, router: %s",
1981bde7947SAnkita Bajaj 				dhcp->op, your_ip, mask, router);
1991bde7947SAnkita Bajaj 		/* set ip configuration */
2001bde7947SAnkita Bajaj 		if (!set_ipv4_addr(dut, ifname, your_ip, mask)) {
2011bde7947SAnkita Bajaj 			sigma_dut_print(dut, DUT_MSG_ERROR,
2021bde7947SAnkita Bajaj 					"Failed to set IP address");
2031bde7947SAnkita Bajaj 			continue;
2041bde7947SAnkita Bajaj 		}
2051bde7947SAnkita Bajaj 		if (set_ipv4_gw(dut, router) < 1) {
2061bde7947SAnkita Bajaj 			sigma_dut_print(dut, DUT_MSG_ERROR,
2071bde7947SAnkita Bajaj 					"Failed to set Gateway address");
2081bde7947SAnkita Bajaj 			continue;
2091bde7947SAnkita Bajaj 		}
2101bde7947SAnkita Bajaj 
2111bde7947SAnkita Bajaj 		sigma_dut_print(dut, DUT_MSG_DEBUG,
2121bde7947SAnkita Bajaj 				"IP configuration completed");
2131bde7947SAnkita Bajaj 	}
2141bde7947SAnkita Bajaj 
2151bde7947SAnkita Bajaj exit:
2161bde7947SAnkita Bajaj 	sigma_dut_print(dut, DUT_MSG_INFO, "HLP: Received failed in exit");
2171bde7947SAnkita Bajaj 	if (pcap) {
2181bde7947SAnkita Bajaj 		pcap_close(pcap);
2191bde7947SAnkita Bajaj 		pcap = NULL;
2201bde7947SAnkita Bajaj 	}
2211bde7947SAnkita Bajaj 	dut->hlp_thread = 0;
2221bde7947SAnkita Bajaj 	return NULL;
2231bde7947SAnkita Bajaj }
2241bde7947SAnkita Bajaj 
2251bde7947SAnkita Bajaj 
hlp_thread_exit(int signum)2261bde7947SAnkita Bajaj static void hlp_thread_exit(int signum)
2271bde7947SAnkita Bajaj {
2281bde7947SAnkita Bajaj 	pthread_exit(0);
2291bde7947SAnkita Bajaj }
2301bde7947SAnkita Bajaj 
2311bde7947SAnkita Bajaj 
hlp_thread_cleanup(struct sigma_dut * dut)2321bde7947SAnkita Bajaj void hlp_thread_cleanup(struct sigma_dut *dut)
2331bde7947SAnkita Bajaj {
2341bde7947SAnkita Bajaj 	if (pcap) {
2351bde7947SAnkita Bajaj 		pcap_close(pcap);
2361bde7947SAnkita Bajaj 		pcap = NULL;
2371bde7947SAnkita Bajaj 	}
2381bde7947SAnkita Bajaj 	if (dut->hlp_thread) {
2391bde7947SAnkita Bajaj 		sigma_dut_print(dut, DUT_MSG_DEBUG, "Kill thread: %ld",
2401bde7947SAnkita Bajaj 				dut->hlp_thread);
2411bde7947SAnkita Bajaj 		pthread_kill(dut->hlp_thread, SIGUSR1);
2421bde7947SAnkita Bajaj 		dut->hlp_thread = 0;
2431bde7947SAnkita Bajaj 	}
2441bde7947SAnkita Bajaj }
2451bde7947SAnkita Bajaj 
2461bde7947SAnkita Bajaj 
process_fils_hlp(struct sigma_dut * dut)2471bde7947SAnkita Bajaj void process_fils_hlp(struct sigma_dut *dut)
2481bde7947SAnkita Bajaj {
2491bde7947SAnkita Bajaj 	static pthread_t hlp_thread;
2501bde7947SAnkita Bajaj 
2511bde7947SAnkita Bajaj 	if (dut->hlp_thread) {
2521bde7947SAnkita Bajaj 		sigma_dut_print(dut, DUT_MSG_ERROR,
2531bde7947SAnkita Bajaj 				"FILS-HLP DHCP thread already running");
2541bde7947SAnkita Bajaj 		return;
2551bde7947SAnkita Bajaj 	}
2561bde7947SAnkita Bajaj 
2571bde7947SAnkita Bajaj 	signal(SIGUSR1, hlp_thread_exit);
2581bde7947SAnkita Bajaj 
2591bde7947SAnkita Bajaj 	sigma_dut_print(dut, DUT_MSG_DEBUG, "Creating FILS_HLP thread-->");
2601bde7947SAnkita Bajaj 
2611bde7947SAnkita Bajaj 	/* create FILS_HLP thread */
2621bde7947SAnkita Bajaj 	if (!pthread_create(&hlp_thread, NULL, &process_dhcp_ack,
2631bde7947SAnkita Bajaj 			    (void *) dut)) {
2641bde7947SAnkita Bajaj 		dut->hlp_thread = hlp_thread;
2651bde7947SAnkita Bajaj 	} else {
2661bde7947SAnkita Bajaj 		sigma_dut_print(dut, DUT_MSG_DEBUG,
2671bde7947SAnkita Bajaj 				"FILS_HLP thread creation failed");
2681bde7947SAnkita Bajaj 	}
2691bde7947SAnkita Bajaj 
2701bde7947SAnkita Bajaj }
271