10f66f451Sopenharmony_ci/* dhcp.c - DHCP client for dynamic network configuration. 20f66f451Sopenharmony_ci * 30f66f451Sopenharmony_ci * Copyright 2012 Madhur Verma <mad.flexi@gmail.com> 40f66f451Sopenharmony_ci * Copyright 2013 Kyungwan Han <asura321@gmail.com> 50f66f451Sopenharmony_ci * 60f66f451Sopenharmony_ci * Not in SUSv4. 70f66f451Sopenharmony_ciUSE_DHCP(NEWTOY(dhcp, "V:H:F:x*r:O*A#<0=20T#<0=3t#<0=3s:p:i:SBRCaovqnbf", TOYFLAG_SBIN|TOYFLAG_ROOTONLY)) 80f66f451Sopenharmony_ci 90f66f451Sopenharmony_ciconfig DHCP 100f66f451Sopenharmony_ci bool "dhcp" 110f66f451Sopenharmony_ci default n 120f66f451Sopenharmony_ci help 130f66f451Sopenharmony_ci usage: dhcp [-fbnqvoCRB] [-i IFACE] [-r IP] [-s PROG] [-p PIDFILE] 140f66f451Sopenharmony_ci [-H HOSTNAME] [-V VENDOR] [-x OPT:VAL] [-O OPT] 150f66f451Sopenharmony_ci 160f66f451Sopenharmony_ci Configure network dynamically using DHCP. 170f66f451Sopenharmony_ci 180f66f451Sopenharmony_ci -i Interface to use (default eth0) 190f66f451Sopenharmony_ci -p Create pidfile 200f66f451Sopenharmony_ci -s Run PROG at DHCP events (default /usr/share/dhcp/default.script) 210f66f451Sopenharmony_ci -B Request broadcast replies 220f66f451Sopenharmony_ci -t Send up to N discover packets 230f66f451Sopenharmony_ci -T Pause between packets (default 3 seconds) 240f66f451Sopenharmony_ci -A Wait N seconds after failure (default 20) 250f66f451Sopenharmony_ci -f Run in foreground 260f66f451Sopenharmony_ci -b Background if lease is not obtained 270f66f451Sopenharmony_ci -n Exit if lease is not obtained 280f66f451Sopenharmony_ci -q Exit after obtaining lease 290f66f451Sopenharmony_ci -R Release IP on exit 300f66f451Sopenharmony_ci -S Log to syslog too 310f66f451Sopenharmony_ci -a Use arping to validate offered address 320f66f451Sopenharmony_ci -O Request option OPT from server (cumulative) 330f66f451Sopenharmony_ci -o Don't request any options (unless -O is given) 340f66f451Sopenharmony_ci -r Request this IP address 350f66f451Sopenharmony_ci -x OPT:VAL Include option OPT in sent packets (cumulative) 360f66f451Sopenharmony_ci -F Ask server to update DNS mapping for NAME 370f66f451Sopenharmony_ci -H Send NAME as client hostname (default none) 380f66f451Sopenharmony_ci -V VENDOR Vendor identifier (default 'toybox VERSION') 390f66f451Sopenharmony_ci -C Don't send MAC as client identifier 400f66f451Sopenharmony_ci -v Verbose 410f66f451Sopenharmony_ci 420f66f451Sopenharmony_ci Signals: 430f66f451Sopenharmony_ci USR1 Renew current lease 440f66f451Sopenharmony_ci USR2 Release current lease 450f66f451Sopenharmony_ci 460f66f451Sopenharmony_ci*/ 470f66f451Sopenharmony_ci 480f66f451Sopenharmony_ci#define FOR_dhcp 490f66f451Sopenharmony_ci#include "toys.h" 500f66f451Sopenharmony_ci 510f66f451Sopenharmony_ci// TODO: headers not in posix: 520f66f451Sopenharmony_ci#include <netinet/ip.h> 530f66f451Sopenharmony_ci#include <netinet/udp.h> 540f66f451Sopenharmony_ci#include <netpacket/packet.h> 550f66f451Sopenharmony_ci 560f66f451Sopenharmony_ci#include <linux/filter.h> //FIXME: linux specific. fix for other OS ports 570f66f451Sopenharmony_ci#include <linux/if_ether.h> 580f66f451Sopenharmony_ci 590f66f451Sopenharmony_ciGLOBALS( 600f66f451Sopenharmony_ci char *iface; 610f66f451Sopenharmony_ci char *pidfile; 620f66f451Sopenharmony_ci char *script; 630f66f451Sopenharmony_ci long retries; 640f66f451Sopenharmony_ci long timeout; 650f66f451Sopenharmony_ci long tryagain; 660f66f451Sopenharmony_ci struct arg_list *req_opt; 670f66f451Sopenharmony_ci char *req_ip; 680f66f451Sopenharmony_ci struct arg_list *pkt_opt; 690f66f451Sopenharmony_ci char *fdn_name; 700f66f451Sopenharmony_ci char *hostname; 710f66f451Sopenharmony_ci char *vendor_cls; 720f66f451Sopenharmony_ci) 730f66f451Sopenharmony_ci 740f66f451Sopenharmony_ci#define STATE_INIT 0 750f66f451Sopenharmony_ci#define STATE_REQUESTING 1 760f66f451Sopenharmony_ci#define STATE_BOUND 2 770f66f451Sopenharmony_ci#define STATE_RENEWING 3 780f66f451Sopenharmony_ci#define STATE_REBINDING 4 790f66f451Sopenharmony_ci#define STATE_RENEW_REQUESTED 5 800f66f451Sopenharmony_ci#define STATE_RELEASED 6 810f66f451Sopenharmony_ci 820f66f451Sopenharmony_ci#define BOOTP_BROADCAST 0x8000 830f66f451Sopenharmony_ci#define DHCP_MAGIC 0x63825363 840f66f451Sopenharmony_ci 850f66f451Sopenharmony_ci#define DHCP_REQUEST 1 860f66f451Sopenharmony_ci#define DHCP_REPLY 2 870f66f451Sopenharmony_ci#define DHCP_HTYPE_ETHERNET 1 880f66f451Sopenharmony_ci 890f66f451Sopenharmony_ci#define DHCPC_SERVER_PORT 67 900f66f451Sopenharmony_ci#define DHCPC_CLIENT_PORT 68 910f66f451Sopenharmony_ci 920f66f451Sopenharmony_ci#define DHCPDISCOVER 1 930f66f451Sopenharmony_ci#define DHCPOFFER 2 940f66f451Sopenharmony_ci#define DHCPREQUEST 3 950f66f451Sopenharmony_ci#define DHCPACK 5 960f66f451Sopenharmony_ci#define DHCPNAK 6 970f66f451Sopenharmony_ci#define DHCPRELEASE 7 980f66f451Sopenharmony_ci 990f66f451Sopenharmony_ci#define DHCP_OPTION_PADDING 0x00 1000f66f451Sopenharmony_ci#define DHCP_OPTION_SUBNET_MASK 0x01 1010f66f451Sopenharmony_ci#define DHCP_OPTION_ROUTER 0x03 1020f66f451Sopenharmony_ci#define DHCP_OPTION_DNS_SERVER 0x06 1030f66f451Sopenharmony_ci#define DHCP_OPTION_HOST_NAME 0x0c 1040f66f451Sopenharmony_ci#define DHCP_OPTION_BROADCAST 0x1c 1050f66f451Sopenharmony_ci#define DHCP_OPTION_REQ_IPADDR 0x32 1060f66f451Sopenharmony_ci#define DHCP_OPTION_LEASE_TIME 0x33 1070f66f451Sopenharmony_ci#define DHCP_OPTION_OVERLOAD 0x34 1080f66f451Sopenharmony_ci#define DHCP_OPTION_MSG_TYPE 0x35 1090f66f451Sopenharmony_ci#define DHCP_OPTION_SERVER_ID 0x36 1100f66f451Sopenharmony_ci#define DHCP_OPTION_REQ_LIST 0x37 1110f66f451Sopenharmony_ci#define DHCP_OPTION_MAX_SIZE 0x39 1120f66f451Sopenharmony_ci#define DHCP_OPTION_CLIENTID 0x3D 1130f66f451Sopenharmony_ci#define DHCP_OPTION_VENDOR 0x3C 1140f66f451Sopenharmony_ci#define DHCP_OPTION_FQDN 0x51 1150f66f451Sopenharmony_ci#define DHCP_OPTION_END 0xFF 1160f66f451Sopenharmony_ci 1170f66f451Sopenharmony_ci#define DHCP_NUM8 (1<<8) 1180f66f451Sopenharmony_ci#define DHCP_NUM16 (1<<9) 1190f66f451Sopenharmony_ci#define DHCP_NUM32 DHCP_NUM16 | DHCP_NUM8 1200f66f451Sopenharmony_ci#define DHCP_STRING (1<<10) 1210f66f451Sopenharmony_ci#define DHCP_STRLST (1<<11) 1220f66f451Sopenharmony_ci#define DHCP_IP (1<<12) 1230f66f451Sopenharmony_ci#define DHCP_IPLIST (1<<13) 1240f66f451Sopenharmony_ci#define DHCP_IPPLST (1<<14) 1250f66f451Sopenharmony_ci#define DHCP_STCRTS (1<<15) 1260f66f451Sopenharmony_ci 1270f66f451Sopenharmony_ci#define LOG_SILENT 0x0 1280f66f451Sopenharmony_ci#define LOG_CONSOLE 0x1 1290f66f451Sopenharmony_ci#define LOG_SYSTEM 0x2 1300f66f451Sopenharmony_ci 1310f66f451Sopenharmony_ci#define MODE_OFF 0 1320f66f451Sopenharmony_ci#define MODE_RAW 1 1330f66f451Sopenharmony_ci#define MODE_APP 2 1340f66f451Sopenharmony_ci 1350f66f451Sopenharmony_cistatic void (*dbg)(char *format, ...); 1360f66f451Sopenharmony_cistatic void dummy(char *format, ...){ 1370f66f451Sopenharmony_ci return; 1380f66f451Sopenharmony_ci} 1390f66f451Sopenharmony_ci 1400f66f451Sopenharmony_citypedef struct dhcpc_result_s { 1410f66f451Sopenharmony_ci struct in_addr serverid; 1420f66f451Sopenharmony_ci struct in_addr ipaddr; 1430f66f451Sopenharmony_ci struct in_addr netmask; 1440f66f451Sopenharmony_ci struct in_addr dnsaddr; 1450f66f451Sopenharmony_ci struct in_addr default_router; 1460f66f451Sopenharmony_ci uint32_t lease_time; 1470f66f451Sopenharmony_ci} dhcpc_result_t; 1480f66f451Sopenharmony_ci 1490f66f451Sopenharmony_citypedef struct __attribute__((packed)) dhcp_msg_s { 1500f66f451Sopenharmony_ci uint8_t op; 1510f66f451Sopenharmony_ci uint8_t htype; 1520f66f451Sopenharmony_ci uint8_t hlen; 1530f66f451Sopenharmony_ci uint8_t hops; 1540f66f451Sopenharmony_ci uint32_t xid; 1550f66f451Sopenharmony_ci uint16_t secs; 1560f66f451Sopenharmony_ci uint16_t flags; 1570f66f451Sopenharmony_ci uint32_t ciaddr; 1580f66f451Sopenharmony_ci uint32_t yiaddr; 1590f66f451Sopenharmony_ci uint32_t nsiaddr; 1600f66f451Sopenharmony_ci uint32_t ngiaddr; 1610f66f451Sopenharmony_ci uint8_t chaddr[16]; 1620f66f451Sopenharmony_ci uint8_t sname[64]; 1630f66f451Sopenharmony_ci uint8_t file[128]; 1640f66f451Sopenharmony_ci uint32_t cookie; 1650f66f451Sopenharmony_ci uint8_t options[308]; 1660f66f451Sopenharmony_ci} dhcp_msg_t; 1670f66f451Sopenharmony_ci 1680f66f451Sopenharmony_citypedef struct __attribute__((packed)) dhcp_raw_s { 1690f66f451Sopenharmony_ci struct iphdr iph; 1700f66f451Sopenharmony_ci struct udphdr udph; 1710f66f451Sopenharmony_ci dhcp_msg_t dhcp; 1720f66f451Sopenharmony_ci} dhcp_raw_t; 1730f66f451Sopenharmony_ci 1740f66f451Sopenharmony_citypedef struct dhcpc_state_s { 1750f66f451Sopenharmony_ci uint8_t macaddr[6]; 1760f66f451Sopenharmony_ci char *iface; 1770f66f451Sopenharmony_ci int ifindex; 1780f66f451Sopenharmony_ci int sockfd; 1790f66f451Sopenharmony_ci int status; 1800f66f451Sopenharmony_ci int mode; 1810f66f451Sopenharmony_ci uint32_t mask; 1820f66f451Sopenharmony_ci struct in_addr ipaddr; 1830f66f451Sopenharmony_ci struct in_addr serverid; 1840f66f451Sopenharmony_ci dhcp_msg_t pdhcp; 1850f66f451Sopenharmony_ci} dhcpc_state_t; 1860f66f451Sopenharmony_ci 1870f66f451Sopenharmony_citypedef struct option_val_s { 1880f66f451Sopenharmony_ci char *key; 1890f66f451Sopenharmony_ci uint16_t code; 1900f66f451Sopenharmony_ci void *val; 1910f66f451Sopenharmony_ci size_t len; 1920f66f451Sopenharmony_ci} option_val_t; 1930f66f451Sopenharmony_ci 1940f66f451Sopenharmony_cistruct fd_pair { int rd; int wr; }; 1950f66f451Sopenharmony_cistatic uint32_t xid; 1960f66f451Sopenharmony_cistatic dhcpc_state_t *state; 1970f66f451Sopenharmony_cistatic struct fd_pair sigfd; 1980f66f451Sopenharmony_ciuint8_t bmacaddr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; 1990f66f451Sopenharmony_ci int set = 1; 2000f66f451Sopenharmony_ciuint8_t infomode = LOG_CONSOLE; 2010f66f451Sopenharmony_ciuint8_t raw_opt[29]; 2020f66f451Sopenharmony_ciint raw_optcount = 0; 2030f66f451Sopenharmony_cistruct arg_list *x_opt; 2040f66f451Sopenharmony_ciin_addr_t server = 0; 2050f66f451Sopenharmony_ci 2060f66f451Sopenharmony_cistatic option_val_t *msgopt_list = NULL; 2070f66f451Sopenharmony_cistatic option_val_t options_list[] = { 2080f66f451Sopenharmony_ci {"lease" , DHCP_NUM32 | 0x33, NULL, 0}, 2090f66f451Sopenharmony_ci {"subnet" , DHCP_IP | 0x01, NULL, 0}, 2100f66f451Sopenharmony_ci {"broadcast" , DHCP_IP | 0x1c, NULL, 0}, 2110f66f451Sopenharmony_ci {"router" , DHCP_IP | 0x03, NULL, 0}, 2120f66f451Sopenharmony_ci {"ipttl" , DHCP_NUM8 | 0x17, NULL, 0}, 2130f66f451Sopenharmony_ci {"mtu" , DHCP_NUM16 | 0x1a, NULL, 0}, 2140f66f451Sopenharmony_ci {"hostname" , DHCP_STRING | 0x0c, NULL, 0}, 2150f66f451Sopenharmony_ci {"domain" , DHCP_STRING | 0x0f, NULL, 0}, 2160f66f451Sopenharmony_ci {"search" , DHCP_STRLST | 0x77, NULL, 0}, 2170f66f451Sopenharmony_ci {"nisdomain" , DHCP_STRING | 0x28, NULL, 0}, 2180f66f451Sopenharmony_ci {"timezone" , DHCP_NUM32 | 0x02, NULL, 0}, 2190f66f451Sopenharmony_ci {"tftp" , DHCP_STRING | 0x42, NULL, 0}, 2200f66f451Sopenharmony_ci {"bootfile" , DHCP_STRING | 0x43, NULL, 0}, 2210f66f451Sopenharmony_ci {"bootsize" , DHCP_NUM16 | 0x0d, NULL, 0}, 2220f66f451Sopenharmony_ci {"rootpath" , DHCP_STRING | 0x11, NULL, 0}, 2230f66f451Sopenharmony_ci {"wpad" , DHCP_STRING | 0xfc, NULL, 0}, 2240f66f451Sopenharmony_ci {"serverid" , DHCP_IP | 0x36, NULL, 0}, 2250f66f451Sopenharmony_ci {"message" , DHCP_STRING | 0x38, NULL, 0}, 2260f66f451Sopenharmony_ci {"vlanid" , DHCP_NUM32 | 0x84, NULL, 0}, 2270f66f451Sopenharmony_ci {"vlanpriority" , DHCP_NUM32 | 0x85, NULL, 0}, 2280f66f451Sopenharmony_ci {"dns" , DHCP_IPLIST | 0x06, NULL, 0}, 2290f66f451Sopenharmony_ci {"wins" , DHCP_IPLIST | 0x2c, NULL, 0}, 2300f66f451Sopenharmony_ci {"nissrv" , DHCP_IPLIST | 0x29, NULL, 0}, 2310f66f451Sopenharmony_ci {"ntpsrv" , DHCP_IPLIST | 0x2a, NULL, 0}, 2320f66f451Sopenharmony_ci {"lprsrv" , DHCP_IPLIST | 0x09, NULL, 0}, 2330f66f451Sopenharmony_ci {"swapsrv" , DHCP_IP | 0x10, NULL, 0}, 2340f66f451Sopenharmony_ci {"routes" , DHCP_STCRTS | 0x21, NULL, 0}, 2350f66f451Sopenharmony_ci {"staticroutes" , DHCP_STCRTS | 0x79, NULL, 0}, 2360f66f451Sopenharmony_ci {"msstaticroutes" , DHCP_STCRTS | 0xf9, NULL, 0}, 2370f66f451Sopenharmony_ci}; 2380f66f451Sopenharmony_ci 2390f66f451Sopenharmony_cistatic struct sock_filter filter_instr[] = { 2400f66f451Sopenharmony_ci BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 9), 2410f66f451Sopenharmony_ci BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, IPPROTO_UDP, 0, 6), 2420f66f451Sopenharmony_ci BPF_STMT(BPF_LD|BPF_H|BPF_ABS, 6), 2430f66f451Sopenharmony_ci BPF_JUMP(BPF_JMP|BPF_JSET|BPF_K, 0x1fff, 4, 0), 2440f66f451Sopenharmony_ci BPF_STMT(BPF_LDX|BPF_B|BPF_MSH, 0), BPF_STMT(BPF_LD|BPF_H|BPF_IND, 2), 2450f66f451Sopenharmony_ci BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 68, 0, 1), 2460f66f451Sopenharmony_ci BPF_STMT(BPF_RET|BPF_K, 0xffffffff), BPF_STMT(BPF_RET|BPF_K, 0), 2470f66f451Sopenharmony_ci}; 2480f66f451Sopenharmony_ci 2490f66f451Sopenharmony_cistatic struct sock_fprog filter_prog = { 2500f66f451Sopenharmony_ci .len = ARRAY_LEN(filter_instr), 2510f66f451Sopenharmony_ci .filter = (struct sock_filter *) filter_instr, 2520f66f451Sopenharmony_ci}; 2530f66f451Sopenharmony_ci 2540f66f451Sopenharmony_ci// calculate options size. 2550f66f451Sopenharmony_cistatic int dhcp_opt_size(uint8_t *optionptr) 2560f66f451Sopenharmony_ci{ 2570f66f451Sopenharmony_ci int i = 0; 2580f66f451Sopenharmony_ci for(;optionptr[i] != 0xff; i++) if(optionptr[i] != 0x00) i += optionptr[i + 1] + 2 -1; 2590f66f451Sopenharmony_ci return i; 2600f66f451Sopenharmony_ci} 2610f66f451Sopenharmony_ci 2620f66f451Sopenharmony_ci// calculates checksum for dhcp messages. 2630f66f451Sopenharmony_cistatic uint16_t dhcp_checksum(void *addr, int count) 2640f66f451Sopenharmony_ci{ 2650f66f451Sopenharmony_ci int32_t sum = 0; 2660f66f451Sopenharmony_ci uint16_t tmp = 0, *source = (uint16_t *)addr; 2670f66f451Sopenharmony_ci 2680f66f451Sopenharmony_ci while (count > 1) { 2690f66f451Sopenharmony_ci sum += *source++; 2700f66f451Sopenharmony_ci count -= 2; 2710f66f451Sopenharmony_ci } 2720f66f451Sopenharmony_ci if (count > 0) { 2730f66f451Sopenharmony_ci *(uint8_t*)&tmp = *(uint8_t*)source; 2740f66f451Sopenharmony_ci sum += tmp; 2750f66f451Sopenharmony_ci } 2760f66f451Sopenharmony_ci while (sum >> 16) sum = (sum & 0xffff) + (sum >> 16); 2770f66f451Sopenharmony_ci return ~sum; 2780f66f451Sopenharmony_ci} 2790f66f451Sopenharmony_ci 2800f66f451Sopenharmony_ci// gets information of INTERFACE and updates IFINDEX, MAC and IP 2810f66f451Sopenharmony_cistatic int get_interface( char *interface, int *ifindex, uint32_t *oip, uint8_t *mac) 2820f66f451Sopenharmony_ci{ 2830f66f451Sopenharmony_ci struct ifreq req; 2840f66f451Sopenharmony_ci struct sockaddr_in *ip; 2850f66f451Sopenharmony_ci int fd = xsocket(AF_INET, SOCK_RAW, IPPROTO_RAW); 2860f66f451Sopenharmony_ci 2870f66f451Sopenharmony_ci req.ifr_addr.sa_family = AF_INET; 2880f66f451Sopenharmony_ci xstrncpy(req.ifr_name, interface, IFNAMSIZ); 2890f66f451Sopenharmony_ci req.ifr_name[IFNAMSIZ-1] = '\0'; 2900f66f451Sopenharmony_ci 2910f66f451Sopenharmony_ci xioctl(fd, SIOCGIFFLAGS, &req); 2920f66f451Sopenharmony_ci if (!(req.ifr_flags & IFF_UP)) return -1; 2930f66f451Sopenharmony_ci 2940f66f451Sopenharmony_ci if (oip) { 2950f66f451Sopenharmony_ci xioctl(fd, SIOCGIFADDR, &req); 2960f66f451Sopenharmony_ci ip = (struct sockaddr_in*) &req.ifr_addr; 2970f66f451Sopenharmony_ci dbg("IP %s\n", inet_ntoa(ip->sin_addr)); 2980f66f451Sopenharmony_ci *oip = ntohl(ip->sin_addr.s_addr); 2990f66f451Sopenharmony_ci } 3000f66f451Sopenharmony_ci if (ifindex) { 3010f66f451Sopenharmony_ci xioctl(fd, SIOCGIFINDEX, &req); 3020f66f451Sopenharmony_ci dbg("Adapter index %d\n", req.ifr_ifindex); 3030f66f451Sopenharmony_ci *ifindex = req.ifr_ifindex; 3040f66f451Sopenharmony_ci } 3050f66f451Sopenharmony_ci if (mac) { 3060f66f451Sopenharmony_ci xioctl(fd, SIOCGIFHWADDR, &req); 3070f66f451Sopenharmony_ci memcpy(mac, req.ifr_hwaddr.sa_data, 6); 3080f66f451Sopenharmony_ci dbg("MAC %02x:%02x:%02x:%02x:%02x:%02x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); 3090f66f451Sopenharmony_ci } 3100f66f451Sopenharmony_ci close(fd); 3110f66f451Sopenharmony_ci return 0; 3120f66f451Sopenharmony_ci} 3130f66f451Sopenharmony_ci 3140f66f451Sopenharmony_ci/* 3150f66f451Sopenharmony_ci *logs messeges to syslog or console 3160f66f451Sopenharmony_ci *opening the log is still left with applet. 3170f66f451Sopenharmony_ci *FIXME: move to more relevent lib. probably libc.c 3180f66f451Sopenharmony_ci */ 3190f66f451Sopenharmony_cistatic void infomsg(uint8_t infomode, char *s, ...) 3200f66f451Sopenharmony_ci{ 3210f66f451Sopenharmony_ci int used; 3220f66f451Sopenharmony_ci char *msg; 3230f66f451Sopenharmony_ci va_list p, t; 3240f66f451Sopenharmony_ci 3250f66f451Sopenharmony_ci if (infomode == LOG_SILENT) return; 3260f66f451Sopenharmony_ci va_start(p, s); 3270f66f451Sopenharmony_ci va_copy(t, p); 3280f66f451Sopenharmony_ci used = vsnprintf(NULL, 0, s, t); 3290f66f451Sopenharmony_ci used++; 3300f66f451Sopenharmony_ci va_end(t); 3310f66f451Sopenharmony_ci 3320f66f451Sopenharmony_ci msg = xmalloc(used); 3330f66f451Sopenharmony_ci vsnprintf(msg, used, s, p); 3340f66f451Sopenharmony_ci va_end(p); 3350f66f451Sopenharmony_ci 3360f66f451Sopenharmony_ci if (infomode & LOG_SYSTEM) syslog(LOG_INFO, "%s", msg); 3370f66f451Sopenharmony_ci if (infomode & LOG_CONSOLE) printf("%s\n", msg); 3380f66f451Sopenharmony_ci free(msg); 3390f66f451Sopenharmony_ci} 3400f66f451Sopenharmony_ci 3410f66f451Sopenharmony_ci/* 3420f66f451Sopenharmony_ci * Writes self PID in file PATH 3430f66f451Sopenharmony_ci * FIXME: libc implementation only writes in /var/run 3440f66f451Sopenharmony_ci * this is more generic as some implemenation may provide 3450f66f451Sopenharmony_ci * arguments to write in specific file. as dhcpd does. 3460f66f451Sopenharmony_ci */ 3470f66f451Sopenharmony_cistatic void write_pid(char *path) 3480f66f451Sopenharmony_ci{ 3490f66f451Sopenharmony_ci int pidfile = open(path, O_CREAT | O_WRONLY | O_TRUNC, 0666); 3500f66f451Sopenharmony_ci if (pidfile > 0) { 3510f66f451Sopenharmony_ci char pidbuf[12]; 3520f66f451Sopenharmony_ci 3530f66f451Sopenharmony_ci sprintf(pidbuf, "%u", (unsigned)getpid()); 3540f66f451Sopenharmony_ci write(pidfile, pidbuf, strlen(pidbuf)); 3550f66f451Sopenharmony_ci close(pidfile); 3560f66f451Sopenharmony_ci } 3570f66f451Sopenharmony_ci} 3580f66f451Sopenharmony_ci 3590f66f451Sopenharmony_ci// String STR to UINT32 conversion strored in VAR 3600f66f451Sopenharmony_cistatic long strtou32( char *str) 3610f66f451Sopenharmony_ci{ 3620f66f451Sopenharmony_ci char *endptr = NULL; 3630f66f451Sopenharmony_ci int base = 10; 3640f66f451Sopenharmony_ci errno=0; 3650f66f451Sopenharmony_ci if (str[0]=='0' && (str[1]=='x' || str[1]=='X')) { 3660f66f451Sopenharmony_ci base = 16; 3670f66f451Sopenharmony_ci str+=2; 3680f66f451Sopenharmony_ci } 3690f66f451Sopenharmony_ci long ret_val = strtol(str, &endptr, base); 3700f66f451Sopenharmony_ci if (errno) return -1; 3710f66f451Sopenharmony_ci else if (endptr && (*endptr!='\0'||endptr == str)) return -1; 3720f66f451Sopenharmony_ci return ret_val; 3730f66f451Sopenharmony_ci} 3740f66f451Sopenharmony_ci 3750f66f451Sopenharmony_ci// IP String STR to binary data. 3760f66f451Sopenharmony_cistatic int striptovar( char *str, void *var) 3770f66f451Sopenharmony_ci{ 3780f66f451Sopenharmony_ci in_addr_t addr; 3790f66f451Sopenharmony_ci if(!str) error_exit("NULL address string."); 3800f66f451Sopenharmony_ci addr = inet_addr(str); 3810f66f451Sopenharmony_ci if(addr == -1) error_exit("Wrong address %s.",str ); 3820f66f451Sopenharmony_ci *((uint32_t*)(var)) = (uint32_t)addr; 3830f66f451Sopenharmony_ci return 0; 3840f66f451Sopenharmony_ci} 3850f66f451Sopenharmony_ci 3860f66f451Sopenharmony_ci// String to dhcp option conversion 3870f66f451Sopenharmony_cistatic int strtoopt( char *str, uint8_t optonly) 3880f66f451Sopenharmony_ci{ 3890f66f451Sopenharmony_ci char *option, *valstr, *grp, *tp; 3900f66f451Sopenharmony_ci long optcode = 0, convtmp; 3910f66f451Sopenharmony_ci uint16_t flag = 0; 3920f66f451Sopenharmony_ci uint32_t mask, nip, router; 3930f66f451Sopenharmony_ci int count, size = ARRAY_LEN(options_list); 3940f66f451Sopenharmony_ci 3950f66f451Sopenharmony_ci if (!*str) return 0; 3960f66f451Sopenharmony_ci option = strtok((char*)str, ":"); 3970f66f451Sopenharmony_ci if (!option) return -1; 3980f66f451Sopenharmony_ci 3990f66f451Sopenharmony_ci dbg("-x option : %s ", option); 4000f66f451Sopenharmony_ci optcode = strtou32(option); 4010f66f451Sopenharmony_ci 4020f66f451Sopenharmony_ci if (optcode > 0 && optcode < 256) { // raw option 4030f66f451Sopenharmony_ci for (count = 0; count < size; count++) { 4040f66f451Sopenharmony_ci if ((options_list[count].code & 0X00FF) == optcode) { 4050f66f451Sopenharmony_ci flag = (options_list[count].code & 0XFF00); 4060f66f451Sopenharmony_ci break; 4070f66f451Sopenharmony_ci } 4080f66f451Sopenharmony_ci } 4090f66f451Sopenharmony_ci if (count == size) error_exit("Obsolete OR Unknown Option : %s", option); 4100f66f451Sopenharmony_ci } else { // string option 4110f66f451Sopenharmony_ci for (count = 0; count < size; count++) { 4120f66f451Sopenharmony_ci if (!strcmp(options_list[count].key, option)) { 4130f66f451Sopenharmony_ci flag = (options_list[count].code & 0XFF00); 4140f66f451Sopenharmony_ci optcode = (options_list[count].code & 0X00FF); 4150f66f451Sopenharmony_ci break; 4160f66f451Sopenharmony_ci } 4170f66f451Sopenharmony_ci } 4180f66f451Sopenharmony_ci if (count == size) error_exit("Obsolete OR Unknown Option : %s", option); 4190f66f451Sopenharmony_ci } 4200f66f451Sopenharmony_ci if (!flag || !optcode) return -1; 4210f66f451Sopenharmony_ci if (optonly) return optcode; 4220f66f451Sopenharmony_ci 4230f66f451Sopenharmony_ci valstr = strtok(NULL, "\n"); 4240f66f451Sopenharmony_ci if (!valstr) error_exit("option %s has no value defined.\n", option); 4250f66f451Sopenharmony_ci dbg(" value : %-20s \n ", valstr); 4260f66f451Sopenharmony_ci switch (flag) { 4270f66f451Sopenharmony_ci case DHCP_NUM32: 4280f66f451Sopenharmony_ci options_list[count].len = sizeof(uint32_t); 4290f66f451Sopenharmony_ci options_list[count].val = xmalloc(sizeof(uint32_t)); 4300f66f451Sopenharmony_ci convtmp = strtou32(valstr); 4310f66f451Sopenharmony_ci if (convtmp < 0) error_exit("Invalid/wrong formatted number %s", valstr); 4320f66f451Sopenharmony_ci convtmp = htonl(convtmp); 4330f66f451Sopenharmony_ci memcpy(options_list[count].val, &convtmp, sizeof(uint32_t)); 4340f66f451Sopenharmony_ci break; 4350f66f451Sopenharmony_ci case DHCP_NUM16: 4360f66f451Sopenharmony_ci options_list[count].len = sizeof(uint16_t); 4370f66f451Sopenharmony_ci options_list[count].val = xmalloc(sizeof(uint16_t)); 4380f66f451Sopenharmony_ci convtmp = strtou32(valstr); 4390f66f451Sopenharmony_ci if (convtmp < 0) error_exit("Invalid/malformed number %s", valstr); 4400f66f451Sopenharmony_ci convtmp = htons(convtmp); 4410f66f451Sopenharmony_ci memcpy(options_list[count].val, &convtmp, sizeof(uint16_t)); 4420f66f451Sopenharmony_ci break; 4430f66f451Sopenharmony_ci case DHCP_NUM8: 4440f66f451Sopenharmony_ci options_list[count].len = sizeof(uint8_t); 4450f66f451Sopenharmony_ci options_list[count].val = xmalloc(sizeof(uint8_t)); 4460f66f451Sopenharmony_ci convtmp = strtou32(valstr); 4470f66f451Sopenharmony_ci if (convtmp < 0) error_exit("Invalid/malformed number %s", valstr); 4480f66f451Sopenharmony_ci memcpy(options_list[count].val, &convtmp, sizeof(uint8_t)); 4490f66f451Sopenharmony_ci break; 4500f66f451Sopenharmony_ci case DHCP_IP: 4510f66f451Sopenharmony_ci options_list[count].len = sizeof(uint32_t); 4520f66f451Sopenharmony_ci options_list[count].val = xmalloc(sizeof(uint32_t)); 4530f66f451Sopenharmony_ci striptovar(valstr, options_list[count].val); 4540f66f451Sopenharmony_ci break; 4550f66f451Sopenharmony_ci case DHCP_STRING: 4560f66f451Sopenharmony_ci options_list[count].len = strlen(valstr); 4570f66f451Sopenharmony_ci options_list[count].val = strdup(valstr); 4580f66f451Sopenharmony_ci break; 4590f66f451Sopenharmony_ci case DHCP_IPLIST: 4600f66f451Sopenharmony_ci while(valstr){ 4610f66f451Sopenharmony_ci options_list[count].val = xrealloc(options_list[count].val, options_list[count].len + sizeof(uint32_t)); 4620f66f451Sopenharmony_ci striptovar(valstr, ((uint8_t*)options_list[count].val)+options_list[count].len); 4630f66f451Sopenharmony_ci options_list[count].len += sizeof(uint32_t); 4640f66f451Sopenharmony_ci valstr = strtok(NULL," \t"); 4650f66f451Sopenharmony_ci } 4660f66f451Sopenharmony_ci break; 4670f66f451Sopenharmony_ci case DHCP_STRLST: 4680f66f451Sopenharmony_ci case DHCP_IPPLST: 4690f66f451Sopenharmony_ci break; 4700f66f451Sopenharmony_ci case DHCP_STCRTS: 4710f66f451Sopenharmony_ci /* Option binary format: 4720f66f451Sopenharmony_ci * mask [one byte, 0..32] 4730f66f451Sopenharmony_ci * ip [0..4 bytes depending on mask] 4740f66f451Sopenharmony_ci * router [4 bytes] 4750f66f451Sopenharmony_ci * may be repeated 4760f66f451Sopenharmony_ci * staticroutes 10.0.0.0/8 10.127.0.1, 10.11.12.0/24 10.11.12.1 4770f66f451Sopenharmony_ci */ 4780f66f451Sopenharmony_ci grp = strtok(valstr, ",");; 4790f66f451Sopenharmony_ci while(grp){ 4800f66f451Sopenharmony_ci while(*grp == ' ' || *grp == '\t') grp++; 4810f66f451Sopenharmony_ci tp = strchr(grp, '/'); 4820f66f451Sopenharmony_ci if (!tp) error_exit("malformed static route option"); 4830f66f451Sopenharmony_ci *tp = '\0'; 4840f66f451Sopenharmony_ci mask = strtol(++tp, &tp, 10); 4850f66f451Sopenharmony_ci if (striptovar(grp, (uint8_t*)&nip) < 0) error_exit("malformed static route option"); 4860f66f451Sopenharmony_ci while(*tp == ' ' || *tp == '\t' || *tp == '-') tp++; 4870f66f451Sopenharmony_ci if (striptovar(tp, (uint8_t*)&router) < 0) error_exit("malformed static route option"); 4880f66f451Sopenharmony_ci options_list[count].val = xrealloc(options_list[count].val, options_list[count].len + 1 + mask/8 + 4); 4890f66f451Sopenharmony_ci memcpy(((uint8_t*)options_list[count].val)+options_list[count].len, &mask, 1); 4900f66f451Sopenharmony_ci options_list[count].len += 1; 4910f66f451Sopenharmony_ci memcpy(((uint8_t*)options_list[count].val)+options_list[count].len, &nip, mask/8); 4920f66f451Sopenharmony_ci options_list[count].len += mask/8; 4930f66f451Sopenharmony_ci memcpy(((uint8_t*)options_list[count].val)+options_list[count].len, &router, 4); 4940f66f451Sopenharmony_ci options_list[count].len += 4; 4950f66f451Sopenharmony_ci tp = NULL; 4960f66f451Sopenharmony_ci grp = strtok(NULL, ","); 4970f66f451Sopenharmony_ci } 4980f66f451Sopenharmony_ci break; 4990f66f451Sopenharmony_ci } 5000f66f451Sopenharmony_ci return 0; 5010f66f451Sopenharmony_ci} 5020f66f451Sopenharmony_ci 5030f66f451Sopenharmony_ci// Creates environment pointers from RES to use in script 5040f66f451Sopenharmony_cistatic int fill_envp(dhcpc_result_t *res) 5050f66f451Sopenharmony_ci{ 5060f66f451Sopenharmony_ci struct in_addr temp; 5070f66f451Sopenharmony_ci int size = ARRAY_LEN(options_list), count, ret = -1; 5080f66f451Sopenharmony_ci 5090f66f451Sopenharmony_ci ret = setenv("interface", state->iface, 1); 5100f66f451Sopenharmony_ci if (!res) return ret; 5110f66f451Sopenharmony_ci if (res->ipaddr.s_addr) { 5120f66f451Sopenharmony_ci temp.s_addr = htonl(res->ipaddr.s_addr); 5130f66f451Sopenharmony_ci ret = setenv("ip", inet_ntoa(temp), 1); 5140f66f451Sopenharmony_ci if (ret) return ret; 5150f66f451Sopenharmony_ci } 5160f66f451Sopenharmony_ci if (msgopt_list) { 5170f66f451Sopenharmony_ci for (count = 0; count < size; count++) { 5180f66f451Sopenharmony_ci if ((msgopt_list[count].len == 0) || (msgopt_list[count].val == NULL)) continue; 5190f66f451Sopenharmony_ci ret = setenv(msgopt_list[count].key, (char*)msgopt_list[count].val, 1); 5200f66f451Sopenharmony_ci if (ret) return ret; 5210f66f451Sopenharmony_ci } 5220f66f451Sopenharmony_ci } 5230f66f451Sopenharmony_ci return ret; 5240f66f451Sopenharmony_ci} 5250f66f451Sopenharmony_ci 5260f66f451Sopenharmony_ci// Executes Script NAME. 5270f66f451Sopenharmony_cistatic void run_script(dhcpc_result_t *res, char *name) 5280f66f451Sopenharmony_ci{ 5290f66f451Sopenharmony_ci volatile int error = 0; 5300f66f451Sopenharmony_ci pid_t pid; 5310f66f451Sopenharmony_ci char *argv[3]; 5320f66f451Sopenharmony_ci struct stat sts; 5330f66f451Sopenharmony_ci char *script = (toys.optflags & FLAG_s) ? TT.script 5340f66f451Sopenharmony_ci : "/usr/share/dhcp/default.script"; 5350f66f451Sopenharmony_ci 5360f66f451Sopenharmony_ci if (stat(script, &sts) == -1 && errno == ENOENT) return; 5370f66f451Sopenharmony_ci if (fill_envp(res)) { 5380f66f451Sopenharmony_ci dbg("Failed to create environment variables."); 5390f66f451Sopenharmony_ci return; 5400f66f451Sopenharmony_ci } 5410f66f451Sopenharmony_ci dbg("Executing %s %s\n", script, name); 5420f66f451Sopenharmony_ci argv[0] = (char*) script; 5430f66f451Sopenharmony_ci argv[1] = (char*) name; 5440f66f451Sopenharmony_ci argv[2] = NULL; 5450f66f451Sopenharmony_ci fflush(NULL); 5460f66f451Sopenharmony_ci 5470f66f451Sopenharmony_ci pid = vfork(); 5480f66f451Sopenharmony_ci if (pid < 0) { 5490f66f451Sopenharmony_ci dbg("Fork failed.\n"); 5500f66f451Sopenharmony_ci return; 5510f66f451Sopenharmony_ci } 5520f66f451Sopenharmony_ci if (!pid) { 5530f66f451Sopenharmony_ci execvp(argv[0], argv); 5540f66f451Sopenharmony_ci error = errno; 5550f66f451Sopenharmony_ci _exit(111); 5560f66f451Sopenharmony_ci } 5570f66f451Sopenharmony_ci if (error) { 5580f66f451Sopenharmony_ci waitpid(pid, NULL,0); 5590f66f451Sopenharmony_ci errno = error; 5600f66f451Sopenharmony_ci perror_msg("script exec failed"); 5610f66f451Sopenharmony_ci } 5620f66f451Sopenharmony_ci dbg("script complete.\n"); 5630f66f451Sopenharmony_ci} 5640f66f451Sopenharmony_ci 5650f66f451Sopenharmony_ci// returns a randome ID 5660f66f451Sopenharmony_cistatic uint32_t getxid(void) 5670f66f451Sopenharmony_ci{ 5680f66f451Sopenharmony_ci uint32_t randnum; 5690f66f451Sopenharmony_ci int fd = xopenro("/dev/urandom"); 5700f66f451Sopenharmony_ci 5710f66f451Sopenharmony_ci// TODO xreadfile 5720f66f451Sopenharmony_ci xreadall(fd, &randnum, sizeof(randnum)); 5730f66f451Sopenharmony_ci xclose(fd); 5740f66f451Sopenharmony_ci return randnum; 5750f66f451Sopenharmony_ci} 5760f66f451Sopenharmony_ci 5770f66f451Sopenharmony_ci// opens socket in raw mode. 5780f66f451Sopenharmony_cistatic int mode_raw(void) 5790f66f451Sopenharmony_ci{ 5800f66f451Sopenharmony_ci state->mode = MODE_OFF; 5810f66f451Sopenharmony_ci struct sockaddr_ll sock; 5820f66f451Sopenharmony_ci 5830f66f451Sopenharmony_ci if (state->sockfd > 0) close(state->sockfd); 5840f66f451Sopenharmony_ci dbg("Opening raw socket on ifindex %d\n", state->ifindex); 5850f66f451Sopenharmony_ci 5860f66f451Sopenharmony_ci state->sockfd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP)); 5870f66f451Sopenharmony_ci if (state->sockfd < 0) { 5880f66f451Sopenharmony_ci dbg("MODE RAW : socket fail ERROR : %d\n", state->sockfd); 5890f66f451Sopenharmony_ci return -1; 5900f66f451Sopenharmony_ci } 5910f66f451Sopenharmony_ci dbg("Got raw socket fd %d\n", state->sockfd); 5920f66f451Sopenharmony_ci memset(&sock, 0, sizeof(sock)); 5930f66f451Sopenharmony_ci sock.sll_family = AF_PACKET; 5940f66f451Sopenharmony_ci sock.sll_protocol = htons(ETH_P_IP); 5950f66f451Sopenharmony_ci sock.sll_ifindex = state->ifindex; 5960f66f451Sopenharmony_ci 5970f66f451Sopenharmony_ci if (bind(state->sockfd, (struct sockaddr *) &sock, sizeof(sock))) { 5980f66f451Sopenharmony_ci dbg("MODE RAW : bind fail.\n"); 5990f66f451Sopenharmony_ci close(state->sockfd); 6000f66f451Sopenharmony_ci return -1; 6010f66f451Sopenharmony_ci } 6020f66f451Sopenharmony_ci state->mode = MODE_RAW; 6030f66f451Sopenharmony_ci if (setsockopt(state->sockfd, SOL_SOCKET, SO_ATTACH_FILTER, &filter_prog, sizeof(filter_prog)) < 0) 6040f66f451Sopenharmony_ci dbg("MODE RAW : filter attach fail.\n"); 6050f66f451Sopenharmony_ci 6060f66f451Sopenharmony_ci dbg("MODE RAW : success\n"); 6070f66f451Sopenharmony_ci return 0; 6080f66f451Sopenharmony_ci} 6090f66f451Sopenharmony_ci 6100f66f451Sopenharmony_ci// opens UDP socket 6110f66f451Sopenharmony_cistatic int mode_app(void) 6120f66f451Sopenharmony_ci{ 6130f66f451Sopenharmony_ci struct sockaddr_in addr; 6140f66f451Sopenharmony_ci struct ifreq ifr; 6150f66f451Sopenharmony_ci 6160f66f451Sopenharmony_ci state->mode = MODE_OFF; 6170f66f451Sopenharmony_ci if (state->sockfd > 0) close(state->sockfd); 6180f66f451Sopenharmony_ci 6190f66f451Sopenharmony_ci dbg("Opening listen socket on *:%d %s\n", DHCPC_CLIENT_PORT, state->iface); 6200f66f451Sopenharmony_ci state->sockfd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); 6210f66f451Sopenharmony_ci if (state->sockfd < 0) { 6220f66f451Sopenharmony_ci dbg("MODE APP : socket fail ERROR: %d\n", state->sockfd); 6230f66f451Sopenharmony_ci return -1; 6240f66f451Sopenharmony_ci } 6250f66f451Sopenharmony_ci setsockopt(state->sockfd, SOL_SOCKET, SO_REUSEADDR, &set, sizeof(set)); 6260f66f451Sopenharmony_ci if (setsockopt(state->sockfd, SOL_SOCKET, SO_BROADCAST, &set, sizeof(set)) == -1) { 6270f66f451Sopenharmony_ci dbg("MODE APP : brodcast failed.\n"); 6280f66f451Sopenharmony_ci close(state->sockfd); 6290f66f451Sopenharmony_ci return -1; 6300f66f451Sopenharmony_ci } 6310f66f451Sopenharmony_ci xstrncpy(ifr.ifr_name, state->iface, IFNAMSIZ); 6320f66f451Sopenharmony_ci ifr.ifr_name[IFNAMSIZ -1] = '\0'; 6330f66f451Sopenharmony_ci setsockopt(state->sockfd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)); 6340f66f451Sopenharmony_ci 6350f66f451Sopenharmony_ci memset(&addr, 0, sizeof(addr)); 6360f66f451Sopenharmony_ci addr.sin_family = AF_INET; 6370f66f451Sopenharmony_ci addr.sin_port = htons(DHCPC_CLIENT_PORT); 6380f66f451Sopenharmony_ci addr.sin_addr.s_addr = INADDR_ANY ; 6390f66f451Sopenharmony_ci 6400f66f451Sopenharmony_ci if (bind(state->sockfd, (struct sockaddr *) &addr, sizeof(addr))) { 6410f66f451Sopenharmony_ci close(state->sockfd); 6420f66f451Sopenharmony_ci dbg("MODE APP : bind failed.\n"); 6430f66f451Sopenharmony_ci return -1; 6440f66f451Sopenharmony_ci } 6450f66f451Sopenharmony_ci state->mode = MODE_APP; 6460f66f451Sopenharmony_ci dbg("MODE APP : success\n"); 6470f66f451Sopenharmony_ci return 0; 6480f66f451Sopenharmony_ci} 6490f66f451Sopenharmony_ci 6500f66f451Sopenharmony_cistatic int read_raw(void) 6510f66f451Sopenharmony_ci{ 6520f66f451Sopenharmony_ci dhcp_raw_t packet; 6530f66f451Sopenharmony_ci int bytes = 0; 6540f66f451Sopenharmony_ci 6550f66f451Sopenharmony_ci memset(&packet, 0, sizeof(packet)); 6560f66f451Sopenharmony_ci if ((bytes = read(state->sockfd, &packet, sizeof(packet))) < 0) { 6570f66f451Sopenharmony_ci dbg("\tPacket read error, ignoring\n"); 6580f66f451Sopenharmony_ci return bytes; 6590f66f451Sopenharmony_ci } 6600f66f451Sopenharmony_ci if (bytes < (int) (sizeof(packet.iph) + sizeof(packet.udph))) { 6610f66f451Sopenharmony_ci dbg("\tPacket is too short, ignoring\n"); 6620f66f451Sopenharmony_ci return -2; 6630f66f451Sopenharmony_ci } 6640f66f451Sopenharmony_ci if (bytes < ntohs(packet.iph.tot_len)) { 6650f66f451Sopenharmony_ci dbg("\tOversized packet, ignoring\n"); 6660f66f451Sopenharmony_ci return -2; 6670f66f451Sopenharmony_ci } 6680f66f451Sopenharmony_ci // ignore any extra garbage bytes 6690f66f451Sopenharmony_ci bytes = ntohs(packet.iph.tot_len); 6700f66f451Sopenharmony_ci // make sure its the right packet for us, and that it passes sanity checks 6710f66f451Sopenharmony_ci if (packet.iph.protocol != IPPROTO_UDP || packet.iph.version != IPVERSION 6720f66f451Sopenharmony_ci || packet.iph.ihl != (sizeof(packet.iph) >> 2) 6730f66f451Sopenharmony_ci || packet.udph.dest != htons(DHCPC_CLIENT_PORT) 6740f66f451Sopenharmony_ci || ntohs(packet.udph.len) != (uint16_t)(bytes - sizeof(packet.iph))) { 6750f66f451Sopenharmony_ci dbg("\tUnrelated/bogus packet, ignoring\n"); 6760f66f451Sopenharmony_ci return -2; 6770f66f451Sopenharmony_ci } 6780f66f451Sopenharmony_ci // Verify IP checksum. 6790f66f451Sopenharmony_ci if (dhcp_checksum(&packet.iph, sizeof(packet.iph)) != 0) { 6800f66f451Sopenharmony_ci dbg("\tBad IP header checksum, ignoring\n"); 6810f66f451Sopenharmony_ci return -2; 6820f66f451Sopenharmony_ci } 6830f66f451Sopenharmony_ci // Verify UDP checksum. From RFC 768, the UDP checksum is done over the IPv4 6840f66f451Sopenharmony_ci // pseudo header, the UDP header and the UDP data. The IPv4 pseudo header 6850f66f451Sopenharmony_ci // includes saddr, daddr, protocol, and UDP length. The IP header has to be 6860f66f451Sopenharmony_ci // modified for this. 6870f66f451Sopenharmony_ci memset(&packet.iph, 0, ((size_t) &((struct iphdr *)0)->protocol)); 6880f66f451Sopenharmony_ci packet.iph.check = 0; 6890f66f451Sopenharmony_ci packet.iph.tot_len = packet.udph.len; 6900f66f451Sopenharmony_ci if (packet.udph.check != 0 && dhcp_checksum(&packet, bytes) != 0) { 6910f66f451Sopenharmony_ci dbg("\tPacket with bad UDP checksum received, ignoring\n"); 6920f66f451Sopenharmony_ci return -2; 6930f66f451Sopenharmony_ci } 6940f66f451Sopenharmony_ci memcpy(&state->pdhcp, &packet.dhcp, bytes - (sizeof(packet.iph) + sizeof(packet.udph))); 6950f66f451Sopenharmony_ci if (state->pdhcp.cookie != htonl(DHCP_MAGIC)) { 6960f66f451Sopenharmony_ci dbg("\tPacket with bad magic, ignoring\n"); 6970f66f451Sopenharmony_ci return -2; 6980f66f451Sopenharmony_ci } 6990f66f451Sopenharmony_ci return bytes - sizeof(packet.iph) - sizeof(packet.udph); 7000f66f451Sopenharmony_ci} 7010f66f451Sopenharmony_ci 7020f66f451Sopenharmony_cistatic int read_app(void) 7030f66f451Sopenharmony_ci{ 7040f66f451Sopenharmony_ci int ret; 7050f66f451Sopenharmony_ci 7060f66f451Sopenharmony_ci memset(&state->pdhcp, 0, sizeof(dhcp_msg_t)); 7070f66f451Sopenharmony_ci if ((ret = read(state->sockfd, &state->pdhcp, sizeof(dhcp_msg_t))) < 0) { 7080f66f451Sopenharmony_ci dbg("Packet read error, ignoring\n"); 7090f66f451Sopenharmony_ci return ret; /* returns -1 */ 7100f66f451Sopenharmony_ci } 7110f66f451Sopenharmony_ci if (state->pdhcp.cookie != htonl(DHCP_MAGIC)) { 7120f66f451Sopenharmony_ci dbg("Packet with bad magic, ignoring\n"); 7130f66f451Sopenharmony_ci return -2; 7140f66f451Sopenharmony_ci } 7150f66f451Sopenharmony_ci return ret; 7160f66f451Sopenharmony_ci} 7170f66f451Sopenharmony_ci 7180f66f451Sopenharmony_ci// Sends data through raw socket. 7190f66f451Sopenharmony_cistatic int send_raw(void) 7200f66f451Sopenharmony_ci{ 7210f66f451Sopenharmony_ci struct sockaddr_ll dest_sll; 7220f66f451Sopenharmony_ci dhcp_raw_t packet; 7230f66f451Sopenharmony_ci unsigned padding; 7240f66f451Sopenharmony_ci int fd, result = -1; 7250f66f451Sopenharmony_ci 7260f66f451Sopenharmony_ci memset(&packet, 0, sizeof(dhcp_raw_t)); 7270f66f451Sopenharmony_ci memcpy(&packet.dhcp, &state->pdhcp, sizeof(dhcp_msg_t)); 7280f66f451Sopenharmony_ci 7290f66f451Sopenharmony_ci if ((fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) { 7300f66f451Sopenharmony_ci dbg("SEND RAW: socket failed\n"); 7310f66f451Sopenharmony_ci return result; 7320f66f451Sopenharmony_ci } 7330f66f451Sopenharmony_ci memset(&dest_sll, 0, sizeof(dest_sll)); 7340f66f451Sopenharmony_ci dest_sll.sll_family = AF_PACKET; 7350f66f451Sopenharmony_ci dest_sll.sll_protocol = htons(ETH_P_IP); 7360f66f451Sopenharmony_ci dest_sll.sll_ifindex = state->ifindex; 7370f66f451Sopenharmony_ci dest_sll.sll_halen = 6; 7380f66f451Sopenharmony_ci memcpy(dest_sll.sll_addr, bmacaddr , 6); 7390f66f451Sopenharmony_ci 7400f66f451Sopenharmony_ci if (bind(fd, (struct sockaddr *) &dest_sll, sizeof(dest_sll)) < 0) { 7410f66f451Sopenharmony_ci dbg("SEND RAW: bind failed\n"); 7420f66f451Sopenharmony_ci close(fd); 7430f66f451Sopenharmony_ci return result; 7440f66f451Sopenharmony_ci } 7450f66f451Sopenharmony_ci padding = 308 - 1 - dhcp_opt_size(state->pdhcp.options); 7460f66f451Sopenharmony_ci packet.iph.protocol = IPPROTO_UDP; 7470f66f451Sopenharmony_ci packet.iph.saddr = INADDR_ANY; 7480f66f451Sopenharmony_ci packet.iph.daddr = INADDR_BROADCAST; 7490f66f451Sopenharmony_ci packet.udph.source = htons(DHCPC_CLIENT_PORT); 7500f66f451Sopenharmony_ci packet.udph.dest = htons(DHCPC_SERVER_PORT); 7510f66f451Sopenharmony_ci packet.udph.len = htons(sizeof(dhcp_raw_t) - sizeof(struct iphdr) - padding); 7520f66f451Sopenharmony_ci packet.iph.tot_len = packet.udph.len; 7530f66f451Sopenharmony_ci packet.udph.check = dhcp_checksum(&packet, sizeof(dhcp_raw_t) - padding); 7540f66f451Sopenharmony_ci packet.iph.tot_len = htons(sizeof(dhcp_raw_t) - padding); 7550f66f451Sopenharmony_ci packet.iph.ihl = sizeof(packet.iph) >> 2; 7560f66f451Sopenharmony_ci packet.iph.version = IPVERSION; 7570f66f451Sopenharmony_ci packet.iph.ttl = IPDEFTTL; 7580f66f451Sopenharmony_ci packet.iph.check = dhcp_checksum(&packet.iph, sizeof(packet.iph)); 7590f66f451Sopenharmony_ci 7600f66f451Sopenharmony_ci result = sendto(fd, &packet, sizeof(dhcp_raw_t) - padding, 0, 7610f66f451Sopenharmony_ci (struct sockaddr *) &dest_sll, sizeof(dest_sll)); 7620f66f451Sopenharmony_ci 7630f66f451Sopenharmony_ci close(fd); 7640f66f451Sopenharmony_ci if (result < 0) dbg("SEND RAW: PACKET send error\n"); 7650f66f451Sopenharmony_ci return result; 7660f66f451Sopenharmony_ci} 7670f66f451Sopenharmony_ci 7680f66f451Sopenharmony_ci// Sends data through UDP socket. 7690f66f451Sopenharmony_cistatic int send_app(void) 7700f66f451Sopenharmony_ci{ 7710f66f451Sopenharmony_ci struct sockaddr_in cli; 7720f66f451Sopenharmony_ci int fd, ret = -1; 7730f66f451Sopenharmony_ci 7740f66f451Sopenharmony_ci if ((fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { 7750f66f451Sopenharmony_ci dbg("SEND APP: sock failed.\n"); 7760f66f451Sopenharmony_ci return ret; 7770f66f451Sopenharmony_ci } 7780f66f451Sopenharmony_ci setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &set, sizeof(set)); 7790f66f451Sopenharmony_ci 7800f66f451Sopenharmony_ci memset(&cli, 0, sizeof(cli)); 7810f66f451Sopenharmony_ci cli.sin_family = AF_INET; 7820f66f451Sopenharmony_ci cli.sin_port = htons(DHCPC_CLIENT_PORT); 7830f66f451Sopenharmony_ci cli.sin_addr.s_addr = state->pdhcp.ciaddr; 7840f66f451Sopenharmony_ci if (bind(fd, (struct sockaddr *)&cli, sizeof(cli)) == -1) { 7850f66f451Sopenharmony_ci dbg("SEND APP: bind failed.\n"); 7860f66f451Sopenharmony_ci goto error_fd; 7870f66f451Sopenharmony_ci } 7880f66f451Sopenharmony_ci memset(&cli, 0, sizeof(cli)); 7890f66f451Sopenharmony_ci cli.sin_family = AF_INET; 7900f66f451Sopenharmony_ci cli.sin_port = htons(DHCPC_SERVER_PORT); 7910f66f451Sopenharmony_ci cli.sin_addr.s_addr = state->serverid.s_addr; 7920f66f451Sopenharmony_ci if (connect(fd, (struct sockaddr *)&cli, sizeof(cli)) == -1) { 7930f66f451Sopenharmony_ci dbg("SEND APP: connect failed.\n"); 7940f66f451Sopenharmony_ci goto error_fd; 7950f66f451Sopenharmony_ci } 7960f66f451Sopenharmony_ci int padding = 308 - 1 - dhcp_opt_size(state->pdhcp.options); 7970f66f451Sopenharmony_ci if((ret = write(fd, &state->pdhcp, sizeof(dhcp_msg_t) - padding)) < 0) { 7980f66f451Sopenharmony_ci dbg("SEND APP: write failed error %d\n", ret); 7990f66f451Sopenharmony_ci goto error_fd; 8000f66f451Sopenharmony_ci } 8010f66f451Sopenharmony_ci dbg("SEND APP: write success wrote %d\n", ret); 8020f66f451Sopenharmony_cierror_fd: 8030f66f451Sopenharmony_ci close(fd); 8040f66f451Sopenharmony_ci return ret; 8050f66f451Sopenharmony_ci} 8060f66f451Sopenharmony_ci 8070f66f451Sopenharmony_ci// Generic signal handler real handling is done in main funcrion. 8080f66f451Sopenharmony_cistatic void signal_handler(int sig) 8090f66f451Sopenharmony_ci{ 8100f66f451Sopenharmony_ci unsigned char ch = sig; 8110f66f451Sopenharmony_ci if (write(sigfd.wr, &ch, 1) != 1) dbg("can't send signal\n"); 8120f66f451Sopenharmony_ci} 8130f66f451Sopenharmony_ci 8140f66f451Sopenharmony_ci// signal setup for SIGUSR1 SIGUSR2 SIGTERM 8150f66f451Sopenharmony_cistatic int setup_signal() 8160f66f451Sopenharmony_ci{ 8170f66f451Sopenharmony_ci if (pipe((int *)&sigfd) < 0) { 8180f66f451Sopenharmony_ci dbg("signal pipe failed\n"); 8190f66f451Sopenharmony_ci return -1; 8200f66f451Sopenharmony_ci } 8210f66f451Sopenharmony_ci fcntl(sigfd.wr , F_SETFD, FD_CLOEXEC); 8220f66f451Sopenharmony_ci fcntl(sigfd.rd , F_SETFD, FD_CLOEXEC); 8230f66f451Sopenharmony_ci int flags = fcntl(sigfd.wr, F_GETFL); 8240f66f451Sopenharmony_ci fcntl(sigfd.wr, F_SETFL, flags | O_NONBLOCK); 8250f66f451Sopenharmony_ci signal(SIGUSR1, signal_handler); 8260f66f451Sopenharmony_ci signal(SIGUSR2, signal_handler); 8270f66f451Sopenharmony_ci signal(SIGTERM, signal_handler); 8280f66f451Sopenharmony_ci 8290f66f451Sopenharmony_ci return 0; 8300f66f451Sopenharmony_ci} 8310f66f451Sopenharmony_ci 8320f66f451Sopenharmony_ci// adds client id to dhcp packet 8330f66f451Sopenharmony_cistatic uint8_t *dhcpc_addclientid(uint8_t *optptr) 8340f66f451Sopenharmony_ci{ 8350f66f451Sopenharmony_ci *optptr++ = DHCP_OPTION_CLIENTID; 8360f66f451Sopenharmony_ci *optptr++ = 7; 8370f66f451Sopenharmony_ci *optptr++ = 1; 8380f66f451Sopenharmony_ci memcpy(optptr, &state->macaddr, 6); 8390f66f451Sopenharmony_ci return optptr + 6; 8400f66f451Sopenharmony_ci} 8410f66f451Sopenharmony_ci 8420f66f451Sopenharmony_ci// adds messege type to dhcp packet 8430f66f451Sopenharmony_cistatic uint8_t *dhcpc_addmsgtype(uint8_t *optptr, uint8_t type) 8440f66f451Sopenharmony_ci{ 8450f66f451Sopenharmony_ci *optptr++ = DHCP_OPTION_MSG_TYPE; 8460f66f451Sopenharmony_ci *optptr++ = 1; 8470f66f451Sopenharmony_ci *optptr++ = type; 8480f66f451Sopenharmony_ci return optptr; 8490f66f451Sopenharmony_ci} 8500f66f451Sopenharmony_ci 8510f66f451Sopenharmony_ci// adds max size to dhcp packet 8520f66f451Sopenharmony_cistatic uint8_t *dhcpc_addmaxsize(uint8_t *optptr, uint16_t size) 8530f66f451Sopenharmony_ci{ 8540f66f451Sopenharmony_ci *optptr++ = DHCP_OPTION_MAX_SIZE; 8550f66f451Sopenharmony_ci *optptr++ = 2; 8560f66f451Sopenharmony_ci memcpy(optptr, &size, 2); 8570f66f451Sopenharmony_ci return optptr + 2; 8580f66f451Sopenharmony_ci} 8590f66f451Sopenharmony_ci 8600f66f451Sopenharmony_cistatic uint8_t *dhcpc_addstropt(uint8_t *optptr, uint8_t opcode, char* str, int len) 8610f66f451Sopenharmony_ci{ 8620f66f451Sopenharmony_ci *optptr++ = opcode; 8630f66f451Sopenharmony_ci *optptr++ = len; 8640f66f451Sopenharmony_ci memcpy(optptr, str, len); 8650f66f451Sopenharmony_ci return optptr + len; 8660f66f451Sopenharmony_ci} 8670f66f451Sopenharmony_ci 8680f66f451Sopenharmony_ci// adds server id to dhcp packet. 8690f66f451Sopenharmony_cistatic uint8_t *dhcpc_addserverid(struct in_addr *serverid, uint8_t *optptr) 8700f66f451Sopenharmony_ci{ 8710f66f451Sopenharmony_ci *optptr++ = DHCP_OPTION_SERVER_ID; 8720f66f451Sopenharmony_ci *optptr++ = 4; 8730f66f451Sopenharmony_ci memcpy(optptr, &serverid->s_addr, 4); 8740f66f451Sopenharmony_ci return optptr + 4; 8750f66f451Sopenharmony_ci} 8760f66f451Sopenharmony_ci 8770f66f451Sopenharmony_ci// adds requested ip address to dhcp packet. 8780f66f451Sopenharmony_cistatic uint8_t *dhcpc_addreqipaddr(struct in_addr *ipaddr, uint8_t *optptr) 8790f66f451Sopenharmony_ci{ 8800f66f451Sopenharmony_ci *optptr++ = DHCP_OPTION_REQ_IPADDR; 8810f66f451Sopenharmony_ci *optptr++ = 4; 8820f66f451Sopenharmony_ci memcpy(optptr, &ipaddr->s_addr, 4); 8830f66f451Sopenharmony_ci return optptr + 4; 8840f66f451Sopenharmony_ci} 8850f66f451Sopenharmony_ci 8860f66f451Sopenharmony_ci// adds hostname to dhcp packet. 8870f66f451Sopenharmony_cistatic uint8_t *dhcpc_addfdnname(uint8_t *optptr, char *hname) 8880f66f451Sopenharmony_ci{ 8890f66f451Sopenharmony_ci int size = strlen(hname); 8900f66f451Sopenharmony_ci 8910f66f451Sopenharmony_ci *optptr++ = DHCP_OPTION_FQDN; 8920f66f451Sopenharmony_ci *optptr++ = size + 3; 8930f66f451Sopenharmony_ci *optptr++ = 0x1; //flags 8940f66f451Sopenharmony_ci optptr += 2; // two blank bytes 8950f66f451Sopenharmony_ci strcpy((char*)optptr, hname); // name 8960f66f451Sopenharmony_ci 8970f66f451Sopenharmony_ci return optptr + size; 8980f66f451Sopenharmony_ci} 8990f66f451Sopenharmony_ci 9000f66f451Sopenharmony_ci// adds request options using -o,-O flag to dhcp packet 9010f66f451Sopenharmony_cistatic uint8_t *dhcpc_addreqoptions(uint8_t *optptr) 9020f66f451Sopenharmony_ci{ 9030f66f451Sopenharmony_ci uint8_t *len; 9040f66f451Sopenharmony_ci 9050f66f451Sopenharmony_ci *optptr++ = DHCP_OPTION_REQ_LIST; 9060f66f451Sopenharmony_ci len = optptr; 9070f66f451Sopenharmony_ci *len = 0; 9080f66f451Sopenharmony_ci optptr++; 9090f66f451Sopenharmony_ci 9100f66f451Sopenharmony_ci if (!(toys.optflags & FLAG_o)) { 9110f66f451Sopenharmony_ci *len = 4; 9120f66f451Sopenharmony_ci *optptr++ = DHCP_OPTION_SUBNET_MASK; 9130f66f451Sopenharmony_ci *optptr++ = DHCP_OPTION_ROUTER; 9140f66f451Sopenharmony_ci *optptr++ = DHCP_OPTION_DNS_SERVER; 9150f66f451Sopenharmony_ci *optptr++ = DHCP_OPTION_BROADCAST; 9160f66f451Sopenharmony_ci } 9170f66f451Sopenharmony_ci if (toys.optflags & FLAG_O) { 9180f66f451Sopenharmony_ci memcpy(optptr++, raw_opt, raw_optcount); 9190f66f451Sopenharmony_ci *len += raw_optcount; 9200f66f451Sopenharmony_ci } 9210f66f451Sopenharmony_ci return optptr; 9220f66f451Sopenharmony_ci} 9230f66f451Sopenharmony_ci 9240f66f451Sopenharmony_cistatic uint8_t *dhcpc_addend(uint8_t *optptr) 9250f66f451Sopenharmony_ci{ 9260f66f451Sopenharmony_ci *optptr++ = DHCP_OPTION_END; 9270f66f451Sopenharmony_ci return optptr; 9280f66f451Sopenharmony_ci} 9290f66f451Sopenharmony_ci 9300f66f451Sopenharmony_ci// Sets values of -x options in dhcp discover and request packet. 9310f66f451Sopenharmony_cistatic uint8_t* set_xopt(uint8_t *optptr) 9320f66f451Sopenharmony_ci{ 9330f66f451Sopenharmony_ci int count; 9340f66f451Sopenharmony_ci int size = ARRAY_LEN(options_list); 9350f66f451Sopenharmony_ci for (count = 0; count < size; count++) { 9360f66f451Sopenharmony_ci if ((options_list[count].len == 0) || (options_list[count].val == NULL)) continue; 9370f66f451Sopenharmony_ci *optptr++ = (uint8_t) (options_list[count].code & 0x00FF); 9380f66f451Sopenharmony_ci *optptr++ = (uint8_t) options_list[count].len; 9390f66f451Sopenharmony_ci memcpy(optptr, options_list[count].val, options_list[count].len); 9400f66f451Sopenharmony_ci optptr += options_list[count].len; 9410f66f451Sopenharmony_ci } 9420f66f451Sopenharmony_ci return optptr; 9430f66f451Sopenharmony_ci} 9440f66f451Sopenharmony_ci 9450f66f451Sopenharmony_cistatic uint32_t get_option_serverid (uint8_t *opt, dhcpc_result_t *presult) 9460f66f451Sopenharmony_ci{ 9470f66f451Sopenharmony_ci uint32_t var = 0; 9480f66f451Sopenharmony_ci while (*opt != DHCP_OPTION_SERVER_ID) { 9490f66f451Sopenharmony_ci if (*opt == DHCP_OPTION_END) return var; 9500f66f451Sopenharmony_ci opt += opt[1] + 2; 9510f66f451Sopenharmony_ci } 9520f66f451Sopenharmony_ci memcpy(&var, opt+2, sizeof(uint32_t)); 9530f66f451Sopenharmony_ci state->serverid.s_addr = var; 9540f66f451Sopenharmony_ci presult->serverid.s_addr = state->serverid.s_addr; 9550f66f451Sopenharmony_ci presult->serverid.s_addr = ntohl(presult->serverid.s_addr); 9560f66f451Sopenharmony_ci return var; 9570f66f451Sopenharmony_ci} 9580f66f451Sopenharmony_ci 9590f66f451Sopenharmony_cistatic uint8_t get_option_msgtype(uint8_t *opt) 9600f66f451Sopenharmony_ci{ 9610f66f451Sopenharmony_ci uint32_t var = 0; 9620f66f451Sopenharmony_ci while (*opt != DHCP_OPTION_MSG_TYPE) { 9630f66f451Sopenharmony_ci if (*opt == DHCP_OPTION_END) return var; 9640f66f451Sopenharmony_ci opt += opt[1] + 2; 9650f66f451Sopenharmony_ci } 9660f66f451Sopenharmony_ci memcpy(&var, opt+2, sizeof(uint8_t)); 9670f66f451Sopenharmony_ci return var; 9680f66f451Sopenharmony_ci} 9690f66f451Sopenharmony_ci 9700f66f451Sopenharmony_cistatic uint8_t get_option_lease(uint8_t *opt, dhcpc_result_t *presult) 9710f66f451Sopenharmony_ci{ 9720f66f451Sopenharmony_ci uint32_t var = 0; 9730f66f451Sopenharmony_ci while (*opt != DHCP_OPTION_LEASE_TIME) { 9740f66f451Sopenharmony_ci if (*opt == DHCP_OPTION_END) return var; 9750f66f451Sopenharmony_ci opt += opt[1] + 2; 9760f66f451Sopenharmony_ci } 9770f66f451Sopenharmony_ci memcpy(&var, opt+2, sizeof(uint32_t)); 9780f66f451Sopenharmony_ci var = htonl(var); 9790f66f451Sopenharmony_ci presult->lease_time = var; 9800f66f451Sopenharmony_ci return var; 9810f66f451Sopenharmony_ci} 9820f66f451Sopenharmony_ci 9830f66f451Sopenharmony_ci 9840f66f451Sopenharmony_ci// sends dhcp msg of MSGTYPE 9850f66f451Sopenharmony_cistatic int dhcpc_sendmsg(int msgtype) 9860f66f451Sopenharmony_ci{ 9870f66f451Sopenharmony_ci uint8_t *pend; 9880f66f451Sopenharmony_ci struct in_addr rqsd; 9890f66f451Sopenharmony_ci char *vendor; 9900f66f451Sopenharmony_ci 9910f66f451Sopenharmony_ci // Create the common message header settings 9920f66f451Sopenharmony_ci memset(&state->pdhcp, 0, sizeof(dhcp_msg_t)); 9930f66f451Sopenharmony_ci state->pdhcp.op = DHCP_REQUEST; 9940f66f451Sopenharmony_ci state->pdhcp.htype = DHCP_HTYPE_ETHERNET; 9950f66f451Sopenharmony_ci state->pdhcp.hlen = 6; 9960f66f451Sopenharmony_ci state->pdhcp.xid = xid; 9970f66f451Sopenharmony_ci memcpy(state->pdhcp.chaddr, state->macaddr, 6); 9980f66f451Sopenharmony_ci memset(&state->pdhcp.chaddr[6], 0, 10); 9990f66f451Sopenharmony_ci state->pdhcp.cookie = htonl(DHCP_MAGIC);; 10000f66f451Sopenharmony_ci 10010f66f451Sopenharmony_ci // Add the common header options 10020f66f451Sopenharmony_ci pend = state->pdhcp.options; 10030f66f451Sopenharmony_ci pend = dhcpc_addmsgtype(pend, msgtype); 10040f66f451Sopenharmony_ci 10050f66f451Sopenharmony_ci if (!(toys.optflags & FLAG_C)) pend = dhcpc_addclientid(pend); 10060f66f451Sopenharmony_ci // Handle the message specific settings 10070f66f451Sopenharmony_ci switch (msgtype) { 10080f66f451Sopenharmony_ci case DHCPDISCOVER: // Broadcast DISCOVER message to all servers 10090f66f451Sopenharmony_ci state->pdhcp.flags = htons(BOOTP_BROADCAST); // Broadcast bit. 10100f66f451Sopenharmony_ci if (toys.optflags & FLAG_r) { 10110f66f451Sopenharmony_ci inet_aton(TT.req_ip, &rqsd); 10120f66f451Sopenharmony_ci pend = dhcpc_addreqipaddr(&rqsd, pend); 10130f66f451Sopenharmony_ci } 10140f66f451Sopenharmony_ci pend = dhcpc_addmaxsize(pend, htons(sizeof(dhcp_raw_t))); 10150f66f451Sopenharmony_ci vendor = (toys.optflags & FLAG_V) ? TT.vendor_cls : "toybox\0"; 10160f66f451Sopenharmony_ci pend = dhcpc_addstropt(pend, DHCP_OPTION_VENDOR, vendor, strlen(vendor)); 10170f66f451Sopenharmony_ci if (toys.optflags & FLAG_H) pend = dhcpc_addstropt(pend, DHCP_OPTION_HOST_NAME, TT.hostname, strlen(TT.hostname)); 10180f66f451Sopenharmony_ci if (toys.optflags & FLAG_F) pend = dhcpc_addfdnname(pend, TT.fdn_name); 10190f66f451Sopenharmony_ci if (!(toys.optflags & FLAG_o) || (toys.optflags & FLAG_O)) 10200f66f451Sopenharmony_ci pend = dhcpc_addreqoptions(pend); 10210f66f451Sopenharmony_ci if (toys.optflags & FLAG_x) pend = set_xopt(pend); 10220f66f451Sopenharmony_ci break; 10230f66f451Sopenharmony_ci case DHCPREQUEST: // Send REQUEST message to the server that sent the *first* OFFER 10240f66f451Sopenharmony_ci state->pdhcp.flags = htons(BOOTP_BROADCAST); // Broadcast bit. 10250f66f451Sopenharmony_ci if (state->status == STATE_RENEWING) memcpy(&state->pdhcp.ciaddr, &state->ipaddr.s_addr, 4); 10260f66f451Sopenharmony_ci pend = dhcpc_addmaxsize(pend, htons(sizeof(dhcp_raw_t))); 10270f66f451Sopenharmony_ci rqsd.s_addr = htonl(server); 10280f66f451Sopenharmony_ci pend = dhcpc_addserverid(&rqsd, pend); 10290f66f451Sopenharmony_ci pend = dhcpc_addreqipaddr(&state->ipaddr, pend); 10300f66f451Sopenharmony_ci vendor = (toys.optflags & FLAG_V) ? TT.vendor_cls : "toybox\0"; 10310f66f451Sopenharmony_ci pend = dhcpc_addstropt(pend, DHCP_OPTION_VENDOR, vendor, strlen(vendor)); 10320f66f451Sopenharmony_ci if (toys.optflags & FLAG_H) pend = dhcpc_addstropt(pend, DHCP_OPTION_HOST_NAME, TT.hostname, strlen(TT.hostname)); 10330f66f451Sopenharmony_ci if (toys.optflags & FLAG_F) pend = dhcpc_addfdnname(pend, TT.fdn_name); 10340f66f451Sopenharmony_ci if (!(toys.optflags & FLAG_o) || (toys.optflags & FLAG_O)) 10350f66f451Sopenharmony_ci pend = dhcpc_addreqoptions(pend); 10360f66f451Sopenharmony_ci if (toys.optflags & FLAG_x) pend = set_xopt(pend); 10370f66f451Sopenharmony_ci break; 10380f66f451Sopenharmony_ci case DHCPRELEASE: // Send RELEASE message to the server. 10390f66f451Sopenharmony_ci memcpy(&state->pdhcp.ciaddr, &state->ipaddr.s_addr, 4); 10400f66f451Sopenharmony_ci rqsd.s_addr = htonl(server); 10410f66f451Sopenharmony_ci pend = dhcpc_addserverid(&rqsd, pend); 10420f66f451Sopenharmony_ci break; 10430f66f451Sopenharmony_ci default: 10440f66f451Sopenharmony_ci return -1; 10450f66f451Sopenharmony_ci } 10460f66f451Sopenharmony_ci pend = dhcpc_addend(pend); 10470f66f451Sopenharmony_ci 10480f66f451Sopenharmony_ci if (state->mode == MODE_APP) return send_app(); 10490f66f451Sopenharmony_ci return send_raw(); 10500f66f451Sopenharmony_ci} 10510f66f451Sopenharmony_ci 10520f66f451Sopenharmony_ci/* 10530f66f451Sopenharmony_ci * parses options from received dhcp packet at OPTPTR and 10540f66f451Sopenharmony_ci * stores result in PRESULT or MSGOPT_LIST 10550f66f451Sopenharmony_ci */ 10560f66f451Sopenharmony_cistatic uint8_t dhcpc_parseoptions(dhcpc_result_t *presult, uint8_t *optptr) 10570f66f451Sopenharmony_ci{ 10580f66f451Sopenharmony_ci uint8_t type = 0, *options, overloaded = 0;; 10590f66f451Sopenharmony_ci uint16_t flag = 0; 10600f66f451Sopenharmony_ci uint32_t convtmp = 0; 10610f66f451Sopenharmony_ci char *dest, *pfx; 10620f66f451Sopenharmony_ci struct in_addr addr; 10630f66f451Sopenharmony_ci int count, optlen, size = ARRAY_LEN(options_list); 10640f66f451Sopenharmony_ci 10650f66f451Sopenharmony_ci if (toys.optflags & FLAG_x) { 10660f66f451Sopenharmony_ci if(msgopt_list){ 10670f66f451Sopenharmony_ci for (count = 0; count < size; count++){ 10680f66f451Sopenharmony_ci if(msgopt_list[count].val) free(msgopt_list[count].val); 10690f66f451Sopenharmony_ci msgopt_list[count].val = NULL; 10700f66f451Sopenharmony_ci msgopt_list[count].len = 0; 10710f66f451Sopenharmony_ci } 10720f66f451Sopenharmony_ci } else { 10730f66f451Sopenharmony_ci msgopt_list = xmalloc(sizeof(options_list)); 10740f66f451Sopenharmony_ci memcpy(msgopt_list, options_list, sizeof(options_list)); 10750f66f451Sopenharmony_ci for (count = 0; count < size; count++) { 10760f66f451Sopenharmony_ci msgopt_list[count].len = 0; 10770f66f451Sopenharmony_ci msgopt_list[count].val = NULL; 10780f66f451Sopenharmony_ci } 10790f66f451Sopenharmony_ci } 10800f66f451Sopenharmony_ci } else { 10810f66f451Sopenharmony_ci msgopt_list = options_list; 10820f66f451Sopenharmony_ci for (count = 0; count < size; count++) { 10830f66f451Sopenharmony_ci msgopt_list[count].len = 0; 10840f66f451Sopenharmony_ci if(msgopt_list[count].val) free(msgopt_list[count].val); 10850f66f451Sopenharmony_ci msgopt_list[count].val = NULL; 10860f66f451Sopenharmony_ci } 10870f66f451Sopenharmony_ci } 10880f66f451Sopenharmony_ci 10890f66f451Sopenharmony_ci while (*optptr != DHCP_OPTION_END) { 10900f66f451Sopenharmony_ci if (*optptr == DHCP_OPTION_PADDING) { 10910f66f451Sopenharmony_ci optptr++; 10920f66f451Sopenharmony_ci continue; 10930f66f451Sopenharmony_ci } 10940f66f451Sopenharmony_ci if (*optptr == DHCP_OPTION_OVERLOAD) { 10950f66f451Sopenharmony_ci overloaded = optptr[2]; 10960f66f451Sopenharmony_ci optptr += optptr[1] + 2; 10970f66f451Sopenharmony_ci continue; 10980f66f451Sopenharmony_ci } 10990f66f451Sopenharmony_ci for (count = 0, flag = 0; count < size; count++) { 11000f66f451Sopenharmony_ci if ((msgopt_list[count].code & 0X00FF) == *optptr) { 11010f66f451Sopenharmony_ci flag = (msgopt_list[count].code & 0XFF00); 11020f66f451Sopenharmony_ci break; 11030f66f451Sopenharmony_ci } 11040f66f451Sopenharmony_ci } 11050f66f451Sopenharmony_ci switch (flag) { 11060f66f451Sopenharmony_ci case DHCP_NUM32: 11070f66f451Sopenharmony_ci memcpy(&convtmp, &optptr[2], sizeof(uint32_t)); 11080f66f451Sopenharmony_ci convtmp = htonl(convtmp); 11090f66f451Sopenharmony_ci sprintf(toybuf, "%u", convtmp); 11100f66f451Sopenharmony_ci msgopt_list[count].val = strdup(toybuf); 11110f66f451Sopenharmony_ci msgopt_list[count].len = strlen(toybuf); 11120f66f451Sopenharmony_ci break; 11130f66f451Sopenharmony_ci case DHCP_NUM16: 11140f66f451Sopenharmony_ci memcpy(&convtmp, &optptr[2], sizeof(uint16_t)); 11150f66f451Sopenharmony_ci convtmp = htons(convtmp); 11160f66f451Sopenharmony_ci sprintf(toybuf, "%u", convtmp); 11170f66f451Sopenharmony_ci msgopt_list[count].val = strdup(toybuf); 11180f66f451Sopenharmony_ci msgopt_list[count].len = strlen(toybuf); 11190f66f451Sopenharmony_ci break; 11200f66f451Sopenharmony_ci case DHCP_NUM8: 11210f66f451Sopenharmony_ci memcpy(&convtmp, &optptr[2], sizeof(uint8_t)); 11220f66f451Sopenharmony_ci sprintf(toybuf, "%u", convtmp); 11230f66f451Sopenharmony_ci msgopt_list[count].val = strdup(toybuf); 11240f66f451Sopenharmony_ci msgopt_list[count].len = strlen(toybuf); 11250f66f451Sopenharmony_ci break; 11260f66f451Sopenharmony_ci case DHCP_IP: 11270f66f451Sopenharmony_ci memcpy(&convtmp, &optptr[2], sizeof(uint32_t)); 11280f66f451Sopenharmony_ci addr.s_addr = convtmp; 11290f66f451Sopenharmony_ci sprintf(toybuf, "%s", inet_ntoa(addr)); 11300f66f451Sopenharmony_ci msgopt_list[count].val = strdup(toybuf); 11310f66f451Sopenharmony_ci msgopt_list[count].len = strlen(toybuf); 11320f66f451Sopenharmony_ci break; 11330f66f451Sopenharmony_ci case DHCP_STRING: 11340f66f451Sopenharmony_ci sprintf(toybuf, "%.*s", optptr[1], &optptr[2]); 11350f66f451Sopenharmony_ci msgopt_list[count].val = strdup(toybuf); 11360f66f451Sopenharmony_ci msgopt_list[count].len = strlen(toybuf); 11370f66f451Sopenharmony_ci break; 11380f66f451Sopenharmony_ci case DHCP_IPLIST: 11390f66f451Sopenharmony_ci options = &optptr[2]; 11400f66f451Sopenharmony_ci optlen = optptr[1]; 11410f66f451Sopenharmony_ci dest = toybuf; 11420f66f451Sopenharmony_ci while (optlen) { 11430f66f451Sopenharmony_ci memcpy(&convtmp, options, sizeof(uint32_t)); 11440f66f451Sopenharmony_ci addr.s_addr = convtmp; 11450f66f451Sopenharmony_ci dest += sprintf(dest, "%s ", inet_ntoa(addr)); 11460f66f451Sopenharmony_ci options += 4; 11470f66f451Sopenharmony_ci optlen -= 4; 11480f66f451Sopenharmony_ci } 11490f66f451Sopenharmony_ci *(dest - 1) = '\0'; 11500f66f451Sopenharmony_ci msgopt_list[count].val = strdup(toybuf); 11510f66f451Sopenharmony_ci msgopt_list[count].len = strlen(toybuf); 11520f66f451Sopenharmony_ci break; 11530f66f451Sopenharmony_ci case DHCP_STRLST: //FIXME: do smthing. 11540f66f451Sopenharmony_ci case DHCP_IPPLST: 11550f66f451Sopenharmony_ci break; 11560f66f451Sopenharmony_ci case DHCP_STCRTS: 11570f66f451Sopenharmony_ci pfx = ""; 11580f66f451Sopenharmony_ci dest = toybuf; 11590f66f451Sopenharmony_ci options = &optptr[2]; 11600f66f451Sopenharmony_ci optlen = optptr[1]; 11610f66f451Sopenharmony_ci 11620f66f451Sopenharmony_ci while (optlen >= 1 + 4) { 11630f66f451Sopenharmony_ci uint32_t nip = 0; 11640f66f451Sopenharmony_ci int bytes; 11650f66f451Sopenharmony_ci uint8_t *p_tmp; 11660f66f451Sopenharmony_ci unsigned mask = *options; 11670f66f451Sopenharmony_ci 11680f66f451Sopenharmony_ci if (mask > 32) break; 11690f66f451Sopenharmony_ci optlen--; 11700f66f451Sopenharmony_ci p_tmp = (void*) &nip; 11710f66f451Sopenharmony_ci bytes = (mask + 7) / 8; 11720f66f451Sopenharmony_ci while (--bytes >= 0) { 11730f66f451Sopenharmony_ci *p_tmp++ = *options++; 11740f66f451Sopenharmony_ci optlen--; 11750f66f451Sopenharmony_ci } 11760f66f451Sopenharmony_ci if (optlen < 4) break; 11770f66f451Sopenharmony_ci dest += sprintf(dest, "%s%u.%u.%u.%u", pfx, ((uint8_t*) &nip)[0], 11780f66f451Sopenharmony_ci ((uint8_t*) &nip)[1], ((uint8_t*) &nip)[2], ((uint8_t*) &nip)[3]); 11790f66f451Sopenharmony_ci pfx = " "; 11800f66f451Sopenharmony_ci dest += sprintf(dest, "/%u ", mask); 11810f66f451Sopenharmony_ci dest += sprintf(dest, "%u.%u.%u.%u", options[0], options[1], options[2], options[3]); 11820f66f451Sopenharmony_ci options += 4; 11830f66f451Sopenharmony_ci optlen -= 4; 11840f66f451Sopenharmony_ci } 11850f66f451Sopenharmony_ci msgopt_list[count].val = strdup(toybuf); 11860f66f451Sopenharmony_ci msgopt_list[count].len = strlen(toybuf); 11870f66f451Sopenharmony_ci break; 11880f66f451Sopenharmony_ci default: break; 11890f66f451Sopenharmony_ci } 11900f66f451Sopenharmony_ci optptr += optptr[1] + 2; 11910f66f451Sopenharmony_ci } 11920f66f451Sopenharmony_ci if ((overloaded == 1) || (overloaded == 3)) dhcpc_parseoptions(presult, optptr); 11930f66f451Sopenharmony_ci if ((overloaded == 2) || (overloaded == 3)) dhcpc_parseoptions(presult, optptr); 11940f66f451Sopenharmony_ci return type; 11950f66f451Sopenharmony_ci} 11960f66f451Sopenharmony_ci 11970f66f451Sopenharmony_ci// parses recvd messege to check that it was for us. 11980f66f451Sopenharmony_cistatic uint8_t dhcpc_parsemsg(dhcpc_result_t *presult) 11990f66f451Sopenharmony_ci{ 12000f66f451Sopenharmony_ci if (state->pdhcp.op == DHCP_REPLY 12010f66f451Sopenharmony_ci && !memcmp(state->pdhcp.chaddr, state->macaddr, 6) 12020f66f451Sopenharmony_ci && !memcmp(&state->pdhcp.xid, &xid, sizeof(xid))) { 12030f66f451Sopenharmony_ci memcpy(&presult->ipaddr.s_addr, &state->pdhcp.yiaddr, 4); 12040f66f451Sopenharmony_ci presult->ipaddr.s_addr = ntohl(presult->ipaddr.s_addr); 12050f66f451Sopenharmony_ci return get_option_msgtype(state->pdhcp.options); 12060f66f451Sopenharmony_ci } 12070f66f451Sopenharmony_ci return 0; 12080f66f451Sopenharmony_ci} 12090f66f451Sopenharmony_ci 12100f66f451Sopenharmony_ci// Sends a IP renew request. 12110f66f451Sopenharmony_cistatic void renew(void) 12120f66f451Sopenharmony_ci{ 12130f66f451Sopenharmony_ci infomsg(infomode, "Performing a DHCP renew"); 12140f66f451Sopenharmony_ci switch (state->status) { 12150f66f451Sopenharmony_ci case STATE_INIT: 12160f66f451Sopenharmony_ci break; 12170f66f451Sopenharmony_ci case STATE_BOUND: 12180f66f451Sopenharmony_ci mode_raw(); 12190f66f451Sopenharmony_ci case STATE_RENEWING: // FALLTHROUGH 12200f66f451Sopenharmony_ci case STATE_REBINDING: // FALLTHROUGH 12210f66f451Sopenharmony_ci state->status = STATE_RENEW_REQUESTED; 12220f66f451Sopenharmony_ci break; 12230f66f451Sopenharmony_ci case STATE_RENEW_REQUESTED: 12240f66f451Sopenharmony_ci run_script(NULL, "deconfig"); 12250f66f451Sopenharmony_ci case STATE_REQUESTING: // FALLTHROUGH 12260f66f451Sopenharmony_ci case STATE_RELEASED: // FALLTHROUGH 12270f66f451Sopenharmony_ci mode_raw(); 12280f66f451Sopenharmony_ci state->status = STATE_INIT; 12290f66f451Sopenharmony_ci break; 12300f66f451Sopenharmony_ci default: break; 12310f66f451Sopenharmony_ci } 12320f66f451Sopenharmony_ci} 12330f66f451Sopenharmony_ci 12340f66f451Sopenharmony_ci// Sends a IP release request. 12350f66f451Sopenharmony_cistatic void release(void) 12360f66f451Sopenharmony_ci{ 12370f66f451Sopenharmony_ci char buffer[sizeof("255.255.255.255\0")]; 12380f66f451Sopenharmony_ci struct in_addr temp_addr; 12390f66f451Sopenharmony_ci 12400f66f451Sopenharmony_ci mode_app(); 12410f66f451Sopenharmony_ci // send release packet 12420f66f451Sopenharmony_ci if (state->status == STATE_BOUND || state->status == STATE_RENEWING || state->status == STATE_REBINDING) { 12430f66f451Sopenharmony_ci temp_addr.s_addr = htonl(server); 12440f66f451Sopenharmony_ci xstrncpy(buffer, inet_ntoa(temp_addr), sizeof(buffer)); 12450f66f451Sopenharmony_ci temp_addr.s_addr = state->ipaddr.s_addr; 12460f66f451Sopenharmony_ci infomsg( infomode, "Unicasting a release of %s to %s", inet_ntoa(temp_addr), buffer); 12470f66f451Sopenharmony_ci dhcpc_sendmsg(DHCPRELEASE); 12480f66f451Sopenharmony_ci run_script(NULL, "deconfig"); 12490f66f451Sopenharmony_ci } 12500f66f451Sopenharmony_ci infomsg(infomode, "Entering released state"); 12510f66f451Sopenharmony_ci close(state->sockfd); 12520f66f451Sopenharmony_ci state->sockfd = -1; 12530f66f451Sopenharmony_ci state->mode = MODE_OFF; 12540f66f451Sopenharmony_ci state->status = STATE_RELEASED; 12550f66f451Sopenharmony_ci} 12560f66f451Sopenharmony_ci 12570f66f451Sopenharmony_cistatic void free_option_stores(void) 12580f66f451Sopenharmony_ci{ 12590f66f451Sopenharmony_ci int count, size = ARRAY_LEN(options_list); 12600f66f451Sopenharmony_ci for (count = 0; count < size; count++) 12610f66f451Sopenharmony_ci if (options_list[count].val) free(options_list[count].val); 12620f66f451Sopenharmony_ci if (toys.optflags & FLAG_x) { 12630f66f451Sopenharmony_ci for (count = 0; count < size; count++) 12640f66f451Sopenharmony_ci if (msgopt_list[count].val) free(msgopt_list[count].val); 12650f66f451Sopenharmony_ci free(msgopt_list); 12660f66f451Sopenharmony_ci } 12670f66f451Sopenharmony_ci} 12680f66f451Sopenharmony_ci 12690f66f451Sopenharmony_civoid dhcp_main(void) 12700f66f451Sopenharmony_ci{ 12710f66f451Sopenharmony_ci struct timeval tv; 12720f66f451Sopenharmony_ci int retval, bufflen = 0; 12730f66f451Sopenharmony_ci dhcpc_result_t result; 12740f66f451Sopenharmony_ci uint8_t packets = 0, retries = 0; 12750f66f451Sopenharmony_ci uint32_t timeout = 0, waited = 0; 12760f66f451Sopenharmony_ci fd_set rfds; 12770f66f451Sopenharmony_ci 12780f66f451Sopenharmony_ci xid = 0; 12790f66f451Sopenharmony_ci setlinebuf(stdout); 12800f66f451Sopenharmony_ci dbg = dummy; 12810f66f451Sopenharmony_ci if (toys.optflags & FLAG_v) dbg = xprintf; 12820f66f451Sopenharmony_ci if (toys.optflags & FLAG_p) write_pid(TT.pidfile); 12830f66f451Sopenharmony_ci retries = TT.retries; 12840f66f451Sopenharmony_ci if (toys.optflags & FLAG_S) { 12850f66f451Sopenharmony_ci openlog("UDHCPC :", LOG_PID, LOG_DAEMON); 12860f66f451Sopenharmony_ci infomode |= LOG_SYSTEM; 12870f66f451Sopenharmony_ci } 12880f66f451Sopenharmony_ci infomsg(infomode, "dhcp started"); 12890f66f451Sopenharmony_ci if (toys.optflags & FLAG_O) { 12900f66f451Sopenharmony_ci while (TT.req_opt) { 12910f66f451Sopenharmony_ci raw_opt[raw_optcount] = (uint8_t) strtoopt(TT.req_opt->arg, 1); 12920f66f451Sopenharmony_ci raw_optcount++; 12930f66f451Sopenharmony_ci TT.req_opt = TT.req_opt->next; 12940f66f451Sopenharmony_ci } 12950f66f451Sopenharmony_ci } 12960f66f451Sopenharmony_ci if (toys.optflags & FLAG_x) { 12970f66f451Sopenharmony_ci while (TT.pkt_opt) { 12980f66f451Sopenharmony_ci (void) strtoopt(TT.pkt_opt->arg, 0); 12990f66f451Sopenharmony_ci TT.pkt_opt = TT.pkt_opt->next; 13000f66f451Sopenharmony_ci } 13010f66f451Sopenharmony_ci } 13020f66f451Sopenharmony_ci memset(&result, 0, sizeof(dhcpc_result_t)); 13030f66f451Sopenharmony_ci state = (dhcpc_state_t*) xmalloc(sizeof(dhcpc_state_t)); 13040f66f451Sopenharmony_ci memset(state, 0, sizeof(dhcpc_state_t)); 13050f66f451Sopenharmony_ci state->iface = (toys.optflags & FLAG_i) ? TT.iface : "eth0"; 13060f66f451Sopenharmony_ci 13070f66f451Sopenharmony_ci if (get_interface(state->iface, &state->ifindex, NULL, state->macaddr)) 13080f66f451Sopenharmony_ci perror_exit("Failed to get interface %s", state->iface); 13090f66f451Sopenharmony_ci 13100f66f451Sopenharmony_ci run_script(NULL, "deconfig"); 13110f66f451Sopenharmony_ci setup_signal(); 13120f66f451Sopenharmony_ci state->status = STATE_INIT; 13130f66f451Sopenharmony_ci mode_raw(); 13140f66f451Sopenharmony_ci fcntl(state->sockfd, F_SETFD, FD_CLOEXEC); 13150f66f451Sopenharmony_ci 13160f66f451Sopenharmony_ci for (;;) { 13170f66f451Sopenharmony_ci FD_ZERO(&rfds); 13180f66f451Sopenharmony_ci if (state->sockfd >= 0) FD_SET(state->sockfd, &rfds); 13190f66f451Sopenharmony_ci FD_SET(sigfd.rd, &rfds); 13200f66f451Sopenharmony_ci tv.tv_sec = timeout - waited; 13210f66f451Sopenharmony_ci tv.tv_usec = 0; 13220f66f451Sopenharmony_ci retval = 0; 13230f66f451Sopenharmony_ci 13240f66f451Sopenharmony_ci int maxfd = (sigfd.rd > state->sockfd)? sigfd.rd : state->sockfd; 13250f66f451Sopenharmony_ci dbg("select wait ....\n"); 13260f66f451Sopenharmony_ci uint32_t timestmp = time(NULL); 13270f66f451Sopenharmony_ci if((retval = select(maxfd + 1, &rfds, NULL, NULL, &tv)) < 0) { 13280f66f451Sopenharmony_ci if (errno == EINTR) { 13290f66f451Sopenharmony_ci waited += (unsigned) time(NULL) - timestmp; 13300f66f451Sopenharmony_ci continue; 13310f66f451Sopenharmony_ci } 13320f66f451Sopenharmony_ci perror_exit("Error in select"); 13330f66f451Sopenharmony_ci } 13340f66f451Sopenharmony_ci if (!retval) { // Timed out 13350f66f451Sopenharmony_ci if (get_interface(state->iface, &state->ifindex, NULL, state->macaddr)) 13360f66f451Sopenharmony_ci error_exit("Interface lost %s\n", state->iface); 13370f66f451Sopenharmony_ci 13380f66f451Sopenharmony_ci switch (state->status) { 13390f66f451Sopenharmony_ci case STATE_INIT: 13400f66f451Sopenharmony_ci if (packets < retries) { 13410f66f451Sopenharmony_ci if (!packets) xid = getxid(); 13420f66f451Sopenharmony_ci run_script(NULL, "deconfig"); 13430f66f451Sopenharmony_ci infomsg(infomode, "Sending discover..."); 13440f66f451Sopenharmony_ci dhcpc_sendmsg(DHCPDISCOVER); 13450f66f451Sopenharmony_ci server = 0; 13460f66f451Sopenharmony_ci timeout = TT.timeout; 13470f66f451Sopenharmony_ci waited = 0; 13480f66f451Sopenharmony_ci packets++; 13490f66f451Sopenharmony_ci continue; 13500f66f451Sopenharmony_ci } 13510f66f451Sopenharmony_cilease_fail: 13520f66f451Sopenharmony_ci run_script(NULL,"leasefail"); 13530f66f451Sopenharmony_ci if (toys.optflags & FLAG_n) { 13540f66f451Sopenharmony_ci infomsg(infomode, "Lease failed. Exiting"); 13550f66f451Sopenharmony_ci goto ret_with_sockfd; 13560f66f451Sopenharmony_ci } 13570f66f451Sopenharmony_ci if (toys.optflags & FLAG_b) { 13580f66f451Sopenharmony_ci infomsg(infomode, "Lease failed. Going Daemon mode"); 13590f66f451Sopenharmony_ci daemon(0, 0); 13600f66f451Sopenharmony_ci if (toys.optflags & FLAG_p) write_pid(TT.pidfile); 13610f66f451Sopenharmony_ci toys.optflags &= ~FLAG_b; 13620f66f451Sopenharmony_ci toys.optflags |= FLAG_f; 13630f66f451Sopenharmony_ci } 13640f66f451Sopenharmony_ci timeout = TT.tryagain; 13650f66f451Sopenharmony_ci waited = 0; 13660f66f451Sopenharmony_ci packets = 0; 13670f66f451Sopenharmony_ci continue; 13680f66f451Sopenharmony_ci case STATE_REQUESTING: 13690f66f451Sopenharmony_ci if (packets < retries) { 13700f66f451Sopenharmony_ci memcpy(&state->ipaddr.s_addr,&state->pdhcp.yiaddr, 4); 13710f66f451Sopenharmony_ci dhcpc_sendmsg(DHCPREQUEST); 13720f66f451Sopenharmony_ci infomsg(infomode, "Sending select for %d.%d.%d.%d...", 13730f66f451Sopenharmony_ci (result.ipaddr.s_addr >> 24) & 0xff, (result.ipaddr.s_addr >> 16) & 0xff, (result.ipaddr.s_addr >> 8) & 0xff, (result.ipaddr.s_addr) & 0xff); 13740f66f451Sopenharmony_ci timeout = TT.timeout; 13750f66f451Sopenharmony_ci waited = 0; 13760f66f451Sopenharmony_ci packets++; 13770f66f451Sopenharmony_ci continue; 13780f66f451Sopenharmony_ci } 13790f66f451Sopenharmony_ci mode_raw(); 13800f66f451Sopenharmony_ci state->status = STATE_INIT; 13810f66f451Sopenharmony_ci goto lease_fail; 13820f66f451Sopenharmony_ci case STATE_BOUND: 13830f66f451Sopenharmony_ci state->status = STATE_RENEWING; 13840f66f451Sopenharmony_ci dbg("Entering renew state\n"); 13850f66f451Sopenharmony_ci // FALLTHROUGH 13860f66f451Sopenharmony_ci case STATE_RENEW_REQUESTED: // FALLTHROUGH 13870f66f451Sopenharmony_ci case STATE_RENEWING: 13880f66f451Sopenharmony_cirenew_requested: 13890f66f451Sopenharmony_ci if (timeout > 60) { 13900f66f451Sopenharmony_ci dhcpc_sendmsg(DHCPREQUEST); 13910f66f451Sopenharmony_ci timeout >>= 1; 13920f66f451Sopenharmony_ci waited = 0; 13930f66f451Sopenharmony_ci continue; 13940f66f451Sopenharmony_ci } 13950f66f451Sopenharmony_ci dbg("Entering rebinding state\n"); 13960f66f451Sopenharmony_ci state->status = STATE_REBINDING; 13970f66f451Sopenharmony_ci // FALLTHROUGH 13980f66f451Sopenharmony_ci case STATE_REBINDING: 13990f66f451Sopenharmony_ci mode_raw(); 14000f66f451Sopenharmony_ci if (timeout > 0) { 14010f66f451Sopenharmony_ci dhcpc_sendmsg(DHCPREQUEST); 14020f66f451Sopenharmony_ci timeout >>= 1; 14030f66f451Sopenharmony_ci waited = 0; 14040f66f451Sopenharmony_ci continue; 14050f66f451Sopenharmony_ci } 14060f66f451Sopenharmony_ci infomsg(infomode, "Lease lost, entering INIT state"); 14070f66f451Sopenharmony_ci run_script(NULL, "deconfig"); 14080f66f451Sopenharmony_ci state->status = STATE_INIT; 14090f66f451Sopenharmony_ci timeout = 0; 14100f66f451Sopenharmony_ci waited = 0; 14110f66f451Sopenharmony_ci packets = 0; 14120f66f451Sopenharmony_ci continue; 14130f66f451Sopenharmony_ci default: break; 14140f66f451Sopenharmony_ci } 14150f66f451Sopenharmony_ci timeout = INT_MAX; 14160f66f451Sopenharmony_ci waited = 0; 14170f66f451Sopenharmony_ci continue; 14180f66f451Sopenharmony_ci } 14190f66f451Sopenharmony_ci if (FD_ISSET(sigfd.rd, &rfds)) { // Some Activity on RDFDs : is signal 14200f66f451Sopenharmony_ci unsigned char sig; 14210f66f451Sopenharmony_ci if (read(sigfd.rd, &sig, 1) != 1) { 14220f66f451Sopenharmony_ci dbg("signal read failed.\n"); 14230f66f451Sopenharmony_ci continue; 14240f66f451Sopenharmony_ci } 14250f66f451Sopenharmony_ci switch (sig) { 14260f66f451Sopenharmony_ci case SIGUSR1: 14270f66f451Sopenharmony_ci infomsg(infomode, "Received SIGUSR1"); 14280f66f451Sopenharmony_ci renew(); 14290f66f451Sopenharmony_ci packets = 0; 14300f66f451Sopenharmony_ci waited = 0; 14310f66f451Sopenharmony_ci if (state->status == STATE_RENEW_REQUESTED) goto renew_requested; 14320f66f451Sopenharmony_ci if (state->status == STATE_INIT) timeout = 0; 14330f66f451Sopenharmony_ci continue; 14340f66f451Sopenharmony_ci case SIGUSR2: 14350f66f451Sopenharmony_ci infomsg(infomode, "Received SIGUSR2"); 14360f66f451Sopenharmony_ci release(); 14370f66f451Sopenharmony_ci timeout = INT_MAX; 14380f66f451Sopenharmony_ci waited = 0; 14390f66f451Sopenharmony_ci packets = 0; 14400f66f451Sopenharmony_ci continue; 14410f66f451Sopenharmony_ci case SIGTERM: 14420f66f451Sopenharmony_ci infomsg(infomode, "Received SIGTERM"); 14430f66f451Sopenharmony_ci if (toys.optflags & FLAG_R) release(); 14440f66f451Sopenharmony_ci goto ret_with_sockfd; 14450f66f451Sopenharmony_ci default: break; 14460f66f451Sopenharmony_ci } 14470f66f451Sopenharmony_ci } 14480f66f451Sopenharmony_ci if (FD_ISSET(state->sockfd, &rfds)) { // Some Activity on RDFDs : is socket 14490f66f451Sopenharmony_ci dbg("main sock read\n"); 14500f66f451Sopenharmony_ci uint8_t msgType; 14510f66f451Sopenharmony_ci if (state->mode == MODE_RAW) bufflen = read_raw(); 14520f66f451Sopenharmony_ci if (state->mode == MODE_APP) bufflen = read_app(); 14530f66f451Sopenharmony_ci if (bufflen < 0) { 14540f66f451Sopenharmony_ci if (state->mode == MODE_RAW) mode_raw(); 14550f66f451Sopenharmony_ci if (state->mode == MODE_APP) mode_app(); 14560f66f451Sopenharmony_ci continue; 14570f66f451Sopenharmony_ci } 14580f66f451Sopenharmony_ci waited += time(NULL) - timestmp; 14590f66f451Sopenharmony_ci memset(&result, 0, sizeof(dhcpc_result_t)); 14600f66f451Sopenharmony_ci msgType = dhcpc_parsemsg(&result); 14610f66f451Sopenharmony_ci if (msgType != DHCPNAK && result.ipaddr.s_addr == 0 ) continue; // no ip for me ignore 14620f66f451Sopenharmony_ci if (!msgType || !get_option_serverid(state->pdhcp.options, &result)) continue; //no server id ignore 14630f66f451Sopenharmony_ci if (msgType == DHCPOFFER && server == 0) server = result.serverid.s_addr; // select the server 14640f66f451Sopenharmony_ci if (result.serverid.s_addr != server) continue; // not from the server we requested ignore 14650f66f451Sopenharmony_ci dhcpc_parseoptions(&result, state->pdhcp.options); 14660f66f451Sopenharmony_ci get_option_lease(state->pdhcp.options, &result); 14670f66f451Sopenharmony_ci 14680f66f451Sopenharmony_ci switch (state->status) { 14690f66f451Sopenharmony_ci case STATE_INIT: 14700f66f451Sopenharmony_ci if (msgType == DHCPOFFER) { 14710f66f451Sopenharmony_ci state->status = STATE_REQUESTING; 14720f66f451Sopenharmony_ci mode_raw(); 14730f66f451Sopenharmony_ci timeout = 0; 14740f66f451Sopenharmony_ci waited = 0; 14750f66f451Sopenharmony_ci packets = 0; 14760f66f451Sopenharmony_ci } 14770f66f451Sopenharmony_ci continue; 14780f66f451Sopenharmony_ci case STATE_REQUESTING: // FALLTHROUGH 14790f66f451Sopenharmony_ci case STATE_RENEWING: // FALLTHROUGH 14800f66f451Sopenharmony_ci case STATE_RENEW_REQUESTED: // FALLTHROUGH 14810f66f451Sopenharmony_ci case STATE_REBINDING: 14820f66f451Sopenharmony_ci if (msgType == DHCPACK) { 14830f66f451Sopenharmony_ci timeout = result.lease_time / 2; 14840f66f451Sopenharmony_ci run_script(&result, state->status == STATE_REQUESTING ? "bound" : "renew"); 14850f66f451Sopenharmony_ci state->status = STATE_BOUND; 14860f66f451Sopenharmony_ci infomsg(infomode, "Lease of %d.%d.%d.%d obtained, lease time %d from server %d.%d.%d.%d", 14870f66f451Sopenharmony_ci (result.ipaddr.s_addr >> 24) & 0xff, (result.ipaddr.s_addr >> 16) & 0xff, (result.ipaddr.s_addr >> 8) & 0xff, (result.ipaddr.s_addr) & 0xff, 14880f66f451Sopenharmony_ci result.lease_time, 14890f66f451Sopenharmony_ci (result.serverid.s_addr >> 24) & 0xff, (result.serverid.s_addr >> 16) & 0xff, (result.serverid.s_addr >> 8) & 0xff, (result.serverid.s_addr) & 0xff); 14900f66f451Sopenharmony_ci if (toys.optflags & FLAG_q) { 14910f66f451Sopenharmony_ci if (toys.optflags & FLAG_R) release(); 14920f66f451Sopenharmony_ci goto ret_with_sockfd; 14930f66f451Sopenharmony_ci } 14940f66f451Sopenharmony_ci toys.optflags &= ~FLAG_n; 14950f66f451Sopenharmony_ci if (!(toys.optflags & FLAG_f)) { 14960f66f451Sopenharmony_ci daemon(0, 0); 14970f66f451Sopenharmony_ci toys.optflags |= FLAG_f; 14980f66f451Sopenharmony_ci if (toys.optflags & FLAG_p) write_pid(TT.pidfile); 14990f66f451Sopenharmony_ci } 15000f66f451Sopenharmony_ci waited = 0; 15010f66f451Sopenharmony_ci continue; 15020f66f451Sopenharmony_ci } else if (msgType == DHCPNAK) { 15030f66f451Sopenharmony_ci dbg("NACK received.\n"); 15040f66f451Sopenharmony_ci run_script(&result, "nak"); 15050f66f451Sopenharmony_ci if (state->status != STATE_REQUESTING) run_script(NULL, "deconfig"); 15060f66f451Sopenharmony_ci mode_raw(); 15070f66f451Sopenharmony_ci sleep(3); 15080f66f451Sopenharmony_ci state->status = STATE_INIT; 15090f66f451Sopenharmony_ci state->ipaddr.s_addr = 0; 15100f66f451Sopenharmony_ci server = 0; 15110f66f451Sopenharmony_ci timeout = 0; 15120f66f451Sopenharmony_ci packets = 0; 15130f66f451Sopenharmony_ci waited = 0; 15140f66f451Sopenharmony_ci } 15150f66f451Sopenharmony_ci continue; 15160f66f451Sopenharmony_ci default: break; 15170f66f451Sopenharmony_ci } 15180f66f451Sopenharmony_ci } 15190f66f451Sopenharmony_ci } 15200f66f451Sopenharmony_ciret_with_sockfd: 15210f66f451Sopenharmony_ci if (CFG_TOYBOX_FREE) { 15220f66f451Sopenharmony_ci free_option_stores(); 15230f66f451Sopenharmony_ci if (state->sockfd > 0) close(state->sockfd); 15240f66f451Sopenharmony_ci free(state); 15250f66f451Sopenharmony_ci } 15260f66f451Sopenharmony_ci} 1527