aboutsummaryrefslogtreecommitdiff
path: root/networking/udhcp/dhcpd.c
diff options
context:
space:
mode:
Diffstat (limited to 'networking/udhcp/dhcpd.c')
-rw-r--r--networking/udhcp/dhcpd.c183
1 files changed, 115 insertions, 68 deletions
diff --git a/networking/udhcp/dhcpd.c b/networking/udhcp/dhcpd.c
index 0c55fa5e4..058f86bca 100644
--- a/networking/udhcp/dhcpd.c
+++ b/networking/udhcp/dhcpd.c
@@ -48,14 +48,25 @@
48#define g_leases ((struct dyn_lease*)ptr_to_globals) 48#define g_leases ((struct dyn_lease*)ptr_to_globals)
49/* struct server_config_t server_config is in bb_common_bufsiz1 */ 49/* struct server_config_t server_config is in bb_common_bufsiz1 */
50 50
51struct static_lease {
52 struct static_lease *next;
53 uint32_t nip;
54 uint8_t mac[6];
55 uint8_t opt[1];
56};
57
51/* Takes the address of the pointer to the static_leases linked list, 58/* Takes the address of the pointer to the static_leases linked list,
52 * address to a 6 byte mac address, 59 * address to a 6 byte mac address,
53 * 4 byte IP address */ 60 * 4 byte IP address */
54static void add_static_lease(struct static_lease **st_lease_pp, 61static void add_static_lease(struct static_lease **st_lease_pp,
55 uint8_t *mac, 62 uint8_t *mac,
56 uint32_t nip) 63 uint32_t nip,
64 const char *opts)
57{ 65{
58 struct static_lease *st_lease; 66 struct static_lease *st_lease;
67 unsigned optlen;
68
69 optlen = (opts ? 1+1+strnlen(opts, 120) : 0);
59 70
60 /* Find the tail of the list */ 71 /* Find the tail of the list */
61 while ((st_lease = *st_lease_pp) != NULL) { 72 while ((st_lease = *st_lease_pp) != NULL) {
@@ -63,15 +74,34 @@ static void add_static_lease(struct static_lease **st_lease_pp,
63 } 74 }
64 75
65 /* Add new node */ 76 /* Add new node */
66 *st_lease_pp = st_lease = xzalloc(sizeof(*st_lease)); 77 *st_lease_pp = st_lease = xzalloc(sizeof(*st_lease) + optlen);
67 memcpy(st_lease->mac, mac, 6); 78 memcpy(st_lease->mac, mac, 6);
68 st_lease->nip = nip; 79 st_lease->nip = nip;
69 /*st_lease->next = NULL;*/ 80 /*st_lease->next = NULL;*/
81 if (optlen) {
82 st_lease->opt[OPT_CODE] = DHCP_HOST_NAME;
83 optlen -= 2;
84 st_lease->opt[OPT_LEN] = optlen;
85 memcpy(&st_lease->opt[OPT_DATA], opts, optlen);
86 }
87
88#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 2
89 /* Print out static leases just to check what's going on */
90 if (dhcp_verbose >= 2) {
91 bb_info_msg("static lease: mac:%02x:%02x:%02x:%02x:%02x:%02x nip:%x",
92 st_lease->mac[0], st_lease->mac[1], st_lease->mac[2],
93 st_lease->mac[3], st_lease->mac[4], st_lease->mac[5],
94 st_lease->nip
95 );
96 }
97#endif
70} 98}
71 99
72/* Find static lease IP by mac */ 100/* Find static lease IP by mac */
73static uint32_t get_static_nip_by_mac(struct static_lease *st_lease, void *mac) 101static uint32_t get_static_nip_by_mac(void *mac)
74{ 102{
103 struct static_lease *st_lease = server_config.static_leases;
104
75 while (st_lease) { 105 while (st_lease) {
76 if (memcmp(st_lease->mac, mac, 6) == 0) 106 if (memcmp(st_lease->mac, mac, 6) == 0)
77 return st_lease->nip; 107 return st_lease->nip;
@@ -81,8 +111,10 @@ static uint32_t get_static_nip_by_mac(struct static_lease *st_lease, void *mac)
81 return 0; 111 return 0;
82} 112}
83 113
84static int is_nip_reserved(struct static_lease *st_lease, uint32_t nip) 114static int is_nip_reserved_as_static(uint32_t nip)
85{ 115{
116 struct static_lease *st_lease = server_config.static_leases;
117
86 while (st_lease) { 118 while (st_lease) {
87 if (st_lease->nip == nip) 119 if (st_lease->nip == nip)
88 return 1; 120 return 1;
@@ -92,30 +124,6 @@ static int is_nip_reserved(struct static_lease *st_lease, uint32_t nip)
92 return 0; 124 return 0;
93} 125}
94 126
95#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 2
96/* Print out static leases just to check what's going on */
97/* Takes the address of the pointer to the static_leases linked list */
98static void log_static_leases(struct static_lease **st_lease_pp)
99{
100 struct static_lease *cur;
101
102 if (dhcp_verbose < 2)
103 return;
104
105 cur = *st_lease_pp;
106 while (cur) {
107 bb_error_msg("static lease: mac:%02x:%02x:%02x:%02x:%02x:%02x nip:%x",
108 cur->mac[0], cur->mac[1], cur->mac[2],
109 cur->mac[3], cur->mac[4], cur->mac[5],
110 cur->nip
111 );
112 cur = cur->next;
113 }
114}
115#else
116# define log_static_leases(st_lease_pp) ((void)0)
117#endif
118
119/* Find the oldest expired lease, NULL if there are no expired leases */ 127/* Find the oldest expired lease, NULL if there are no expired leases */
120static struct dyn_lease *oldest_expired_lease(void) 128static struct dyn_lease *oldest_expired_lease(void)
121{ 129{
@@ -242,7 +250,7 @@ static int nobody_responds_to_arp(uint32_t nip, const uint8_t *safe_mac, unsigne
242 return r; 250 return r;
243 251
244 temp.s_addr = nip; 252 temp.s_addr = nip;
245 bb_error_msg("%s belongs to someone, reserving it for %u seconds", 253 bb_info_msg("%s belongs to someone, reserving it for %u seconds",
246 inet_ntoa(temp), (unsigned)server_config.conflict_time); 254 inet_ntoa(temp), (unsigned)server_config.conflict_time);
247 add_lease(NULL, nip, server_config.conflict_time, NULL, 0); 255 add_lease(NULL, nip, server_config.conflict_time, NULL, 0);
248 return 0; 256 return 0;
@@ -288,7 +296,7 @@ static uint32_t find_free_or_expired_nip(const uint8_t *safe_mac, unsigned arppi
288 if (nip == server_config.server_nip) 296 if (nip == server_config.server_nip)
289 goto next_addr; 297 goto next_addr;
290 /* is this a static lease addr? */ 298 /* is this a static lease addr? */
291 if (is_nip_reserved(server_config.static_leases, nip)) 299 if (is_nip_reserved_as_static(nip))
292 goto next_addr; 300 goto next_addr;
293 301
294 lease = find_lease_by_nip(nip); 302 lease = find_lease_by_nip(nip);
@@ -340,6 +348,7 @@ static int FAST_FUNC read_staticlease(const char *const_line, void *arg)
340 char *line; 348 char *line;
341 char *mac_string; 349 char *mac_string;
342 char *ip_string; 350 char *ip_string;
351 char *opts;
343 struct ether_addr mac_bytes; /* it's "struct { uint8_t mac[6]; }" */ 352 struct ether_addr mac_bytes; /* it's "struct { uint8_t mac[6]; }" */
344 uint32_t nip; 353 uint32_t nip;
345 354
@@ -354,14 +363,16 @@ static int FAST_FUNC read_staticlease(const char *const_line, void *arg)
354 if (!ip_string || !udhcp_str2nip(ip_string, &nip)) 363 if (!ip_string || !udhcp_str2nip(ip_string, &nip))
355 return 0; 364 return 0;
356 365
357 add_static_lease(arg, (uint8_t*) &mac_bytes, nip); 366 opts = strtok_r(NULL, " \t", &line);
367 /* opts might be NULL, that's not an error */
358 368
359 log_static_leases(arg); 369 add_static_lease(arg, (uint8_t*) &mac_bytes, nip, opts);
360 370
361 return 1; 371 return 1;
362} 372}
363 373
364static int FAST_FUNC read_optset(const char *line, void *arg) { 374static int FAST_FUNC read_optset(const char *line, void *arg)
375{
365 return udhcp_str2optset(line, arg, 376 return udhcp_str2optset(line, arg,
366 dhcp_optflags, dhcp_option_strings, 377 dhcp_optflags, dhcp_option_strings,
367 /*dhcpv6:*/ 0 378 /*dhcpv6:*/ 0
@@ -518,13 +529,13 @@ static NOINLINE void read_leases(const char *file)
518 expires = 0; 529 expires = 0;
519 530
520 /* Check if there is a different static lease for this IP or MAC */ 531 /* Check if there is a different static lease for this IP or MAC */
521 static_nip = get_static_nip_by_mac(server_config.static_leases, lease.lease_mac); 532 static_nip = get_static_nip_by_mac(lease.lease_mac);
522 if (static_nip) { 533 if (static_nip) {
523 /* NB: we do not add lease even if static_nip == lease.lease_nip. 534 /* NB: we do not add lease even if static_nip == lease.lease_nip.
524 */ 535 */
525 continue; 536 continue;
526 } 537 }
527 if (is_nip_reserved(server_config.static_leases, lease.lease_nip)) 538 if (is_nip_reserved_as_static(lease.lease_nip))
528 continue; 539 continue;
529 540
530 /* NB: add_lease takes "relative time", IOW, 541 /* NB: add_lease takes "relative time", IOW,
@@ -602,6 +613,15 @@ static void send_packet(struct dhcp_packet *dhcp_pkt, int force_broadcast)
602 send_packet_to_client(dhcp_pkt, force_broadcast); 613 send_packet_to_client(dhcp_pkt, force_broadcast);
603} 614}
604 615
616static void send_packet_verbose(struct dhcp_packet *dhcp_pkt, const char *fmt)
617{
618 struct in_addr addr;
619 addr.s_addr = dhcp_pkt->yiaddr;
620 bb_info_msg(fmt, inet_ntoa(addr));
621 /* send_packet emits error message itself if it detects failure */
622 send_packet(dhcp_pkt, /*force_bcast:*/ 0);
623}
624
605static void init_packet(struct dhcp_packet *packet, struct dhcp_packet *oldpacket, char type) 625static void init_packet(struct dhcp_packet *packet, struct dhcp_packet *oldpacket, char type)
606{ 626{
607 /* Sets op, htype, hlen, cookie fields 627 /* Sets op, htype, hlen, cookie fields
@@ -621,14 +641,49 @@ static void init_packet(struct dhcp_packet *packet, struct dhcp_packet *oldpacke
621 */ 641 */
622static void add_server_options(struct dhcp_packet *packet) 642static void add_server_options(struct dhcp_packet *packet)
623{ 643{
624 struct option_set *curr = server_config.options; 644 struct option_set *config_opts;
645 uint8_t *client_hostname_opt;
646
647 client_hostname_opt = NULL;
648 if (packet->yiaddr) { /* if we aren't from send_inform()... */
649 struct static_lease *st_lease = server_config.static_leases;
650 while (st_lease) {
651 if (st_lease->nip == packet->yiaddr) {
652 if (st_lease->opt[0] != 0)
653 client_hostname_opt = st_lease->opt;
654 break;
655 }
656 st_lease = st_lease->next;
657 }
658 }
625 659
626 while (curr) { 660 config_opts = server_config.options;
627 if (curr->data[OPT_CODE] != DHCP_LEASE_TIME) 661 while (config_opts) {
628 udhcp_add_binary_option(packet, curr->data); 662 if (config_opts->data[OPT_CODE] != DHCP_LEASE_TIME) {
629 curr = curr->next; 663 /* ^^^^
664 * DHCP_LEASE_TIME is already filled, or in case of
665 * send_inform(), should not be filled at all.
666 */
667 if (config_opts->data[OPT_CODE] != DHCP_HOST_NAME
668 || !client_hostname_opt
669 ) {
670 /* Why "!client_hostname_opt":
671 * add hostname only if client has no hostname
672 * on its static lease line.
673 * (Not that "opt hostname HOST"
674 * makes much sense in udhcpd.conf,
675 * that'd give all clients the same hostname,
676 * but it's a valid configuration).
677 */
678 udhcp_add_binary_option(packet, config_opts->data);
679 }
680 }
681 config_opts = config_opts->next;
630 } 682 }
631 683
684 if (client_hostname_opt)
685 udhcp_add_binary_option(packet, client_hostname_opt);
686
632 packet->siaddr_nip = server_config.siaddr_nip; 687 packet->siaddr_nip = server_config.siaddr_nip;
633 688
634 if (server_config.sname) 689 if (server_config.sname)
@@ -657,12 +712,11 @@ static uint32_t select_lease_time(struct dhcp_packet *packet)
657static NOINLINE void send_offer(struct dhcp_packet *oldpacket, 712static NOINLINE void send_offer(struct dhcp_packet *oldpacket,
658 uint32_t static_lease_nip, 713 uint32_t static_lease_nip,
659 struct dyn_lease *lease, 714 struct dyn_lease *lease,
660 uint8_t *requested_ip_opt, 715 uint32_t requested_nip,
661 unsigned arpping_ms) 716 unsigned arpping_ms)
662{ 717{
663 struct dhcp_packet packet; 718 struct dhcp_packet packet;
664 uint32_t lease_time_sec; 719 uint32_t lease_time_sec;
665 struct in_addr addr;
666 720
667 init_packet(&packet, oldpacket, DHCPOFFER); 721 init_packet(&packet, oldpacket, DHCPOFFER);
668 722
@@ -671,7 +725,6 @@ static NOINLINE void send_offer(struct dhcp_packet *oldpacket,
671 /* Else: */ 725 /* Else: */
672 if (!static_lease_nip) { 726 if (!static_lease_nip) {
673 /* We have no static lease for client's chaddr */ 727 /* We have no static lease for client's chaddr */
674 uint32_t req_nip;
675 const char *p_host_name; 728 const char *p_host_name;
676 729
677 if (lease) { 730 if (lease) {
@@ -682,18 +735,16 @@ static NOINLINE void send_offer(struct dhcp_packet *oldpacket,
682 packet.yiaddr = lease->lease_nip; 735 packet.yiaddr = lease->lease_nip;
683 } 736 }
684 /* Or: if client has requested an IP */ 737 /* Or: if client has requested an IP */
685 else if (requested_ip_opt != NULL 738 else if (requested_nip != 0
686 /* (read IP) */
687 && (move_from_unaligned32(req_nip, requested_ip_opt), 1)
688 /* and the IP is in the lease range */ 739 /* and the IP is in the lease range */
689 && ntohl(req_nip) >= server_config.start_ip 740 && ntohl(requested_nip) >= server_config.start_ip
690 && ntohl(req_nip) <= server_config.end_ip 741 && ntohl(requested_nip) <= server_config.end_ip
691 /* and */ 742 /* and */
692 && ( !(lease = find_lease_by_nip(req_nip)) /* is not already taken */ 743 && ( !(lease = find_lease_by_nip(requested_nip)) /* is not already taken */
693 || is_expired_lease(lease) /* or is taken, but expired */ 744 || is_expired_lease(lease) /* or is taken, but expired */
694 ) 745 )
695 ) { 746 ) {
696 packet.yiaddr = req_nip; 747 packet.yiaddr = requested_nip;
697 } 748 }
698 else { 749 else {
699 /* Otherwise, find a free IP */ 750 /* Otherwise, find a free IP */
@@ -721,10 +772,8 @@ static NOINLINE void send_offer(struct dhcp_packet *oldpacket,
721 udhcp_add_simple_option(&packet, DHCP_LEASE_TIME, htonl(lease_time_sec)); 772 udhcp_add_simple_option(&packet, DHCP_LEASE_TIME, htonl(lease_time_sec));
722 add_server_options(&packet); 773 add_server_options(&packet);
723 774
724 addr.s_addr = packet.yiaddr;
725 bb_error_msg("sending OFFER of %s", inet_ntoa(addr));
726 /* send_packet emits error message itself if it detects failure */ 775 /* send_packet emits error message itself if it detects failure */
727 send_packet(&packet, /*force_bcast:*/ 0); 776 send_packet_verbose(&packet, "sending OFFER to %s");
728} 777}
729 778
730/* NOINLINE: limit stack usage in caller */ 779/* NOINLINE: limit stack usage in caller */
@@ -743,7 +792,6 @@ static NOINLINE void send_ACK(struct dhcp_packet *oldpacket, uint32_t yiaddr)
743{ 792{
744 struct dhcp_packet packet; 793 struct dhcp_packet packet;
745 uint32_t lease_time_sec; 794 uint32_t lease_time_sec;
746 struct in_addr addr;
747 const char *p_host_name; 795 const char *p_host_name;
748 796
749 init_packet(&packet, oldpacket, DHCPACK); 797 init_packet(&packet, oldpacket, DHCPACK);
@@ -751,12 +799,9 @@ static NOINLINE void send_ACK(struct dhcp_packet *oldpacket, uint32_t yiaddr)
751 799
752 lease_time_sec = select_lease_time(oldpacket); 800 lease_time_sec = select_lease_time(oldpacket);
753 udhcp_add_simple_option(&packet, DHCP_LEASE_TIME, htonl(lease_time_sec)); 801 udhcp_add_simple_option(&packet, DHCP_LEASE_TIME, htonl(lease_time_sec));
754
755 add_server_options(&packet); 802 add_server_options(&packet);
756 803
757 addr.s_addr = yiaddr; 804 send_packet_verbose(&packet, "sending ACK to %s");
758 bb_error_msg("sending ACK to %s", inet_ntoa(addr));
759 send_packet(&packet, /*force_bcast:*/ 0);
760 805
761 p_host_name = (const char*) udhcp_get_option(oldpacket, DHCP_HOST_NAME); 806 p_host_name = (const char*) udhcp_get_option(oldpacket, DHCP_HOST_NAME);
762 add_lease(packet.chaddr, packet.yiaddr, 807 add_lease(packet.chaddr, packet.yiaddr,
@@ -796,6 +841,7 @@ static NOINLINE void send_inform(struct dhcp_packet *oldpacket)
796 add_server_options(&packet); 841 add_server_options(&packet);
797 842
798 send_packet(&packet, /*force_bcast:*/ 0); 843 send_packet(&packet, /*force_bcast:*/ 0);
844 // or maybe? send_packet_verbose(&packet, "sending ACK to %s");
799} 845}
800 846
801int udhcpd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 847int udhcpd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
@@ -865,7 +911,7 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv)
865 write_pidfile(server_config.pidfile); 911 write_pidfile(server_config.pidfile);
866 /* if (!..) bb_perror_msg("can't create pidfile %s", pidfile); */ 912 /* if (!..) bb_perror_msg("can't create pidfile %s", pidfile); */
867 913
868 bb_error_msg("started, v"BB_VER); 914 bb_info_msg("started, v"BB_VER);
869 915
870 option = udhcp_find_option(server_config.options, DHCP_LEASE_TIME); 916 option = udhcp_find_option(server_config.options, DHCP_LEASE_TIME);
871 server_config.max_lease_sec = DEFAULT_LEASE_TIME; 917 server_config.max_lease_sec = DEFAULT_LEASE_TIME;
@@ -908,7 +954,7 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv)
908 int tv; 954 int tv;
909 uint8_t *server_id_opt; 955 uint8_t *server_id_opt;
910 uint8_t *requested_ip_opt; 956 uint8_t *requested_ip_opt;
911 uint32_t requested_nip = requested_nip; /* for compiler */ 957 uint32_t requested_nip;
912 uint32_t static_lease_nip; 958 uint32_t static_lease_nip;
913 struct dyn_lease *lease, fake_lease; 959 struct dyn_lease *lease, fake_lease;
914 960
@@ -944,12 +990,12 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv)
944 990
945 if (pfds[0].revents) switch (udhcp_sp_read()) { 991 if (pfds[0].revents) switch (udhcp_sp_read()) {
946 case SIGUSR1: 992 case SIGUSR1:
947 bb_error_msg("received %s", "SIGUSR1"); 993 bb_info_msg("received %s", "SIGUSR1");
948 write_leases(); 994 write_leases();
949 /* why not just reset the timeout, eh */ 995 /* why not just reset the timeout, eh */
950 goto continue_with_autotime; 996 goto continue_with_autotime;
951 case SIGTERM: 997 case SIGTERM:
952 bb_error_msg("received %s", "SIGTERM"); 998 bb_info_msg("received %s", "SIGTERM");
953 write_leases(); 999 write_leases();
954 goto ret0; 1000 goto ret0;
955 } 1001 }
@@ -973,16 +1019,16 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv)
973 continue; 1019 continue;
974 } 1020 }
975 if (packet.hlen != 6) { 1021 if (packet.hlen != 6) {
976 bb_error_msg("MAC length != 6, ignoring packet"); 1022 bb_info_msg("MAC length != 6, ignoring packet");
977 continue; 1023 continue;
978 } 1024 }
979 if (packet.op != BOOTREQUEST) { 1025 if (packet.op != BOOTREQUEST) {
980 bb_error_msg("not a REQUEST, ignoring packet"); 1026 bb_info_msg("not a REQUEST, ignoring packet");
981 continue; 1027 continue;
982 } 1028 }
983 state = udhcp_get_option(&packet, DHCP_MESSAGE_TYPE); 1029 state = udhcp_get_option(&packet, DHCP_MESSAGE_TYPE);
984 if (state == NULL || state[0] < DHCP_MINTYPE || state[0] > DHCP_MAXTYPE) { 1030 if (state == NULL || state[0] < DHCP_MINTYPE || state[0] > DHCP_MAXTYPE) {
985 bb_error_msg("no or bad message type option, ignoring packet"); 1031 bb_info_msg("no or bad message type option, ignoring packet");
986 continue; 1032 continue;
987 } 1033 }
988 1034
@@ -999,9 +1045,9 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv)
999 } 1045 }
1000 1046
1001 /* Look for a static/dynamic lease */ 1047 /* Look for a static/dynamic lease */
1002 static_lease_nip = get_static_nip_by_mac(server_config.static_leases, &packet.chaddr); 1048 static_lease_nip = get_static_nip_by_mac(&packet.chaddr);
1003 if (static_lease_nip) { 1049 if (static_lease_nip) {
1004 bb_error_msg("found static lease: %x", static_lease_nip); 1050 bb_info_msg("found static lease: %x", static_lease_nip);
1005 memcpy(&fake_lease.lease_mac, &packet.chaddr, 6); 1051 memcpy(&fake_lease.lease_mac, &packet.chaddr, 6);
1006 fake_lease.lease_nip = static_lease_nip; 1052 fake_lease.lease_nip = static_lease_nip;
1007 fake_lease.expires = 0; 1053 fake_lease.expires = 0;
@@ -1011,6 +1057,7 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv)
1011 } 1057 }
1012 1058
1013 /* Get REQUESTED_IP if present */ 1059 /* Get REQUESTED_IP if present */
1060 requested_nip = 0;
1014 requested_ip_opt = udhcp_get_option32(&packet, DHCP_REQUESTED_IP); 1061 requested_ip_opt = udhcp_get_option32(&packet, DHCP_REQUESTED_IP);
1015 if (requested_ip_opt) { 1062 if (requested_ip_opt) {
1016 move_from_unaligned32(requested_nip, requested_ip_opt); 1063 move_from_unaligned32(requested_nip, requested_ip_opt);
@@ -1021,7 +1068,7 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv)
1021 case DHCPDISCOVER: 1068 case DHCPDISCOVER:
1022 log1("received %s", "DISCOVER"); 1069 log1("received %s", "DISCOVER");
1023 1070
1024 send_offer(&packet, static_lease_nip, lease, requested_ip_opt, arpping_ms); 1071 send_offer(&packet, static_lease_nip, lease, requested_nip, arpping_ms);
1025 break; 1072 break;
1026 1073
1027 case DHCPREQUEST: 1074 case DHCPREQUEST: