aboutsummaryrefslogtreecommitdiff
path: root/networking/udhcp/dhcpc.c
diff options
context:
space:
mode:
Diffstat (limited to 'networking/udhcp/dhcpc.c')
-rw-r--r--networking/udhcp/dhcpc.c131
1 files changed, 60 insertions, 71 deletions
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c
index 4e3d8ca5e..331f13a8c 100644
--- a/networking/udhcp/dhcpc.c
+++ b/networking/udhcp/dhcpc.c
@@ -605,7 +605,7 @@ static void init_packet(struct dhcp_packet *packet, char type)
605 /* Fill in: op, htype, hlen, cookie fields; message type option: */ 605 /* Fill in: op, htype, hlen, cookie fields; message type option: */
606 udhcp_init_header(packet, type); 606 udhcp_init_header(packet, type);
607 607
608 packet->xid = random_xid(); 608 packet->xid = client_data.xid;
609 609
610 client_data.last_secs = monotonic_sec(); 610 client_data.last_secs = monotonic_sec();
611 if (client_data.first_secs == 0) 611 if (client_data.first_secs == 0)
@@ -663,6 +663,24 @@ static void add_client_options(struct dhcp_packet *packet)
663 // ...add (DHCP_VENDOR, "udhcp "BB_VER) opt... 663 // ...add (DHCP_VENDOR, "udhcp "BB_VER) opt...
664} 664}
665 665
666static void add_serverid_and_clientid_options(struct dhcp_packet *packet, uint32_t server)
667{
668 struct option_set *ci;
669
670 udhcp_add_simple_option(packet, DHCP_SERVER_ID, server);
671
672 /* RFC 2131 section 2:
673 * If the client uses a 'client identifier' in one message,
674 * it MUST use that same identifier in all subsequent messages.
675 * section 3.1.6:
676 * If the client used a 'client identifier' when it obtained the lease,
677 * it MUST use the same 'client identifier' in the DHCPRELEASE message.
678 */
679 ci = udhcp_find_option(client_data.options, DHCP_CLIENT_ID);
680 if (ci)
681 udhcp_add_binary_option(packet, ci->data);
682}
683
666/* RFC 2131 684/* RFC 2131
667 * 4.4.4 Use of broadcast and unicast 685 * 4.4.4 Use of broadcast and unicast
668 * 686 *
@@ -701,17 +719,15 @@ static int bcast_or_ucast(struct dhcp_packet *packet, uint32_t ciaddr, uint32_t
701 719
702/* Broadcast a DHCP discover packet to the network, with an optionally requested IP */ 720/* Broadcast a DHCP discover packet to the network, with an optionally requested IP */
703/* NOINLINE: limit stack usage in caller */ 721/* NOINLINE: limit stack usage in caller */
704static NOINLINE int send_discover(uint32_t xid, uint32_t requested) 722static NOINLINE int send_discover(uint32_t requested)
705{ 723{
706 struct dhcp_packet packet; 724 struct dhcp_packet packet;
707 725
708 /* Fill in: op, htype, hlen, cookie, chaddr fields, 726 /* Fill in: op, htype, hlen, cookie, chaddr fields,
709 * random xid field (we override it below), 727 * xid field, message type option:
710 * message type option:
711 */ 728 */
712 init_packet(&packet, DHCPDISCOVER); 729 init_packet(&packet, DHCPDISCOVER);
713 730
714 packet.xid = xid;
715 if (requested) 731 if (requested)
716 udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested); 732 udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested);
717 733
@@ -729,7 +745,7 @@ static NOINLINE int send_discover(uint32_t xid, uint32_t requested)
729 * "The client _broadcasts_ a DHCPREQUEST message..." 745 * "The client _broadcasts_ a DHCPREQUEST message..."
730 */ 746 */
731/* NOINLINE: limit stack usage in caller */ 747/* NOINLINE: limit stack usage in caller */
732static NOINLINE int send_select(uint32_t xid, uint32_t server, uint32_t requested) 748static NOINLINE int send_select(uint32_t server, uint32_t requested)
733{ 749{
734 struct dhcp_packet packet; 750 struct dhcp_packet packet;
735 struct in_addr temp_addr; 751 struct in_addr temp_addr;
@@ -748,18 +764,16 @@ static NOINLINE int send_select(uint32_t xid, uint32_t server, uint32_t requeste
748 * include that list in all subsequent messages. 764 * include that list in all subsequent messages.
749 */ 765 */
750 /* Fill in: op, htype, hlen, cookie, chaddr fields, 766 /* Fill in: op, htype, hlen, cookie, chaddr fields,
751 * random xid field (we override it below), 767 * xid field, message type option:
752 * message type option:
753 */ 768 */
754 init_packet(&packet, DHCPREQUEST); 769 init_packet(&packet, DHCPREQUEST);
755 770
756 packet.xid = xid;
757 udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested); 771 udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested);
758 772
759 udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server); 773 udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server);
760 774
761 /* Add options: maxsize, 775 /* Add options: maxsize,
762 * "param req" option according to -O, and options specified with -x 776 * "param req" option according to -O, options specified with -x
763 */ 777 */
764 add_client_options(&packet); 778 add_client_options(&packet);
765 779
@@ -775,7 +789,7 @@ static NOINLINE int send_select(uint32_t xid, uint32_t server, uint32_t requeste
775 789
776/* Unicast or broadcast a DHCP renew message */ 790/* Unicast or broadcast a DHCP renew message */
777/* NOINLINE: limit stack usage in caller */ 791/* NOINLINE: limit stack usage in caller */
778static NOINLINE int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr) 792static NOINLINE int send_renew(uint32_t server, uint32_t ciaddr)
779{ 793{
780 struct dhcp_packet packet; 794 struct dhcp_packet packet;
781 795
@@ -794,16 +808,14 @@ static NOINLINE int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr)
794 * replying to the client. 808 * replying to the client.
795 */ 809 */
796 /* Fill in: op, htype, hlen, cookie, chaddr fields, 810 /* Fill in: op, htype, hlen, cookie, chaddr fields,
797 * random xid field (we override it below), 811 * xid field, message type option:
798 * message type option:
799 */ 812 */
800 init_packet(&packet, DHCPREQUEST); 813 init_packet(&packet, DHCPREQUEST);
801 814
802 packet.xid = xid;
803 packet.ciaddr = ciaddr; 815 packet.ciaddr = ciaddr;
804 816
805 /* Add options: maxsize, 817 /* Add options: maxsize,
806 * "param req" option according to -O, and options specified with -x 818 * "param req" option according to -O, options specified with -x
807 */ 819 */
808 add_client_options(&packet); 820 add_client_options(&packet);
809 821
@@ -821,7 +833,7 @@ static NOINLINE int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr)
821#if ENABLE_FEATURE_UDHCPC_ARPING 833#if ENABLE_FEATURE_UDHCPC_ARPING
822/* Broadcast a DHCP decline message */ 834/* Broadcast a DHCP decline message */
823/* NOINLINE: limit stack usage in caller */ 835/* NOINLINE: limit stack usage in caller */
824static NOINLINE int send_decline(/*uint32_t xid,*/ uint32_t server, uint32_t requested) 836static NOINLINE int send_decline(uint32_t server, uint32_t requested)
825{ 837{
826 struct dhcp_packet packet; 838 struct dhcp_packet packet;
827 839
@@ -830,20 +842,10 @@ static NOINLINE int send_decline(/*uint32_t xid,*/ uint32_t server, uint32_t req
830 */ 842 */
831 init_packet(&packet, DHCPDECLINE); 843 init_packet(&packet, DHCPDECLINE);
832 844
833#if 0
834 /* RFC 2131 says DHCPDECLINE's xid is randomly selected by client,
835 * but in case the server is buggy and wants DHCPDECLINE's xid
836 * to match the xid which started entire handshake,
837 * we use the same xid we used in initial DHCPDISCOVER:
838 */
839 packet.xid = xid;
840#endif
841 /* DHCPDECLINE uses "requested ip", not ciaddr, to store offered IP */ 845 /* DHCPDECLINE uses "requested ip", not ciaddr, to store offered IP */
842 udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested); 846 udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested);
843 847
844 udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server); 848 add_serverid_and_clientid_options(&packet, server);
845
846//TODO: add client-id opt?
847 849
848 bb_simple_info_msg("broadcasting decline"); 850 bb_simple_info_msg("broadcasting decline");
849 return raw_bcast_from_client_data_ifindex(&packet, INADDR_ANY); 851 return raw_bcast_from_client_data_ifindex(&packet, INADDR_ANY);
@@ -856,7 +858,6 @@ ALWAYS_INLINE /* one caller, help compiler to use this fact */
856int send_release(uint32_t server, uint32_t ciaddr) 858int send_release(uint32_t server, uint32_t ciaddr)
857{ 859{
858 struct dhcp_packet packet; 860 struct dhcp_packet packet;
859 struct option_set *ci;
860 861
861 /* Fill in: op, htype, hlen, cookie, chaddr, random xid fields, 862 /* Fill in: op, htype, hlen, cookie, chaddr, random xid fields,
862 * message type option: 863 * message type option:
@@ -866,15 +867,7 @@ int send_release(uint32_t server, uint32_t ciaddr)
866 /* DHCPRELEASE uses ciaddr, not "requested ip", to store IP being released */ 867 /* DHCPRELEASE uses ciaddr, not "requested ip", to store IP being released */
867 packet.ciaddr = ciaddr; 868 packet.ciaddr = ciaddr;
868 869
869 udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server); 870 add_serverid_and_clientid_options(&packet, server);
870
871 /* RFC 2131 section 3.1.6:
872 * If the client used a 'client identifier' when it obtained the lease,
873 * it MUST use the same 'client identifier' in the DHCPRELEASE message.
874 */
875 ci = udhcp_find_option(client_data.options, DHCP_CLIENT_ID);
876 if (ci)
877 udhcp_add_binary_option(&packet, ci->data);
878 871
879 bb_info_msg("sending %s", "release"); 872 bb_info_msg("sending %s", "release");
880 /* Note: normally we unicast here since "server" is not zero. 873 /* Note: normally we unicast here since "server" is not zero.
@@ -1120,7 +1113,7 @@ static void change_listen_mode(int new_mode)
1120 /* else LISTEN_NONE: client_data.sockfd stays closed */ 1113 /* else LISTEN_NONE: client_data.sockfd stays closed */
1121} 1114}
1122 1115
1123static void perform_release(uint32_t server_addr, uint32_t requested_ip) 1116static void perform_release(uint32_t server_id, uint32_t requested_ip)
1124{ 1117{
1125 char buffer[sizeof("255.255.255.255")]; 1118 char buffer[sizeof("255.255.255.255")];
1126 struct in_addr temp_addr; 1119 struct in_addr temp_addr;
@@ -1133,12 +1126,13 @@ static void perform_release(uint32_t server_addr, uint32_t requested_ip)
1133 || client_data.state == REBINDING 1126 || client_data.state == REBINDING
1134 || client_data.state == RENEW_REQUESTED 1127 || client_data.state == RENEW_REQUESTED
1135 ) { 1128 ) {
1136 temp_addr.s_addr = server_addr; 1129 temp_addr.s_addr = server_id;
1137 strcpy(buffer, inet_ntoa(temp_addr)); 1130 strcpy(buffer, inet_ntoa(temp_addr));
1138 temp_addr.s_addr = requested_ip; 1131 temp_addr.s_addr = requested_ip;
1139 bb_info_msg("unicasting a release of %s to %s", 1132 bb_info_msg("unicasting a release of %s to %s",
1140 inet_ntoa(temp_addr), buffer); 1133 inet_ntoa(temp_addr), buffer);
1141 send_release(server_addr, requested_ip); /* unicast */ 1134 client_data.xid = random_xid(); //TODO: can omit?
1135 send_release(server_id, requested_ip); /* unicast */
1142 } 1136 }
1143 bb_simple_info_msg("entering released state"); 1137 bb_simple_info_msg("entering released state");
1144/* 1138/*
@@ -1167,7 +1161,7 @@ static void client_background(void)
1167//usage:# define IF_UDHCP_VERBOSE(...) 1161//usage:# define IF_UDHCP_VERBOSE(...)
1168//usage:#endif 1162//usage:#endif
1169//usage:#define udhcpc_trivial_usage 1163//usage:#define udhcpc_trivial_usage
1170//usage: "[-fbq"IF_UDHCP_VERBOSE("v")"RB]"IF_FEATURE_UDHCPC_ARPING(" [-a[MSEC]]")" [-t N] [-T SEC] [-A SEC/-n]\n" 1164//usage: "[-fbq"IF_UDHCP_VERBOSE("v")"RB]"IF_FEATURE_UDHCPC_ARPING(" [-a[MSEC]]")" [-t N] [-T SEC] [-A SEC|-n]\n"
1171//usage: " [-i IFACE]"IF_FEATURE_UDHCP_PORT(" [-P PORT]")" [-s PROG] [-p PIDFILE]\n" 1165//usage: " [-i IFACE]"IF_FEATURE_UDHCP_PORT(" [-P PORT]")" [-s PROG] [-p PIDFILE]\n"
1172//usage: " [-oC] [-r IP] [-V VENDOR] [-F NAME] [-x OPT:VAL]... [-O OPT]..." 1166//usage: " [-oC] [-r IP] [-V VENDOR] [-F NAME] [-x OPT:VAL]... [-O OPT]..."
1173//usage:#define udhcpc_full_usage "\n" 1167//usage:#define udhcpc_full_usage "\n"
@@ -1224,9 +1218,8 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1224 int tryagain_timeout = 20; 1218 int tryagain_timeout = 20;
1225 int discover_timeout = 3; 1219 int discover_timeout = 3;
1226 int discover_retries = 3; 1220 int discover_retries = 3;
1227 uint32_t server_addr = server_addr; /* for compiler */ 1221 uint32_t server_id = server_id; /* for compiler */
1228 uint32_t requested_ip = 0; 1222 uint32_t requested_ip = 0;
1229 uint32_t xid = xid; /* for compiler */
1230 int packet_num; 1223 int packet_num;
1231 int timeout; /* must be signed */ 1224 int timeout; /* must be signed */
1232 int lease_remaining; /* must be signed */ 1225 int lease_remaining; /* must be signed */
@@ -1291,7 +1284,8 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1291 memcpy(p + OPT_DATA + 3, str_F, len); /* do not store NUL byte */ 1284 memcpy(p + OPT_DATA + 3, str_F, len); /* do not store NUL byte */
1292 } 1285 }
1293 if (opt & OPT_r) 1286 if (opt & OPT_r)
1294 requested_ip = inet_addr(str_r); 1287 if (!inet_aton(str_r, (void*)&requested_ip))
1288 bb_show_usage();
1295#if ENABLE_FEATURE_UDHCP_PORT 1289#if ENABLE_FEATURE_UDHCP_PORT
1296 if (opt & OPT_P) { 1290 if (opt & OPT_P) {
1297 CLIENT_PORT = xatou16(str_P); 1291 CLIENT_PORT = xatou16(str_P);
@@ -1451,10 +1445,10 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1451 if (!discover_retries || packet_num < discover_retries) { 1445 if (!discover_retries || packet_num < discover_retries) {
1452 if (packet_num == 0) { 1446 if (packet_num == 0) {
1453 change_listen_mode(LISTEN_RAW); 1447 change_listen_mode(LISTEN_RAW);
1454 xid = random_xid(); 1448 client_data.xid = random_xid();
1455 } 1449 }
1456 /* broadcast */ 1450 /* broadcast */
1457 send_discover(xid, requested_ip); 1451 send_discover(requested_ip);
1458 timeout = discover_timeout; 1452 timeout = discover_timeout;
1459 packet_num++; 1453 packet_num++;
1460 continue; 1454 continue;
@@ -1488,7 +1482,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1488 case REQUESTING: 1482 case REQUESTING:
1489 if (packet_num < 3) { 1483 if (packet_num < 3) {
1490 /* send broadcast select packet */ 1484 /* send broadcast select packet */
1491 send_select(xid, server_addr, requested_ip); 1485 send_select(server_id, requested_ip);
1492 timeout = discover_timeout; 1486 timeout = discover_timeout;
1493 packet_num++; 1487 packet_num++;
1494 continue; 1488 continue;
@@ -1519,7 +1513,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1519 * Anyway, it does recover by eventually failing through 1513 * Anyway, it does recover by eventually failing through
1520 * into INIT_SELECTING state. 1514 * into INIT_SELECTING state.
1521 */ 1515 */
1522 if (send_renew(xid, server_addr, requested_ip) >= 0) { 1516 if (send_renew(server_id, requested_ip) >= 0) {
1523 timeout = discover_timeout; 1517 timeout = discover_timeout;
1524 packet_num++; 1518 packet_num++;
1525 continue; 1519 continue;
@@ -1548,7 +1542,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1548 * try to find DHCP server using broadcast */ 1542 * try to find DHCP server using broadcast */
1549 if (lease_remaining > 0 && packet_num < 3) { 1543 if (lease_remaining > 0 && packet_num < 3) {
1550 /* send a broadcast renew request */ 1544 /* send a broadcast renew request */
1551 send_renew(xid, 0 /*INADDR_ANY*/, requested_ip); 1545 send_renew(0 /*INADDR_ANY*/, requested_ip);
1552 timeout = discover_timeout; 1546 timeout = discover_timeout;
1553 packet_num++; 1547 packet_num++;
1554 continue; 1548 continue;
@@ -1610,7 +1604,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1610 timeout = 0; 1604 timeout = 0;
1611 continue; 1605 continue;
1612 case SIGUSR2: 1606 case SIGUSR2:
1613 perform_release(server_addr, requested_ip); 1607 perform_release(server_id, requested_ip);
1614 /* ^^^ switches to LISTEN_NONE */ 1608 /* ^^^ switches to LISTEN_NONE */
1615 timeout = INT_MAX; 1609 timeout = INT_MAX;
1616 continue; 1610 continue;
@@ -1641,9 +1635,9 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1641 continue; 1635 continue;
1642 } 1636 }
1643 1637
1644 if (packet.xid != xid) { 1638 if (packet.xid != client_data.xid) {
1645 log1("xid %x (our is %x)%s", 1639 log1("xid %x (our is %x)%s",
1646 (unsigned)packet.xid, (unsigned)xid, 1640 (unsigned)packet.xid, (unsigned)client_data.xid,
1647 ", ignoring packet" 1641 ", ignoring packet"
1648 ); 1642 );
1649 continue; 1643 continue;
@@ -1695,13 +1689,13 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1695 * They either supply DHCP_SERVER_ID of 0.0.0.0 or don't supply it at all. 1689 * They either supply DHCP_SERVER_ID of 0.0.0.0 or don't supply it at all.
1696 * They say ISC DHCP client supports this case. 1690 * They say ISC DHCP client supports this case.
1697 */ 1691 */
1698 server_addr = 0; 1692 server_id = 0;
1699 temp = udhcp_get_option32(&packet, DHCP_SERVER_ID); 1693 temp = udhcp_get_option32(&packet, DHCP_SERVER_ID);
1700 if (!temp) { 1694 if (!temp) {
1701 bb_simple_info_msg("no server ID, using 0.0.0.0"); 1695 bb_simple_info_msg("no server ID, using 0.0.0.0");
1702 } else { 1696 } else {
1703 /* it IS unaligned sometimes, don't "optimize" */ 1697 /* it IS unaligned sometimes, don't "optimize" */
1704 move_from_unaligned32(server_addr, temp); 1698 move_from_unaligned32(server_id, temp);
1705 } 1699 }
1706 /*xid = packet.xid; - already is */ 1700 /*xid = packet.xid; - already is */
1707 temp_addr.s_addr = requested_ip = packet.yiaddr; 1701 temp_addr.s_addr = requested_ip = packet.yiaddr;
@@ -1725,7 +1719,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1725 1719
1726 change_listen_mode(LISTEN_NONE); 1720 change_listen_mode(LISTEN_NONE);
1727 1721
1728 temp_addr.s_addr = server_addr; 1722 temp_addr.s_addr = server_id;
1729 strcpy(server_str, inet_ntoa(temp_addr)); 1723 strcpy(server_str, inet_ntoa(temp_addr));
1730 temp_addr.s_addr = packet.yiaddr; 1724 temp_addr.s_addr = packet.yiaddr;
1731 1725
@@ -1772,7 +1766,8 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1772 ) { 1766 ) {
1773 bb_simple_info_msg("offered address is in use " 1767 bb_simple_info_msg("offered address is in use "
1774 "(got ARP reply), declining"); 1768 "(got ARP reply), declining");
1775 send_decline(/*xid,*/ server_addr, packet.yiaddr); 1769 client_data.xid = random_xid(); //TODO: can omit?
1770 send_decline(server_id, packet.yiaddr);
1776 1771
1777 if (client_data.state != REQUESTING) 1772 if (client_data.state != REQUESTING)
1778 d4_run_script_deconfig(); 1773 d4_run_script_deconfig();
@@ -1807,7 +1802,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1807 timeout = (unsigned)lease_remaining / 2; 1802 timeout = (unsigned)lease_remaining / 2;
1808 client_data.state = BOUND; 1803 client_data.state = BOUND;
1809 /* make future renew packets use different xid */ 1804 /* make future renew packets use different xid */
1810 /* xid = random_xid(); ...but why bother? */ 1805 /* client_data.xid = random_xid(); ...but why bother? */
1811 packet_num = 0; 1806 packet_num = 0;
1812 continue; /* back to main loop */ 1807 continue; /* back to main loop */
1813 } 1808 }
@@ -1816,20 +1811,14 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1816 * "wrong" server can reply first, with a NAK. 1811 * "wrong" server can reply first, with a NAK.
1817 * Do not interpret it as a NAK from "our" server. 1812 * Do not interpret it as a NAK from "our" server.
1818 */ 1813 */
1819 if (server_addr != 0) { 1814 uint32_t svid = 0; /* we treat no server id as 0.0.0.0 */
1820 uint32_t svid; 1815 uint8_t *temp = udhcp_get_option32(&packet, DHCP_SERVER_ID);
1821 uint8_t *temp; 1816 if (temp)
1822
1823 temp = udhcp_get_option32(&packet, DHCP_SERVER_ID);
1824 if (!temp) {
1825 non_matching_svid:
1826 log1("received DHCP NAK with wrong"
1827 " server ID%s", ", ignoring packet");
1828 continue;
1829 }
1830 move_from_unaligned32(svid, temp); 1817 move_from_unaligned32(svid, temp);
1831 if (svid != server_addr) 1818 if (svid != server_id) {
1832 goto non_matching_svid; 1819 log1("received DHCP NAK with wrong"
1820 " server ID%s", ", ignoring packet");
1821 continue;
1833 } 1822 }
1834 /* return to init state */ 1823 /* return to init state */
1835 change_listen_mode(LISTEN_NONE); 1824 change_listen_mode(LISTEN_NONE);
@@ -1853,7 +1842,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1853 1842
1854 ret0: 1843 ret0:
1855 if (opt & OPT_R) /* release on quit */ 1844 if (opt & OPT_R) /* release on quit */
1856 perform_release(server_addr, requested_ip); 1845 perform_release(server_id, requested_ip);
1857 retval = 0; 1846 retval = 0;
1858 ret: 1847 ret:
1859 /*if (client_data.pidfile) - remove_pidfile has its own check */ 1848 /*if (client_data.pidfile) - remove_pidfile has its own check */