1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  *
26  * DECLINE/RELEASE configuration functionality for the DHCP client.
27  */
28 
29 #pragma ident	"%Z%%M%	%I%	%E% SMI"
30 
31 #include <sys/types.h>
32 #include <string.h>
33 #include <netinet/in.h>
34 #include <sys/socket.h>
35 #include <net/if.h>
36 #include <netinet/dhcp.h>
37 #include <dhcpmsg.h>
38 #include <dhcp_hostconf.h>
39 #include <unistd.h>
40 
41 #include "packet.h"
42 #include "interface.h"
43 #include "states.h"
44 
45 /*
46  * send_decline(): sends a DECLINE message (broadcasted)
47  *
48  *   input: struct ifslist *: the interface to send the DECLINE on
49  *	    char *: an optional text explanation to send with the message
50  *	    struct in_addr *: the IP address being declined
51  *  output: void
52  */
53 
54 void
55 send_decline(struct ifslist *ifsp, char *msg, struct in_addr *declined_ip)
56 {
57 	dhcp_pkt_t	*dpkt;
58 
59 	dpkt = init_pkt(ifsp, DECLINE);
60 	add_pkt_opt32(dpkt, CD_SERVER_ID, ifsp->if_server.s_addr);
61 
62 	if (msg != NULL)
63 		add_pkt_opt(dpkt, CD_MESSAGE, msg, strlen(msg) + 1);
64 
65 	add_pkt_opt32(dpkt, CD_REQUESTED_IP_ADDR, declined_ip->s_addr);
66 	add_pkt_opt(dpkt, CD_END, NULL, 0);
67 
68 	(void) send_pkt(ifsp, dpkt, htonl(INADDR_BROADCAST), NULL);
69 }
70 
71 /*
72  * dhcp_release(): sends a RELEASE message to a DHCP server and removes
73  *		   the interface from DHCP control
74  *
75  *   input: struct ifslist *: the interface to send the RELEASE on and remove
76  *	    const char *: an optional text explanation to send with the message
77  *  output: int: 1 on success, 0 on failure
78  */
79 
80 int
81 dhcp_release(struct ifslist *ifsp, const char *msg)
82 {
83 	int		retval = 0;
84 	int		error = DHCP_IPC_E_INT;
85 	dhcp_pkt_t	*dpkt;
86 
87 	if (ifsp->if_dflags & DHCP_IF_BOOTP)
88 		goto out;
89 
90 	if (ifsp->if_state != BOUND && ifsp->if_state != RENEWING &&
91 	    ifsp->if_state != REBINDING)
92 		goto out;
93 
94 	dhcpmsg(MSG_INFO, "releasing interface %s", ifsp->if_name);
95 
96 	dpkt = init_pkt(ifsp, RELEASE);
97 	dpkt->pkt->ciaddr.s_addr = ifsp->if_addr.s_addr;
98 
99 	if (msg != NULL)
100 		add_pkt_opt(dpkt, CD_MESSAGE, msg, strlen(msg) + 1);
101 
102 	add_pkt_opt32(dpkt, CD_SERVER_ID, ifsp->if_server.s_addr);
103 	add_pkt_opt(dpkt, CD_END, NULL, 0);
104 
105 	(void) send_pkt(ifsp, dpkt, ifsp->if_server.s_addr, NULL);
106 
107 	/*
108 	 * XXX this totally sucks, but since udp is best-effort,
109 	 * without this delay, there's a good chance that the packet
110 	 * that we just enqueued for sending will get pitched
111 	 * when we canonize the interface below.
112 	 */
113 
114 	(void) usleep(500);
115 	(void) canonize_ifs(ifsp);
116 
117 	remove_ifs(ifsp);
118 	error = DHCP_IPC_SUCCESS;
119 	retval = 1;
120 out:
121 	ipc_action_finish(ifsp, error);
122 	async_finish(ifsp);
123 	return (retval);
124 }
125 
126 /*
127  * dhcp_drop(): drops the interface from DHCP control
128  *
129  *   input: struct ifslist *: the interface to drop
130  *	    const char *: unused
131  *  output: int: always 1
132  */
133 
134 /* ARGSUSED */
135 int
136 dhcp_drop(struct ifslist *ifsp, const char *msg)
137 {
138 	PKT_LIST *plp[2];
139 
140 	dhcpmsg(MSG_INFO, "dropping interface %s", ifsp->if_name);
141 
142 	if (ifsp->if_state == BOUND || ifsp->if_state == RENEWING ||
143 	    ifsp->if_state == REBINDING) {
144 
145 		if ((ifsp->if_dflags & DHCP_IF_BOOTP) == 0) {
146 			plp[0] = ifsp->if_ack;
147 			plp[1] = ifsp->if_orig_ack;
148 			if (write_hostconf(ifsp->if_name, plp, 2,
149 			    monosec_to_time(ifsp->if_curstart_monosec)) == -1)
150 				dhcpmsg(MSG_ERR, "cannot write %s (reboot will "
151 				    "not use cached configuration)",
152 				    ifname_to_hostconf(ifsp->if_name));
153 		}
154 		(void) canonize_ifs(ifsp);
155 	}
156 	remove_ifs(ifsp);
157 	ipc_action_finish(ifsp, DHCP_IPC_SUCCESS);
158 	async_finish(ifsp);
159 	return (1);
160 }
161