1/* serverpacket.c 2 * 3 * Constuct and send DHCP server packets 4 * 5 * Russ Dill <Russ.Dill@asu.edu> July 2001 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2 of the License, or 10 * (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 */ 21 22#include <sys/socket.h> 23#include <netinet/in.h> 24#include <arpa/inet.h> 25#include <string.h> 26#include <time.h> 27#ifdef ARLO_SUPPORT 28#include <linux/ioctl.h> 29#include <stdio.h> 30#include <fcntl.h> 31#include <sys/stat.h> 32#endif 33#include "packet.h" 34#include "debug.h" 35#include "dhcpd.h" 36#include "options.h" 37#include "leases.h" 38 39/* Foxconn added start pling 06/19/2013 */ 40/* For wireless client associated to guest network, we want to assign lease time 41 * of 30 minutes only. 42 */ 43#include <sys/sysinfo.h> 44#include <stdlib.h> 45 46#define GUEST_LEASE_TIME 1800 //secs = 30 minutes 47#define MAX_REFRESH_TIME 3 // 3 secs, to refresh the guest assoc list 48#define GUEST_ASSOC_LIST "/tmp/wlan_guest_clients" 49 50/* 51 * Declare a buffer to store wireless assoclist. 52 * response of "wl assoclist": 53 * 54 * assoclist 00:11:22:33:44:55 55 * assoclist 00:22:33:44:55:66 56 * ... 57 * 58 * To accept max 64 clients, we need (27+2) * 64 = 1856. 59 * So choose 2048 buf size to store all guest clients. 60 */ 61static char guest_assoclist[2048]; 62 63static int get_guest_assoclist(void) 64{ 65 static long last_update =0; 66 struct sysinfo info; 67 char command[128]; 68 FILE *fp = NULL; 69 70 sysinfo(&info); 71 if (info.uptime - last_update >= MAX_REFRESH_TIME) { 72 /* Issue wl commands to create the new list */ 73 sprintf(command, "wl -i wl0.1 assoclist > %s", GUEST_ASSOC_LIST); 74 system(command); 75 sprintf(command, "wl -i wl1.1 assoclist >> %s", GUEST_ASSOC_LIST); 76 system(command); 77 78 /* Read the command output to internal buffer */ 79 memset(guest_assoclist, 0, sizeof(guest_assoclist)); 80 fp = fopen(GUEST_ASSOC_LIST, "r"); 81 if (fp) { 82 fread(guest_assoclist, 1, sizeof(guest_assoclist), fp); 83 fclose(fp); 84 last_update = info.uptime; 85 } 86 } 87} 88 89static int is_guest_network(char *mac) 90{ 91 char client_mac[32]; 92 93 sprintf(client_mac, "%02X:%02X:%02X:%02X:%02X:%02X", 94 (unsigned char)mac[0], 95 (unsigned char)mac[1], 96 (unsigned char)mac[2], 97 (unsigned char)mac[3], 98 (unsigned char)mac[4], 99 (unsigned char)mac[5]); 100 get_guest_assoclist(); 101 if (strstr(guest_assoclist, client_mac)) 102 return 1; 103 else 104 return 0; 105} 106/* Foxconn added end pling 06/19/2013 */ 107 108 109/* Foxconn added start James Hsu 03/05/2015 */ 110/* For arlo client associated to wl0.2, we want to assign lease time to one year 111 */ 112#ifdef ARLO_SUPPORT 113#define ARLO_ASSOC_LIST "/tmp/arlo_guest_clients" 114#define Arlo_lease_time 94608000 //secs for three year 115 116/* 117 * Declare a buffer to store wireless assoclist. 118 * response of "wl assoclist": 119 * 120 * assoclist 00:11:22:33:44:55 121 * assoclist 00:22:33:44:55:66 122 * ... 123 * 124 * To accept max 64 clients, we need (27+2) * 64 = 1856. 125 * So choose 2048 buf size to store all guest clients. 126 */ 127static char arlo_assoclist[2048]; 128 129static int get_arlo_assoclist(void) 130{ 131 static long last_update =0; 132 struct sysinfo info; 133 char command[128]; 134 FILE *fp = NULL; 135 136 sysinfo(&info); 137 if (info.uptime - last_update >= MAX_REFRESH_TIME) { 138 /* Issue wl commands to create the new list */ 139 sprintf(command, "wl -i wl0.2 assoclist > %s", ARLO_ASSOC_LIST); 140 system(command); 141 142 /* Read the command output to internal buffer */ 143 memset(arlo_assoclist, 0, sizeof(arlo_assoclist)); 144 fp = fopen(ARLO_ASSOC_LIST, "r"); 145 if (fp) { 146 fread(arlo_assoclist, 1, sizeof(arlo_assoclist), fp); 147 fclose(fp); 148 last_update = info.uptime; 149 } 150 } 151} 152 153 154static int is_arlo_network(char *mac) 155{ 156 char client_mac[32]; 157 158 sprintf(client_mac, "%02X:%02X:%02X:%02X:%02X:%02X", 159 (unsigned char)mac[0], 160 (unsigned char)mac[1], 161 (unsigned char)mac[2], 162 (unsigned char)mac[3], 163 (unsigned char)mac[4], 164 (unsigned char)mac[5]); 165 get_arlo_assoclist(); 166 if (strstr(arlo_assoclist, client_mac)) 167 return 1; 168 else 169 return 0; 170} 171#endif 172/* Foxconn added end, James Hsu */ 173 174 175/* send a packet to giaddr using the kernel ip stack */ 176static int send_packet_to_relay(struct dhcpMessage *payload) 177{ 178 DEBUG(LOG_INFO, "Forwarding packet to relay"); 179 180 return kernel_packet(payload, server_config.server, SERVER_PORT, 181 payload->giaddr, SERVER_PORT); 182} 183 184 185/* send a packet to a specific arp address and ip address by creating our own ip packet */ 186static int send_packet_to_client(struct dhcpMessage *payload, int force_broadcast) 187{ 188 unsigned char *chaddr; 189 u_int32_t ciaddr; 190 191 if (force_broadcast) { 192 DEBUG(LOG_INFO, "broadcasting packet to client (NAK)"); 193 ciaddr = INADDR_BROADCAST; 194 chaddr = MAC_BCAST_ADDR; 195 } else if (payload->ciaddr) { 196 DEBUG(LOG_INFO, "unicasting packet to client ciaddr"); 197 ciaddr = payload->ciaddr; 198 chaddr = payload->chaddr; 199 } else if (ntohs(payload->flags) & BROADCAST_FLAG) { 200 DEBUG(LOG_INFO, "broadcasting packet to client (requested)"); 201 ciaddr = INADDR_BROADCAST; 202 chaddr = MAC_BCAST_ADDR; 203 } else { 204 DEBUG(LOG_INFO, "unicasting packet to client yiaddr"); 205 ciaddr = payload->yiaddr; 206 chaddr = payload->chaddr; 207 } 208 return raw_packet(payload, server_config.server, SERVER_PORT, 209 ciaddr, CLIENT_PORT, chaddr, server_config.ifindex); 210} 211 212 213/* send a dhcp packet, if force broadcast is set, the packet will be broadcast to the client */ 214static int send_packet(struct dhcpMessage *payload, int force_broadcast) 215{ 216 int ret; 217 218 if (payload->giaddr) 219 ret = send_packet_to_relay(payload); 220 else ret = send_packet_to_client(payload, force_broadcast); 221 return ret; 222} 223 224 225static void init_packet(struct dhcpMessage *packet, struct dhcpMessage *oldpacket, char type) 226{ 227 init_header(packet, type); 228 packet->xid = oldpacket->xid; 229 memcpy(packet->chaddr, oldpacket->chaddr, 16); 230 packet->flags = oldpacket->flags; 231 packet->giaddr = oldpacket->giaddr; 232 packet->ciaddr = oldpacket->ciaddr; 233 add_simple_option(packet->options, DHCP_SERVER_ID, server_config.server); 234} 235 236 237/* add in the bootp options */ 238static void add_bootp_options(struct dhcpMessage *packet) 239{ 240 packet->siaddr = server_config.siaddr; 241 if (server_config.sname) 242 strncpy(packet->sname, server_config.sname, sizeof(packet->sname) - 1); 243 if (server_config.boot_file) 244 strncpy(packet->file, server_config.boot_file, sizeof(packet->file) - 1); 245} 246 247 248/* send a DHCP OFFER to a DHCP DISCOVER */ 249int sendOffer(struct dhcpMessage *oldpacket) 250{ 251 struct dhcpMessage packet; 252 struct dhcpOfferedAddr *lease = NULL; 253 u_int32_t req_align, lease_time_align = server_config.lease; 254 unsigned char *req, *lease_time; 255 struct option_set *curr; 256 struct in_addr addr; 257 unsigned char mac[6]; 258 u_int32_t reserved_ip; 259 260 memcpy(mac, oldpacket->chaddr, 6); 261 262 init_packet(&packet, oldpacket, DHCPOFFER); 263 264 /* ADDME: if static, short circuit */ 265 /* the client is in our lease/offered table */ 266 if ((lease = find_lease_by_chaddr(oldpacket->chaddr)) && 267 268 /* Make sure the IP is not already used on network */ 269 !check_ip(lease->yiaddr)) { 270 271 if (!lease_expired(lease)) 272 lease_time_align = lease->expires - time(0); 273 packet.yiaddr = lease->yiaddr; 274 275 /* Find a reserved ip for this MAC */ 276 } else if ( (reserved_ip = find_reserved_ip(mac)) != 0) { 277 packet.yiaddr = htonl(reserved_ip); 278 279 /* Or the client has a requested ip */ 280 } else if ((req = get_option(oldpacket, DHCP_REQUESTED_IP)) && 281 282 /* Don't look here (ugly hackish thing to do) */ 283 memcpy(&req_align, req, 4) && 284 285 /* check if the requested ip has been reserved */ 286 check_reserved_ip(req_align, mac) && 287 288 /* and the ip is in the lease range */ 289 ntohl(req_align) >= ntohl(server_config.start) && 290 ntohl(req_align) <= ntohl(server_config.end) && 291 292 /* Check that this request ip is not on network */ 293 //!check_ip(ntohl(req_align)) && 294 /* the input parameter of check_ip() should be network order */ 295 !check_ip(req_align) && /* Foxconn modified by Max Ding, 07/07/2011 @TD #42 of WNR3500Lv2 */ 296 297 /* and its not already taken/offered */ /* ADDME: check that its not a static lease */ 298 ((!(lease = find_lease_by_yiaddr(req_align)) || 299 300 /* or its taken, but expired */ /* ADDME: or maybe in here */ 301 lease_expired(lease)))) { 302 packet.yiaddr = req_align; 303 304 /* otherwise, find a free IP */ /*ADDME: is it a static lease? */ 305 } else { 306 packet.yiaddr = find_address2(0, mac); 307 308 /* try for an expired lease */ 309 if (!packet.yiaddr) packet.yiaddr = find_address2(1, mac); 310 } 311 312 if(!packet.yiaddr) { 313 LOG(LOG_WARNING, "no IP addresses to give -- OFFER abandoned"); 314 return -1; 315 } 316 317 if (!add_lease(packet.chaddr, packet.yiaddr, server_config.offer_time)) { 318 LOG(LOG_WARNING, "lease pool is full -- OFFER abandoned"); 319 return -1; 320 } 321 322 if ((lease_time = get_option(oldpacket, DHCP_LEASE_TIME))) { 323 memcpy(&lease_time_align, lease_time, 4); 324 lease_time_align = ntohl(lease_time_align); 325 if (lease_time_align > server_config.lease) 326 lease_time_align = server_config.lease; 327 } 328 329 /* Make sure we aren't just using the lease time from the previous offer */ 330 if (lease_time_align < server_config.min_lease) 331 lease_time_align = server_config.lease; 332 333 /* Foxconn added start pling 06/19/2013 */ 334 /* For guest network clients, set lease time to 30 minutes */ 335 if (is_guest_network(mac)) { 336 lease_time_align = GUEST_LEASE_TIME; 337 DEBUG(LOG_INFO, "send OFFER to guest network client with lease time %d sec", GUEST_LEASE_TIME); 338 } 339 /* Foxconn added end pling 06/19/2013 */ 340 341 /* Foxconn added start, James Hsu, 03/05/2015 */ 342 /* For arlo network client, set lease time to 3 year */ 343#ifdef ARLO_SUPPORT 344 if (is_arlo_network(mac)) { 345 lease_time_align = Arlo_lease_time; 346 DEBUG(LOG_INFO, "send OFFER to arlo network client with lease time %d sec", Arlo_lease_time); 347 } 348#endif 349 /* Foxconn added end, James Hsu, 03/05/2015 */ 350 351 /* ADDME: end of short circuit */ 352 add_simple_option(packet.options, DHCP_LEASE_TIME, htonl(lease_time_align)); 353 354 curr = server_config.options; 355 while (curr) { 356 if (curr->data[OPT_CODE] != DHCP_LEASE_TIME) 357 add_option_string(packet.options, curr->data); 358 curr = curr->next; 359 } 360 361 add_bootp_options(&packet); 362 363 addr.s_addr = packet.yiaddr; 364 LOG(LOG_INFO, "sending OFFER of %s", inet_ntoa(addr)); 365 return send_packet(&packet, 0); 366} 367 368 369int sendNAK(struct dhcpMessage *oldpacket) 370{ 371 struct dhcpMessage packet; 372 373 init_packet(&packet, oldpacket, DHCPNAK); 374 375 DEBUG(LOG_INFO, "sending NAK"); 376 return send_packet(&packet, 1); 377} 378 379 380int sendACK(struct dhcpMessage *oldpacket, u_int32_t yiaddr) 381{ 382 struct dhcpMessage packet; 383 struct option_set *curr; 384 unsigned char *lease_time; 385 386 //Foxconn added start Bob Guo 11/15/2006 387 FILE *fp; 388 unsigned char *client_mac, *client_ip; 389 char logBuffer[96]; 390 //Foxconn added end Bob Guo 11/15/2006 391 392 u_int32_t lease_time_align = server_config.lease; 393 struct in_addr addr; 394 395 init_packet(&packet, oldpacket, DHCPACK); 396 packet.yiaddr = yiaddr; 397 398 if ((lease_time = get_option(oldpacket, DHCP_LEASE_TIME))) { 399 memcpy(&lease_time_align, lease_time, 4); 400 lease_time_align = ntohl(lease_time_align); 401 if (lease_time_align > server_config.lease) 402 lease_time_align = server_config.lease; 403 else if (lease_time_align < server_config.min_lease) 404 lease_time_align = server_config.lease; 405 } 406 407 /* Foxconn added start pling 06/19/2013 */ 408 /* For guest network clients, set lease time to 30 minutes */ 409 if (is_guest_network(packet.chaddr)) { 410 lease_time_align = GUEST_LEASE_TIME; 411 DEBUG(LOG_INFO, "send ACK to guest network client with lease time %d sec", GUEST_LEASE_TIME); 412 } 413 /* Foxconn added end pling 06/19/2013 */ 414 415 /* Foxconn added start, James Hsu, 03/05/2015 */ 416 /* For arlo network client, set lease time to 1 year */ 417#ifdef ARLO_SUPPORT 418 int arlo_arp_buf[64]; 419 char arlo_mac[32]; 420 struct in_addr arlo_addr; 421 if (is_arlo_network(packet.chaddr)) { 422 arlo_addr.s_addr=packet.yiaddr; 423 lease_time_align = Arlo_lease_time; 424 DEBUG(LOG_INFO, "send OFFER to arlo network client with lease time %d sec", Arlo_lease_time); 425 sprintf(arlo_mac, "%02X:%02X:%02X:%02X:%02X:%02X", 426 (unsigned char)packet.chaddr[0], 427 (unsigned char)packet.chaddr[1], 428 (unsigned char)packet.chaddr[2], 429 (unsigned char)packet.chaddr[3], 430 (unsigned char)packet.chaddr[4], 431 (unsigned char)packet.chaddr[5]); 432 sprintf(arlo_arp_buf,"arp -s %s %s",inet_ntoa(arlo_addr), arlo_mac); 433 system(arlo_arp_buf); 434 435 FILE *arlo_client_mac_file; 436 /* Fxconn added start, James Hsu, 04/15/2015 Record arlo client mac to nvram */ 437 arlo_client_mac_file=fopen("/tmp/arlo_client_mac.txt","w"); 438 if (arlo_client_mac_file) 439 { 440 fwrite(arlo_mac,sizeof(arlo_mac),1,arlo_client_mac_file); 441 fclose(arlo_client_mac_file); 442 system ("killall -SIGPIPE arlo_monitor"); 443 } 444 /* Fxconn added end, James Hsu, 04/15/2015 */ 445 446 /* Fxconn added start, James Hsu, 04/08/2015, for isolation arlo network */ 447 #define DEV_FILE_NAME_W_PATH "/dev/acos_nat_cli" 448 #define MAJOR_NUM 100 449 #define IOCTL_AG_ARLO_CLIENT_MAC _IOW(MAJOR_NUM, 203, char *) 450 int ret_val=0, file_desc; 451 char *arlo_client_mac; 452 memcpy(arlo_mac, packet.chaddr,6); 453 file_desc = open(DEV_FILE_NAME_W_PATH, O_RDWR); 454 if (file_desc < 0) 455 { 456 printf("Can't open device file: %s\n", DEV_FILE_NAME_W_PATH); 457 DEBUG(LOG_INFO, "Can't open device file: %s\n", DEV_FILE_NAME_W_PATH); 458 return 0; 459 } 460 ret_val = ioctl(file_desc, IOCTL_AG_ARLO_CLIENT_MAC, arlo_mac); 461 close(file_desc); 462 /* Fxconn added end, James Hsu, 04/08/2015, for isolation arlo network */ 463 } 464#endif 465 /* Foxconn added end, James Hsu, 03/05/2015 */ 466 467 add_simple_option(packet.options, DHCP_LEASE_TIME, htonl(lease_time_align)); 468 469 curr = server_config.options; 470 while (curr) { 471 if (curr->data[OPT_CODE] != DHCP_LEASE_TIME) 472 add_option_string(packet.options, curr->data); 473 curr = curr->next; 474 } 475 476 add_bootp_options(&packet); 477 478 addr.s_addr = packet.yiaddr; 479 LOG(LOG_INFO, "sending ACK to %s", inet_ntoa(addr)); 480 481 if (send_packet(&packet, 0) < 0) 482 return -1; 483 484 add_lease(packet.chaddr, packet.yiaddr, lease_time_align); 485 //Foxconn added start Bob Guo 11/15/2006 486 client_mac = (unsigned char *)packet.chaddr; 487 client_ip = (unsigned char *)&packet.yiaddr; 488 sprintf(logBuffer, "[DHCP IP: (%d.%d.%d.%d)] to MAC address %02X:%02X:%02X:%02X:%02X:%02X,", 489 *client_ip, *(client_ip+1), *(client_ip+2), *(client_ip+3), 490 *client_mac, *(client_mac+1), *(client_mac+2), *(client_mac+3), *(client_mac+4), *(client_mac+5)); 491 if ((fp = fopen("/dev/aglog", "r+")) != NULL) 492 { 493 fwrite(logBuffer, sizeof(char), strlen(logBuffer)+1, fp); 494 fclose(fp); 495 } 496 //Foxconn added end Bob Guo 11/15/2006 497 498 return 0; 499} 500 501 502int send_inform(struct dhcpMessage *oldpacket) 503{ 504 struct dhcpMessage packet; 505 struct option_set *curr; 506 507 init_packet(&packet, oldpacket, DHCPACK); 508 509 curr = server_config.options; 510 while (curr) { 511 if (curr->data[OPT_CODE] != DHCP_LEASE_TIME) 512 add_option_string(packet.options, curr->data); 513 curr = curr->next; 514 } 515 516 add_bootp_options(&packet); 517 518 return send_packet(&packet, 0); 519} 520 521 522 523