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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <sys/types.h> 29 #include <sys/socket.h> 30 #include <sys/time.h> 31 #include <unistd.h> 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <string.h> 35 #include "dhcpagent_ipc.h" 36 #include "dhcpagent_util.h" 37 38 /* 39 * Strings returned by dhcp_status_hdr_string() and 40 * dhcp_status_reply_to_string(). The first define is the header line, and 41 * the second defines line printed underneath. 42 * The spacing of fields must match. 43 */ 44 #define DHCP_STATUS_HDR "Interface State Sent Recv Declined Flags\n" 45 #define DHCP_STATUS_STR "%-10s %-12s %5d %5d %9d " 46 47 static const char *time_to_string(time_t abs_time); 48 49 /* 50 * dhcp_state_to_string(): given a state, provides the state's name 51 * 52 * input: DHCPSTATE: the state to get the name of 53 * output: const char *: the state's name 54 */ 55 56 const char * 57 dhcp_state_to_string(DHCPSTATE state) 58 { 59 const char *states[] = { 60 "INIT", 61 "SELECTING", 62 "REQUESTING", 63 "PRE_BOUND", 64 "BOUND", 65 "RENEWING", 66 "REBINDING", 67 "INFORMATION", 68 "INIT_REBOOT", 69 "ADOPTING", 70 "INFORM_SENT", 71 "DECLINING", 72 "RELEASING" 73 }; 74 75 if (state < 0 || state >= DHCP_NSTATES) 76 return ("<unknown>"); 77 78 return (states[state]); 79 } 80 81 /* 82 * dhcp_string_to_request(): maps a string into a request code 83 * 84 * input: const char *: the string to map 85 * output: dhcp_ipc_type_t: the request code, or -1 if unknown 86 */ 87 88 dhcp_ipc_type_t 89 dhcp_string_to_request(const char *request) 90 { 91 static struct { 92 const char *string; 93 dhcp_ipc_type_t type; 94 } types[] = { 95 { "drop", DHCP_DROP }, 96 { "extend", DHCP_EXTEND }, 97 { "inform", DHCP_INFORM }, 98 { "ping", DHCP_PING }, 99 { "release", DHCP_RELEASE }, 100 { "start", DHCP_START }, 101 { "status", DHCP_STATUS } 102 }; 103 104 unsigned int i; 105 106 for (i = 0; i < (sizeof (types) / sizeof (*types)); i++) 107 if (strcmp(types[i].string, request) == 0) 108 return (types[i].type); 109 110 return (-1); 111 } 112 113 /* 114 * dhcp_start_agent(): starts the agent if not already running 115 * 116 * input: int: number of seconds to wait for agent to start (-1 is forever) 117 * output: int: 0 on success, -1 on failure 118 */ 119 120 int 121 dhcp_start_agent(int timeout) 122 { 123 int error; 124 time_t start_time = time(NULL); 125 dhcp_ipc_request_t *request; 126 dhcp_ipc_reply_t *reply; 127 128 /* 129 * just send a dummy request to the agent to find out if it's 130 * up. we do this instead of directly connecting to it since 131 * we want to make sure we follow its IPC conventions 132 * (otherwise, it will log warnings to syslog). 133 */ 134 135 request = dhcp_ipc_alloc_request(DHCP_PING, "", NULL, 0, 136 DHCP_TYPE_NONE); 137 if (request == NULL) 138 return (-1); 139 140 error = dhcp_ipc_make_request(request, &reply, 0); 141 if (error == 0) { 142 free(reply); 143 free(request); 144 return (0); 145 } 146 if (error != DHCP_IPC_E_CONNECT) { 147 free(request); 148 return (-1); 149 } 150 151 switch (fork()) { 152 153 case -1: 154 free(request); 155 return (-1); 156 157 case 0: 158 (void) execl(DHCP_AGENT_PATH, DHCP_AGENT_PATH, (char *)0); 159 _exit(EXIT_FAILURE); 160 161 default: 162 break; 163 } 164 165 while ((timeout != -1) && (time(NULL) - start_time < timeout)) { 166 error = dhcp_ipc_make_request(request, &reply, 0); 167 if (error == 0) { 168 free(reply); 169 free(request); 170 return (0); 171 } else if (error != DHCP_IPC_E_CONNECT) 172 break; 173 (void) sleep(1); 174 } 175 176 free(request); 177 return (-1); 178 } 179 180 /* 181 * dhcp_status_hdr_string(): Return a string suitable to use as the header 182 * when printing DHCP_STATUS reply. 183 * output: const char *: newline terminated printable string 184 */ 185 const char * 186 dhcp_status_hdr_string(void) 187 { 188 return (DHCP_STATUS_HDR); 189 } 190 191 /* 192 * time_to_string(): Utility routine for printing time 193 * 194 * input: time_t *: time_t to stringify 195 * output: const char *: printable time 196 */ 197 static const char * 198 time_to_string(time_t abs_time) 199 { 200 static char time_buf[24]; 201 time_t tm = abs_time; 202 203 if (tm == DHCP_PERM) 204 return ("Never"); 205 206 if (strftime(time_buf, sizeof (time_buf), "%m/%d/%Y %R", 207 localtime(&tm)) == 0) 208 return ("<unknown>"); 209 210 return (time_buf); 211 } 212 213 /* 214 * dhcp_status_reply_to_string(): Return DHCP IPC reply of type DHCP_STATUS 215 * as a printable string 216 * 217 * input: dhcp_reply_t *: contains the status structure to print 218 * output: const char *: newline terminated printable string 219 */ 220 const char * 221 dhcp_status_reply_to_string(dhcp_ipc_reply_t *reply) 222 { 223 static char str[1024]; 224 size_t reply_size; 225 dhcp_status_t *status; 226 227 status = dhcp_ipc_get_data(reply, &reply_size, NULL); 228 if (reply_size < DHCP_STATUS_VER1_SIZE) 229 return ("<Internal error: status msg size>\n"); 230 231 (void) snprintf(str, sizeof (str), DHCP_STATUS_STR, 232 status->if_name, dhcp_state_to_string(status->if_state), 233 status->if_sent, status->if_recv, status->if_bad_offers); 234 235 if (status->if_dflags & DHCP_IF_PRIMARY) 236 (void) strlcat(str, "[PRIMARY] ", sizeof (str)); 237 238 if (status->if_dflags & DHCP_IF_BOOTP) 239 (void) strlcat(str, "[BOOTP] ", sizeof (str)); 240 241 if (status->if_dflags & DHCP_IF_FAILED) 242 (void) strlcat(str, "[FAILED] ", sizeof (str)); 243 244 if (status->if_dflags & DHCP_IF_BUSY) 245 (void) strlcat(str, "[BUSY] ", sizeof (str)); 246 247 if (status->if_dflags & DHCP_IF_V6) 248 (void) strlcat(str, "[V6] ", sizeof (str)); 249 250 (void) strlcat(str, "\n", sizeof (str)); 251 252 switch (status->if_state) { 253 case BOUND: 254 case RENEWING: 255 case REBINDING: 256 break; 257 default: 258 return (str); 259 } 260 261 (void) strlcat(str, "(Began, Expires, Renew) = (", sizeof (str)); 262 (void) strlcat(str, time_to_string(status->if_began), sizeof (str)); 263 (void) strlcat(str, ", ", sizeof (str)); 264 (void) strlcat(str, time_to_string(status->if_lease), sizeof (str)); 265 (void) strlcat(str, ", ", sizeof (str)); 266 (void) strlcat(str, time_to_string(status->if_t1), sizeof (str)); 267 (void) strlcat(str, ")\n", sizeof (str)); 268 return (str); 269 } 270