10c4bfcacSAsias He #include "kvm/uip.h" 20c4bfcacSAsias He 3bdcc9e40SAsias He #include <arpa/inet.h> 4bdcc9e40SAsias He 5575a9e3fSSasha Levin #define EMPTY_ADDR "0.0.0.0" 6575a9e3fSSasha Levin 78f5f2f95SAsias He static inline bool uip_dhcp_is_discovery(struct uip_dhcp *dhcp) 88f5f2f95SAsias He { 98f5f2f95SAsias He return (dhcp->option[2] == UIP_DHCP_DISCOVER && 108f5f2f95SAsias He dhcp->option[1] == UIP_DHCP_TAG_MSG_TYPE_LEN && 118f5f2f95SAsias He dhcp->option[0] == UIP_DHCP_TAG_MSG_TYPE); 128f5f2f95SAsias He } 138f5f2f95SAsias He 148f5f2f95SAsias He static inline bool uip_dhcp_is_request(struct uip_dhcp *dhcp) 158f5f2f95SAsias He { 168f5f2f95SAsias He return (dhcp->option[2] == UIP_DHCP_REQUEST && 178f5f2f95SAsias He dhcp->option[1] == UIP_DHCP_TAG_MSG_TYPE_LEN && 188f5f2f95SAsias He dhcp->option[0] == UIP_DHCP_TAG_MSG_TYPE); 198f5f2f95SAsias He } 208f5f2f95SAsias He 210c4bfcacSAsias He bool uip_udp_is_dhcp(struct uip_udp *udp) 220c4bfcacSAsias He { 230c4bfcacSAsias He struct uip_dhcp *dhcp; 240c4bfcacSAsias He 250c4bfcacSAsias He if (ntohs(udp->sport) != UIP_DHCP_PORT_CLIENT || 260c4bfcacSAsias He ntohs(udp->dport) != UIP_DHCP_PORT_SERVER) 270c4bfcacSAsias He return false; 280c4bfcacSAsias He 290c4bfcacSAsias He dhcp = (struct uip_dhcp *)udp; 300c4bfcacSAsias He 310c4bfcacSAsias He if (ntohl(dhcp->magic_cookie) != UIP_DHCP_MAGIC_COOKIE) 320c4bfcacSAsias He return false; 330c4bfcacSAsias He 340c4bfcacSAsias He return true; 350c4bfcacSAsias He } 36bdcc9e40SAsias He 37bdcc9e40SAsias He int uip_dhcp_get_dns(struct uip_info *info) 38bdcc9e40SAsias He { 39bdcc9e40SAsias He char key[256], val[256]; 40bdcc9e40SAsias He struct in_addr addr; 41bdcc9e40SAsias He int ret = -1; 42bdcc9e40SAsias He int n = 0; 43bdcc9e40SAsias He FILE *fp; 44bdcc9e40SAsias He u32 ip; 45bdcc9e40SAsias He 46bdcc9e40SAsias He fp = fopen("/etc/resolv.conf", "r"); 47bdcc9e40SAsias He if (!fp) 48a7b946b9SMichael Ellerman return ret; 49bdcc9e40SAsias He 50bdcc9e40SAsias He while (!feof(fp)) { 51bdcc9e40SAsias He if (fscanf(fp, "%s %s\n", key, val) != 2) 52bdcc9e40SAsias He continue; 53bdcc9e40SAsias He if (strncmp("domain", key, 6) == 0) 54bdcc9e40SAsias He info->domain_name = strndup(val, UIP_DHCP_MAX_DOMAIN_NAME_LEN); 55bdcc9e40SAsias He else if (strncmp("nameserver", key, 10) == 0) { 56bdcc9e40SAsias He if (!inet_aton(val, &addr)) 57bdcc9e40SAsias He continue; 58bdcc9e40SAsias He ip = ntohl(addr.s_addr); 59bdcc9e40SAsias He if (n < UIP_DHCP_MAX_DNS_SERVER_NR) 60bdcc9e40SAsias He info->dns_ip[n++] = ip; 61bdcc9e40SAsias He ret = 0; 62bdcc9e40SAsias He } 63bdcc9e40SAsias He } 64bdcc9e40SAsias He 65bdcc9e40SAsias He fclose(fp); 66bdcc9e40SAsias He return ret; 67bdcc9e40SAsias He } 6832a44aafSAsias He 6932a44aafSAsias He static int uip_dhcp_fill_option_name_and_server(struct uip_info *info, u8 *opt, int i) 7032a44aafSAsias He { 7132a44aafSAsias He u8 domain_name_len; 7232a44aafSAsias He u32 *addr; 7332a44aafSAsias He int n; 7432a44aafSAsias He 7532a44aafSAsias He if (info->domain_name) { 7632a44aafSAsias He domain_name_len = strlen(info->domain_name); 7732a44aafSAsias He opt[i++] = UIP_DHCP_TAG_DOMAIN_NAME; 7832a44aafSAsias He opt[i++] = domain_name_len; 7932a44aafSAsias He memcpy(&opt[i], info->domain_name, domain_name_len); 8032a44aafSAsias He i += domain_name_len; 8132a44aafSAsias He } 8232a44aafSAsias He 8332a44aafSAsias He for (n = 0; n < UIP_DHCP_MAX_DNS_SERVER_NR; n++) { 8432a44aafSAsias He if (info->dns_ip[n] == 0) 8532a44aafSAsias He continue; 8632a44aafSAsias He opt[i++] = UIP_DHCP_TAG_DNS_SERVER; 8732a44aafSAsias He opt[i++] = UIP_DHCP_TAG_DNS_SERVER_LEN; 8832a44aafSAsias He addr = (u32 *)&opt[i]; 8932a44aafSAsias He *addr = htonl(info->dns_ip[n]); 9032a44aafSAsias He i += UIP_DHCP_TAG_DNS_SERVER_LEN; 9132a44aafSAsias He } 9232a44aafSAsias He 9332a44aafSAsias He return i; 9432a44aafSAsias He } 95ab8d80a6SAsias He static int uip_dhcp_fill_option(struct uip_info *info, struct uip_dhcp *dhcp, int reply_msg_type) 96ab8d80a6SAsias He { 97ab8d80a6SAsias He int i = 0; 98ab8d80a6SAsias He u32 *addr; 99ab8d80a6SAsias He u8 *opt; 100ab8d80a6SAsias He 101ab8d80a6SAsias He opt = dhcp->option; 102ab8d80a6SAsias He 103ab8d80a6SAsias He opt[i++] = UIP_DHCP_TAG_MSG_TYPE; 104ab8d80a6SAsias He opt[i++] = UIP_DHCP_TAG_MSG_TYPE_LEN; 105ab8d80a6SAsias He opt[i++] = reply_msg_type; 106ab8d80a6SAsias He 107ab8d80a6SAsias He opt[i++] = UIP_DHCP_TAG_SERVER_ID; 108ab8d80a6SAsias He opt[i++] = UIP_DHCP_TAG_SERVER_ID_LEN; 109ab8d80a6SAsias He addr = (u32 *)&opt[i]; 110ab8d80a6SAsias He *addr = htonl(info->host_ip); 111ab8d80a6SAsias He i += UIP_DHCP_TAG_SERVER_ID_LEN; 112ab8d80a6SAsias He 113ab8d80a6SAsias He opt[i++] = UIP_DHCP_TAG_LEASE_TIME; 114ab8d80a6SAsias He opt[i++] = UIP_DHCP_TAG_LEASE_TIME_LEN; 115ab8d80a6SAsias He addr = (u32 *)&opt[i]; 116ab8d80a6SAsias He *addr = htonl(UIP_DHCP_LEASE_TIME); 117ab8d80a6SAsias He i += UIP_DHCP_TAG_LEASE_TIME_LEN; 118ab8d80a6SAsias He 119ab8d80a6SAsias He opt[i++] = UIP_DHCP_TAG_SUBMASK; 120ab8d80a6SAsias He opt[i++] = UIP_DHCP_TAG_SUBMASK_LEN; 121ab8d80a6SAsias He addr = (u32 *)&opt[i]; 122ab8d80a6SAsias He *addr = htonl(info->guest_netmask); 123ab8d80a6SAsias He i += UIP_DHCP_TAG_SUBMASK_LEN; 124ab8d80a6SAsias He 125ab8d80a6SAsias He opt[i++] = UIP_DHCP_TAG_ROUTER; 126ab8d80a6SAsias He opt[i++] = UIP_DHCP_TAG_ROUTER_LEN; 127ab8d80a6SAsias He addr = (u32 *)&opt[i]; 128ab8d80a6SAsias He *addr = htonl(info->host_ip); 129ab8d80a6SAsias He i += UIP_DHCP_TAG_ROUTER_LEN; 130ab8d80a6SAsias He 131575a9e3fSSasha Levin opt[i++] = UIP_DHCP_TAG_ROOT; 132575a9e3fSSasha Levin opt[i++] = strlen(EMPTY_ADDR); 133575a9e3fSSasha Levin addr = (u32 *)&opt[i]; 134575a9e3fSSasha Levin strncpy((void *) addr, EMPTY_ADDR, strlen(EMPTY_ADDR)); 135575a9e3fSSasha Levin i += strlen(EMPTY_ADDR); 136575a9e3fSSasha Levin 137ab8d80a6SAsias He i = uip_dhcp_fill_option_name_and_server(info, opt, i); 138ab8d80a6SAsias He 139ab8d80a6SAsias He opt[i++] = UIP_DHCP_TAG_END; 140ab8d80a6SAsias He 141ab8d80a6SAsias He return 0; 142ab8d80a6SAsias He } 143155c7f33SAsias He 144155c7f33SAsias He static int uip_dhcp_make_pkg(struct uip_info *info, struct uip_udp_socket *sk, struct uip_buf *buf, u8 reply_msg_type) 145155c7f33SAsias He { 146155c7f33SAsias He struct uip_dhcp *dhcp; 147155c7f33SAsias He 148155c7f33SAsias He dhcp = (struct uip_dhcp *)buf->eth; 149155c7f33SAsias He 150155c7f33SAsias He dhcp->msg_type = 2; 151155c7f33SAsias He dhcp->client_ip = 0; 152155c7f33SAsias He dhcp->your_ip = htonl(info->guest_ip); 153155c7f33SAsias He dhcp->server_ip = htonl(info->host_ip); 154155c7f33SAsias He dhcp->agent_ip = 0; 155155c7f33SAsias He 156155c7f33SAsias He uip_dhcp_fill_option(info, dhcp, reply_msg_type); 157155c7f33SAsias He 158155c7f33SAsias He sk->sip = htonl(info->guest_ip); 159155c7f33SAsias He sk->dip = htonl(info->host_ip); 160155c7f33SAsias He sk->sport = htons(UIP_DHCP_PORT_CLIENT); 161155c7f33SAsias He sk->dport = htons(UIP_DHCP_PORT_SERVER); 162155c7f33SAsias He 163155c7f33SAsias He return 0; 164155c7f33SAsias He } 165bcd315dbSAsias He 166bcd315dbSAsias He int uip_tx_do_ipv4_udp_dhcp(struct uip_tx_arg *arg) 167bcd315dbSAsias He { 168bcd315dbSAsias He struct uip_udp_socket sk; 169bcd315dbSAsias He struct uip_dhcp *dhcp; 170bcd315dbSAsias He struct uip_info *info; 171bcd315dbSAsias He struct uip_buf *buf; 172bcd315dbSAsias He u8 reply_msg_type; 173bcd315dbSAsias He 174bcd315dbSAsias He dhcp = (struct uip_dhcp *)arg->eth; 175bcd315dbSAsias He 176bcd315dbSAsias He if (uip_dhcp_is_discovery(dhcp)) 177bcd315dbSAsias He reply_msg_type = UIP_DHCP_OFFER; 178bcd315dbSAsias He else if (uip_dhcp_is_request(dhcp)) 179bcd315dbSAsias He reply_msg_type = UIP_DHCP_ACK; 180bcd315dbSAsias He else 181bcd315dbSAsias He return -1; 182bcd315dbSAsias He 183bcd315dbSAsias He buf = uip_buf_clone(arg); 184bcd315dbSAsias He info = arg->info; 185bcd315dbSAsias He 186bcd315dbSAsias He /* 187bcd315dbSAsias He * Cook DHCP pkg 188bcd315dbSAsias He */ 189bcd315dbSAsias He uip_dhcp_make_pkg(info, &sk, buf, reply_msg_type); 190bcd315dbSAsias He 191bcd315dbSAsias He /* 192bcd315dbSAsias He * Cook UDP pkg 193bcd315dbSAsias He */ 194bcd315dbSAsias He uip_udp_make_pkg(info, &sk, buf, NULL, UIP_DHCP_MAX_PAYLOAD_LEN); 195bcd315dbSAsias He 196bcd315dbSAsias He /* 197bcd315dbSAsias He * Send data received from socket to guest 198bcd315dbSAsias He */ 199bcd315dbSAsias He uip_buf_set_used(info, buf); 200bcd315dbSAsias He 201bcd315dbSAsias He return 0; 202bcd315dbSAsias He } 203*d87b503fSJean-Philippe Brucker 204*d87b503fSJean-Philippe Brucker void uip_dhcp_exit(struct uip_info *info) 205*d87b503fSJean-Philippe Brucker { 206*d87b503fSJean-Philippe Brucker free(info->domain_name); 207*d87b503fSJean-Philippe Brucker info->domain_name = NULL; 208*d87b503fSJean-Philippe Brucker } 209