xref: /titanic_51/usr/src/cmd/cmd-inet/sbin/dhcpagent/inform.c (revision 749f21d359d8fbd020c974a1a5227316221bfc9c)
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 (c) 1995-2001 by Sun Microsystems, Inc.
24  * All rights reserved.
25  *
26  * INFORM_SENT state of the client state machine.
27  */
28 
29 #pragma ident	"%Z%%M%	%I%	%E% SMI"
30 
31 #include <sys/types.h>
32 #include <string.h>
33 #include <time.h>
34 #include <unistd.h>
35 #include <sys/sockio.h>
36 #include <sys/socket.h>
37 #include <netinet/in.h>
38 #include <netinet/udp.h>
39 #include <netinet/ip_var.h>
40 #include <netinet/udp_var.h>
41 #include <dhcpmsg.h>
42 
43 #include "util.h"
44 #include "packet.h"
45 #include "interface.h"
46 
47 /*
48  * dhcp_inform(): sends an INFORM packet and sets up reception for an ACK
49  *
50  *   input: struct ifslist *: the interface to send the inform on, ...
51  *  output: void
52  *    note: the INFORM cannot be sent successfully if the interface
53  *	    does not have an IP address
54  */
55 
56 void
57 dhcp_inform(struct ifslist *ifsp)
58 {
59 	dhcp_pkt_t		*dpkt;
60 	struct in_addr		*our_addr;
61 	struct ifreq		ifr;
62 
63 	ifsp->if_state = INIT;
64 
65 	/*
66 	 * fetch our IP address -- since we may not manage the
67 	 * interface, go fetch it with ioctl()
68 	 */
69 
70 	(void) memset(&ifr, 0, sizeof (struct ifreq));
71 	(void) strlcpy(ifr.ifr_name, ifsp->if_name, IFNAMSIZ);
72 	ifr.ifr_addr.sa_family = AF_INET;
73 
74 	if (ioctl(ifsp->if_sock_fd, SIOCGIFADDR, &ifr) == -1) {
75 		ifsp->if_dflags |= DHCP_IF_FAILED;
76 		ipc_action_finish(ifsp, DHCP_IPC_E_INT);
77 		async_finish(ifsp);
78 		return;
79 	}
80 
81 	/*
82 	 * the error handling here and in the check for IFF_UP below
83 	 * are handled different from most since it is the user who is
84 	 * at fault for the problem, not the machine.
85 	 */
86 
87 	/* LINTED [ifr_addr is a sockaddr which will be aligned] */
88 	our_addr = &((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr;
89 	if (our_addr->s_addr == htonl(INADDR_ANY)) {
90 		dhcpmsg(MSG_WARNING, "dhcp_inform: INFORM attempted on "
91 		    "interface with no IP address");
92 		ipc_action_finish(ifsp, DHCP_IPC_E_NOIPIF);
93 		async_finish(ifsp);
94 		remove_ifs(ifsp);
95 		return;
96 	}
97 
98 	if (ioctl(ifsp->if_sock_fd, SIOCGIFFLAGS, &ifr) == -1) {
99 		ifsp->if_dflags |= DHCP_IF_FAILED;
100 		ipc_action_finish(ifsp, DHCP_IPC_E_INT);
101 		async_finish(ifsp);
102 		return;
103 	}
104 
105 	if ((ifr.ifr_flags & IFF_UP) == 0) {
106 		dhcpmsg(MSG_WARNING, "dhcp_inform: INFORM attempted on downed "
107 		    "interface");
108 		ipc_action_finish(ifsp, DHCP_IPC_E_DOWNIF);
109 		async_finish(ifsp);
110 		remove_ifs(ifsp);
111 		return;
112 	}
113 
114 	/*
115 	 * assemble a DHCPREQUEST packet, without the server id
116 	 * option.  fill in ciaddr, since we know this.  if_server
117 	 * will be set to the server's IP address, which will be the
118 	 * broadcast address if we don't know it.  The max dhcp message size
119 	 * option is set to the interface max, minus the size of the udp and
120 	 * ip headers.
121 	 */
122 
123 	dpkt = init_pkt(ifsp, INFORM);
124 	dpkt->pkt->ciaddr = *our_addr;
125 
126 	add_pkt_opt16(dpkt, CD_MAX_DHCP_SIZE, htons(ifsp->if_max -
127 			sizeof (struct udpiphdr)));
128 	add_pkt_opt(dpkt, CD_CLASS_ID, class_id, class_id_len);
129 	add_pkt_opt(dpkt, CD_REQUEST_LIST, ifsp->if_prl, ifsp->if_prllen);
130 	add_pkt_opt(dpkt, CD_END, NULL, 0);
131 
132 	if (send_pkt(ifsp, dpkt, ifsp->if_server.s_addr, NULL) == 0) {
133 		ifsp->if_dflags |= DHCP_IF_FAILED;
134 		dhcpmsg(MSG_ERROR, "dhcp_inform: send_pkt failed");
135 		ipc_action_finish(ifsp, DHCP_IPC_E_INT);
136 		async_finish(ifsp);
137 		return;
138 	}
139 
140 	if (register_acknak(ifsp) == 0) {
141 		ifsp->if_dflags |= DHCP_IF_FAILED;
142 		ipc_action_finish(ifsp, DHCP_IPC_E_MEMORY);
143 		async_finish(ifsp);
144 		return;
145 	}
146 
147 	ifsp->if_state = INFORM_SENT;
148 }
149