#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <stdio.h>
#include <arpa/inet.h>
#include <sys/un.h>
#include <net/if.h>
#include <pthread.h>
#include <sys/time.h>
#include <unistd.h>
#include <syslog.h>
#include <signal.h>
#include <time.h>
#include <stdlib.h>
#include <assert.h>
#include <errno.h>
#include <getopt.h>
#include <sys/uio.h>
#include "ha.h"
#include "list.h"
#include "hashtable.h"
#include "fileio.h"
#include "msgparser.h"
#include "agentadv.h"
#include "proxyarp.h"
#include "binding.h"
#include "auth.h"
#include "tunnel.h"
#include "debug.h"
#include "agentapi.h"
#include "util.h"
#include "fixed_fd_zero.h"
#include "dyn_ip.h"
#include "ha_config.h"
#include "agent_utils.h"
#include "md5_mac.h"
#include "clientpacket.h"
#include "packet.h"
#include "script.h"
#include "socket.h"
#include "pidfile.h"
Include dependency graph for ha.c:
Go to the source code of this file.
Data Structures | |
struct | dhcp_mobile |
Defines | |
#define | DEBUG_FLAG 'H' |
#define | __USE_BSD |
#define | DEFAULT_SCRIPT "/usr/share/udhcpc/default.script" |
#define | LISTEN_NONE 0 |
#define | LISTEN_KERNEL 1 |
#define | LISTEN_RAW 2 |
#define | ASSERT assert |
#define | MIN(x, y) ( (x) < (y) ? (x) : (y)) |
#define | LOG2(lev, fmt, args...) |
#define | MAX_ADV_DELAY 200000.0 |
Functions | |
int | find_dhcp_mobile (unsigned char *nai, int nai_length) |
DYNAMO find_dhcp_mobile: : Pointer to the mobile node's NAI : Mobile node's NAIs length Returns: Mobile nodes index in array on success or -1 on error. | |
int | add_dhcp_mobile (unsigned long ip, unsigned char *nai, int nai_length) |
DYNAMO add_dhcp_mobile: : Home address of the mobile node : Pointer to the mobile node's NAI : Mobile node's NAIs length Returns: 1 on success or 0 on error. | |
int | del_dhcp_mobile (int i) |
DYNAMO del_dhcp_mobile: : Index of the mobile node in array. | |
unsigned long | udhcp (int selected_mobile, int flag) |
UDHCP old main modified by Dynamo udhcp: : Index of the selected mobile node in array : Flag that tells what to do with selected mobile node. | |
Variables | |
client_config_t | client_config |
int | opt_foreground |
char * | opt_config |
dhcp_mobile | dhcp_mobile_array [HA_DEFAULT_MAX_BINDINGS] |
int | cur_mobiles = 0 |
int | maxmobiles = HA_DEFAULT_MAX_BINDINGS |
fa_nai_ext * | ha_nai = NULL |
#define ASSERT assert |
#define LOG2 | ( | lev, | |||
fmt, | |||||
args... | ) |
Value:
{ DEBUG(DEBUG_FLAG, fmt, ## args); \ syslog(lev, fmt, ## args); }
int add_dhcp_mobile | ( | unsigned long | ip, | |
unsigned char * | nai, | |||
int | nai_length | |||
) |
DYNAMO add_dhcp_mobile: : Home address of the mobile node : Pointer to the mobile node's NAI : Mobile node's NAIs length Returns: 1 on success or 0 on error.
Definition at line 225 of file ha.c.
References cur_mobiles, dhcp_mobile_array, DHCPDISCOVER, maxmobiles, dhcp_mobile::nai, dhcp_mobile::nai_length, dhcp_mobile::requested_ip, dhcp_mobile::state, dhcp_mobile::timeout, and xmalloc.
00226 { 00227 if (cur_mobiles==maxmobiles) return 0; 00228 dhcp_mobile_array[cur_mobiles].requested_ip=ip; 00229 dhcp_mobile_array[cur_mobiles].timeout=0; 00230 dhcp_mobile_array[cur_mobiles].state=DHCPDISCOVER; 00231 dhcp_mobile_array[cur_mobiles].nai= xmalloc(nai_length); 00232 memcpy(dhcp_mobile_array[cur_mobiles].nai, nai, nai_length); 00233 dhcp_mobile_array[cur_mobiles].nai_length=nai_length; 00234 cur_mobiles=cur_mobiles+1; 00235 return 1; 00236 }
int del_dhcp_mobile | ( | int | i | ) |
DYNAMO del_dhcp_mobile: : Index of the mobile node in array.
Returns: 1 on success or 0 on error
Definition at line 247 of file ha.c.
References cur_mobiles, dhcp_mobile_array, dhcp_mobile::fd, dhcp_mobile::lease, dhcp_mobile::nai_length, dhcp_mobile::packet_num, dhcp_mobile::requested_ip, dhcp_mobile::server_addr, dhcp_mobile::signal_pipe, dhcp_mobile::spi, dhcp_mobile::state, and dhcp_mobile::timeout.
00248 { 00249 if(cur_mobiles <= i || i<0) return 0; //index out of array 00250 free(dhcp_mobile_array[i].nai); 00251 dhcp_mobile_array[i].state=0; 00252 dhcp_mobile_array[i].requested_ip=0; 00253 dhcp_mobile_array[i].server_addr=0; 00254 dhcp_mobile_array[i].timeout=0; 00255 dhcp_mobile_array[i].packet_num=0; 00256 dhcp_mobile_array[i].fd=0; 00257 dhcp_mobile_array[i].signal_pipe[0]=0; 00258 dhcp_mobile_array[i].signal_pipe[1]=0; 00259 dhcp_mobile_array[i].nai_length=0; 00260 dhcp_mobile_array[i].lease=0; 00261 dhcp_mobile_array[i].spi=0; 00262 dhcp_mobile_array[i]=dhcp_mobile_array[cur_mobiles-1]; 00263 cur_mobiles=cur_mobiles-1; 00264 return 1; 00265 00266 }
int find_dhcp_mobile | ( | unsigned char * | nai, | |
int | nai_length | |||
) |
DYNAMO find_dhcp_mobile: : Pointer to the mobile node's NAI : Mobile node's NAIs length Returns: Mobile nodes index in array on success or -1 on error.
Definition at line 193 of file ha.c.
References cur_mobiles, and dhcp_mobile_array.
00194 { 00195 int i, n, found; 00196 found=-1; 00197 for(i=0;i<cur_mobiles;i++) 00198 { 00199 if(nai_length==dhcp_mobile_array[i].nai_length) 00200 { 00201 n=memcmp(nai, dhcp_mobile_array[i].nai,nai_length); 00202 if( n==0 ) 00203 { 00204 found=i; 00205 break; 00206 } 00207 } 00208 00209 } 00210 00211 return found; 00212 00213 }
unsigned long udhcp | ( | int | selected_mobile, | |
int | flag | |||
) |
UDHCP old main modified by Dynamo udhcp: : Index of the selected mobile node in array : Flag that tells what to do with selected mobile node.
Returns: Mobile node's home address on Discovery or 0 on Release or -1 on error
Definition at line 379 of file ha.c.
References client_config_t::arp, BOUND, client_config, CLIENT_PORT, client_config_t::clientid, DEBUG, DHCP_CLIENT_ID, DHCP_LEASE_TIME, DHCP_MESSAGE_TYPE, dhcp_mobile_array, DHCP_SERVER_ID, DHCPACK, DHCPNAK, DHCPOFFER, dhcp_mobile::fd, client_config_t::foreground, get_packet(), get_raw_packet(), client_config_t::ifindex, INIT_SELECTING, client_config_t::interface, LISTEN_KERNEL, LISTEN_NONE, LISTEN_RAW, listen_socket(), LOG, LOG_ERR, LOG_INFO, dhcp_mobile::nai, dhcp_mobile::nai_length, OPEN_LOG, OPT_CODE, OPT_DATA, OPT_LEN, dhcp_mobile::packet_num, client_config_t::pidfile, pidfile_acquire(), pidfile_write_release(), client_config_t::quit_after_lease, random_xid(), raw_socket(), read_interface(), REBINDING, RELEASED, RELEASEIP, RENEW_REQUESTED, RENEWING, RENEWIP, dhcp_mobile::requested_ip, REQUESTING, REQUESTIP, run_script(), send_discover(), send_renew(), send_selecting(), dhcp_mobile::signal_pipe, dhcp_mobile::state, dhcp_mobile::timeout, dhcpMessage::xid, xmalloc, and dhcpMessage::yiaddr.
00380 { 00381 00382 unsigned char *temp, *message; 00383 unsigned long t1 = 0, t2 = 0, xid = 0; 00384 unsigned long start = 0, lease; 00385 fd_set rfds; 00386 int retval; 00387 struct timeval tv; 00388 int c, len; 00389 struct dhcpMessage packet; 00390 struct in_addr temp_addr; 00391 int pid_fd; 00392 time_t now; 00393 int max_fd; 00394 int sig; 00395 00396 00397 if (flag == REQUESTIP) 00398 { 00399 if(dhcp_mobile_array[selected_mobile].state==2) return 0; 00400 listen_mode = 0; 00401 dhcp_mobile_array[selected_mobile].state=1; 00402 } 00403 00404 00405 if (flag == RELEASEIP) 00406 { 00407 perform_release(selected_mobile); 00408 return 0; 00409 } 00410 00411 if(flag == RENEWIP) 00412 { 00413 perform_renew(selected_mobile); 00414 return dhcp_mobile_array[selected_mobile].requested_ip; 00415 } 00416 00417 OPEN_LOG("udhcpc"); 00418 00419 pid_fd = pidfile_acquire(client_config.pidfile); 00420 pidfile_write_release(pid_fd); 00421 if (read_interface(client_config.interface, &client_config.ifindex, 00422 NULL, client_config.arp) < 0) 00423 exit_client(1); //should never exit in this version! 00424 00425 /* 00426 DYNAMO:Set NAI into client_id field 00427 */ 00428 00429 int mal_big = dhcp_mobile_array[selected_mobile].nai_length+2; 00430 client_config.clientid = xmalloc(mal_big); 00431 client_config.clientid[OPT_CODE] = DHCP_CLIENT_ID; 00432 client_config.clientid[OPT_LEN] = dhcp_mobile_array[selected_mobile].nai_length; 00433 client_config.clientid[OPT_DATA] = 1; 00434 memcpy(client_config.clientid + 2, dhcp_mobile_array[selected_mobile].nai, dhcp_mobile_array[selected_mobile].nai_length); 00435 00436 /* setup signal handlers */ 00437 socketpair(AF_UNIX, SOCK_STREAM, 0, dhcp_mobile_array[selected_mobile].signal_pipe); 00438 signal(SIGUSR1, signal_handler); 00439 signal(SIGUSR2, signal_handler); 00440 signal(SIGTERM, signal_handler); 00441 00442 dhcp_mobile_array[selected_mobile].state = INIT_SELECTING; 00443 00444 change_mode(LISTEN_RAW, selected_mobile); 00445 00446 for (;;) { 00447 00448 tv.tv_sec = dhcp_mobile_array[selected_mobile].timeout - time(0); 00449 tv.tv_usec = 0; 00450 FD_ZERO(&rfds); 00451 00452 if (listen_mode != LISTEN_NONE && dhcp_mobile_array[selected_mobile].fd < 0) { 00453 if (listen_mode == LISTEN_KERNEL) 00454 dhcp_mobile_array[selected_mobile].fd = listen_socket(INADDR_ANY, CLIENT_PORT, client_config.interface); 00455 else 00456 dhcp_mobile_array[selected_mobile].fd = raw_socket(client_config.ifindex); 00457 if (dhcp_mobile_array[selected_mobile].fd < 0) { 00458 LOG(LOG_ERR, "FATAL: couldn't listen on socket, %s", strerror(errno)); 00459 exit_client(0); 00460 } 00461 } 00462 if (dhcp_mobile_array[selected_mobile].fd >= 0) FD_SET(dhcp_mobile_array[selected_mobile].fd, &rfds); 00463 FD_SET(dhcp_mobile_array[selected_mobile].signal_pipe[0], &rfds); 00464 00465 if (tv.tv_sec > 0) { 00466 DEBUG(LOG_INFO, "Waiting on select...\n"); 00467 max_fd = dhcp_mobile_array[selected_mobile].signal_pipe[0] > dhcp_mobile_array[selected_mobile].fd ? dhcp_mobile_array[selected_mobile].signal_pipe[0] : dhcp_mobile_array[selected_mobile].fd; 00468 retval = select(max_fd + 1, &rfds, NULL, NULL, &tv); 00469 } else retval = 0; /* If we already timed out, fall through */ 00470 00471 now = time(0); 00472 if (retval == 0) { 00473 /* timeout dropped to zero */ 00474 switch (dhcp_mobile_array[selected_mobile].state) { 00475 case INIT_SELECTING: 00476 if (dhcp_mobile_array[selected_mobile].packet_num < 3) { 00477 if (dhcp_mobile_array[selected_mobile].packet_num == 0) 00478 xid = random_xid(); 00479 00480 /* send discover packet */ 00481 00482 send_discover(xid, dhcp_mobile_array[selected_mobile].requested_ip); /* broadcast */ 00483 00484 dhcp_mobile_array[selected_mobile].timeout = now + ((dhcp_mobile_array[selected_mobile].packet_num == 2) ? 4 : 2); 00485 dhcp_mobile_array[selected_mobile].packet_num++; 00486 } else { 00487 /* 00488 if (client_config.background_if_no_lease) { 00489 LOG(LOG_INFO, "No lease, forking to background."); 00490 background(); 00491 } else if (client_config.abort_if_no_lease) { 00492 LOG(LOG_INFO, "No lease, failing."); 00493 exit_client(1); 00494 } 00495 */ 00496 /* wait to try again */ 00497 dhcp_mobile_array[selected_mobile].packet_num = 0; 00498 dhcp_mobile_array[selected_mobile].timeout = 0; 00499 LOG(LOG_INFO, "DHCP-server did not answer after 3 DHCPDISCOVERs"); 00500 return -1; //failed after 3 discovers! 00501 } 00502 00503 break; 00504 case RENEW_REQUESTED: 00505 case REQUESTING: 00506 if (dhcp_mobile_array[selected_mobile].packet_num < 3) { 00507 /* send request packet */ 00508 00509 if (dhcp_mobile_array[selected_mobile].state == RENEW_REQUESTED) 00510 send_renew(xid, dhcp_mobile_array[selected_mobile].server_addr, dhcp_mobile_array[selected_mobile].requested_ip); /* unicast */ 00511 else send_selecting(xid, dhcp_mobile_array[selected_mobile].server_addr, dhcp_mobile_array[selected_mobile].requested_ip); /* broadcast */ 00512 00513 dhcp_mobile_array[selected_mobile].timeout = now + ((dhcp_mobile_array[selected_mobile].packet_num == 2) ? 10 : 2); 00514 dhcp_mobile_array[selected_mobile].packet_num++; 00515 } else { 00516 00517 /* timed out, go back to init state */ 00518 if (dhcp_mobile_array[selected_mobile].state == RENEW_REQUESTED) run_script(NULL, "deconfig"); 00519 dhcp_mobile_array[selected_mobile].state = INIT_SELECTING; 00520 dhcp_mobile_array[selected_mobile].timeout = now; 00521 dhcp_mobile_array[selected_mobile].packet_num = 0; 00522 change_mode(LISTEN_RAW, selected_mobile); 00523 } 00524 break; 00525 case BOUND: 00526 /* Lease is starting to run out, time to enter renewing state */ 00527 dhcp_mobile_array[selected_mobile].state = RENEWING; 00528 change_mode(LISTEN_KERNEL, selected_mobile); 00529 00530 DEBUG(LOG_INFO, "Entering renew state"); 00531 /* fall right through */ 00532 case RENEWING: 00533 /* Either set a new T1, or enter REBINDING state */ 00534 if ((t2 - t1) <= (lease / 14400 + 1)) { 00535 /* timed out, enter rebinding state */ 00536 dhcp_mobile_array[selected_mobile].state = REBINDING; 00537 dhcp_mobile_array[selected_mobile].timeout = now + (t2 - t1); 00538 DEBUG(LOG_INFO, "Entering rebinding state"); 00539 } else { 00540 /* send a request packet */ 00541 send_renew(xid, dhcp_mobile_array[selected_mobile].server_addr, dhcp_mobile_array[selected_mobile].requested_ip); /* unicast */ 00542 00543 t1 = (t2 - t1) / 2 + t1; 00544 dhcp_mobile_array[selected_mobile].timeout = t1 + start; 00545 } 00546 break; 00547 case REBINDING: 00548 /* Either set a new T2, or enter INIT state */ 00549 if ((lease - t2) <= (lease / 14400 + 1)) { 00550 /* timed out, enter init state */ 00551 dhcp_mobile_array[selected_mobile].state = INIT_SELECTING; 00552 LOG(LOG_INFO, "Lease lost, entering init state"); 00553 run_script(NULL, "deconfig"); 00554 dhcp_mobile_array[selected_mobile].timeout = now; 00555 dhcp_mobile_array[selected_mobile].packet_num = 0; 00556 change_mode(LISTEN_RAW, selected_mobile); 00557 } else { 00558 /* send a request packet */ 00559 send_renew(xid, 0, dhcp_mobile_array[selected_mobile].requested_ip); /* broadcast */ 00560 00561 t2 = (lease - t2) / 2 + t2; 00562 dhcp_mobile_array[selected_mobile].timeout = t2 + start; 00563 } 00564 break; 00565 case RELEASED: 00566 /* yah, I know, *you* say it would never happen */ 00567 dhcp_mobile_array[selected_mobile].timeout = 0; 00568 break; 00569 } 00570 00571 00572 } else if (retval > 0 && listen_mode != LISTEN_NONE && FD_ISSET(dhcp_mobile_array[selected_mobile].fd, &rfds)) { 00573 /* a packet is ready, read it */ 00574 00575 if (listen_mode == LISTEN_KERNEL) 00576 len = get_packet(&packet, dhcp_mobile_array[selected_mobile].fd); 00577 else len = get_raw_packet(&packet, dhcp_mobile_array[selected_mobile].fd); 00578 00579 if (len == -1 && errno != EINTR) { 00580 DEBUG(LOG_INFO, "error on read, %s, reopening socket", strerror(errno)); 00581 change_mode(listen_mode, selected_mobile); /* just close and reopen */ 00582 } 00583 if (len < 0) continue; 00584 00585 00586 if (packet.xid != xid) { 00587 DEBUG(LOG_INFO, "Ignoring XID %lx (our xid is %lx)", 00588 (unsigned long) packet.xid, xid); 00589 continue; 00590 } 00591 00592 if ((message = get_option(&packet, DHCP_MESSAGE_TYPE)) == NULL) { 00593 DEBUG(LOG_ERR, "couldnt get option from packet -- ignoring"); 00594 continue; 00595 } 00596 00597 switch (dhcp_mobile_array[selected_mobile].state) { 00598 case INIT_SELECTING: 00599 /* Must be a DHCPOFFER to one of our xid's */ 00600 if (*message == DHCPOFFER) { 00601 if ((temp = get_option(&packet, DHCP_SERVER_ID))) { 00602 memcpy(&dhcp_mobile_array[selected_mobile].server_addr, temp, 4); 00603 xid = packet.xid; 00604 dhcp_mobile_array[selected_mobile].requested_ip = packet.yiaddr; //ip in data struct 00605 00606 /* enter requesting state */ 00607 dhcp_mobile_array[selected_mobile].state = REQUESTING; 00608 dhcp_mobile_array[selected_mobile].timeout = now; 00609 dhcp_mobile_array[selected_mobile].packet_num = 0; 00610 } else { 00611 DEBUG(LOG_ERR, "No server ID in message"); 00612 } 00613 } 00614 break; 00615 case RENEW_REQUESTED: 00616 case REQUESTING: 00617 case RENEWING: 00618 case REBINDING: 00619 if (*message == DHCPACK) { 00620 if (!(temp = get_option(&packet, DHCP_LEASE_TIME))) { 00621 LOG(LOG_ERR, "No lease time with ACK, using 1 hour lease"); 00622 lease = 60 * 60; 00623 } else { 00624 memcpy(&lease, temp, 4); 00625 lease = ntohl(lease); 00626 } 00627 00628 /* enter bound state */ 00629 t1 = lease / 2; 00630 00631 /* little fixed point for n * .875 */ 00632 t2 = (lease * 0x7) >> 3; 00633 temp_addr.s_addr = packet.yiaddr; 00634 LOG(LOG_INFO, "Lease of %s obtained, lease time %ld", 00635 inet_ntoa(temp_addr), lease); 00636 start = now; 00637 dhcp_mobile_array[selected_mobile].timeout = t1 + start; 00638 dhcp_mobile_array[selected_mobile].requested_ip = packet.yiaddr; 00639 run_script(&packet, 00640 ((dhcp_mobile_array[selected_mobile].state == RENEWING || dhcp_mobile_array[selected_mobile].state == REBINDING) ? "renew" : "bound")); 00641 00642 dhcp_mobile_array[selected_mobile].state = BOUND; 00643 change_mode(LISTEN_NONE, selected_mobile); 00644 if (client_config.quit_after_lease){ 00645 return dhcp_mobile_array[selected_mobile].requested_ip; 00646 } 00647 if (!client_config.foreground){ 00648 00649 return dhcp_mobile_array[selected_mobile].requested_ip; 00650 } 00651 00652 } else if (*message == DHCPNAK) { 00653 /* return to init state */ 00654 LOG(LOG_INFO, "Received DHCP NAK"); 00655 run_script(&packet, "nak"); 00656 if (dhcp_mobile_array[selected_mobile].state != REQUESTING) 00657 run_script(NULL, "deconfig"); 00658 dhcp_mobile_array[selected_mobile].state = INIT_SELECTING; 00659 dhcp_mobile_array[selected_mobile].timeout = now; 00660 dhcp_mobile_array[selected_mobile].requested_ip = 0; 00661 dhcp_mobile_array[selected_mobile].packet_num = 0; 00662 change_mode(LISTEN_RAW, selected_mobile); 00663 sleep(3); /* avoid excessive network traffic */ 00664 } 00665 break; 00666 /* case BOUND, RELEASED: - ignore all packets */ 00667 } 00668 } else if (retval > 0 && FD_ISSET(dhcp_mobile_array[selected_mobile].signal_pipe[0], &rfds)) { 00669 if (read(dhcp_mobile_array[selected_mobile].signal_pipe[0], &sig, sizeof(signal)) < 0) { 00670 DEBUG(LOG_ERR, "Could not read signal: %s", 00671 strerror(errno)); 00672 continue; /* probably just EINTR */ 00673 } 00674 switch (sig) { 00675 case SIGUSR1: 00676 perform_renew(selected_mobile); 00677 break; 00678 case SIGUSR2: 00679 perform_release(selected_mobile); 00680 break; 00681 case SIGTERM: 00682 LOG(LOG_INFO, "Received SIGTERM"); 00683 exit_client(0); 00684 } 00685 } else if (retval == -1 && errno == EINTR) { 00686 /* a signal was caught */ 00687 } else { 00688 /* An error occured */ 00689 DEBUG(LOG_ERR, "Error on select"); 00690 } 00691 00692 } 00693 00694 return 0; 00695 }
Here is the call graph for this function:
struct client_config_t client_config |
Initial value:
{ abort_if_no_lease: 0, foreground: 0, quit_after_lease: 0, background_if_no_lease: 0, interface: "eth2", pidfile: NULL, script: DEFAULT_SCRIPT, clientid: NULL, hostname: NULL, ifindex: 0, arp: "\0\0\0\0\0\0", }
Definition at line 92 of file ha.c.
Referenced by run_script(), send_discover(), send_renew(), send_selecting(), and udhcp().
int cur_mobiles = 0 |
Definition at line 133 of file ha.c.
Referenced by add_dhcp_mobile(), del_dhcp_mobile(), and find_dhcp_mobile().
struct dhcp_mobile dhcp_mobile_array[HA_DEFAULT_MAX_BINDINGS] |
Definition at line 131 of file ha.c.
Referenced by add_dhcp_mobile(), del_dhcp_mobile(), find_dhcp_mobile(), and udhcp().
int maxmobiles = HA_DEFAULT_MAX_BINDINGS |
char* opt_config |
int opt_foreground |