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 2006 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 }; 72 73 if (state < 0 || state >= DHCP_NSTATES) 74 return ("<unknown>"); 75 76 return (states[state]); 77 } 78 79 /* 80 * dhcp_string_to_request(): maps a string into a request code 81 * 82 * input: const char *: the string to map 83 * output: dhcp_ipc_type_t: the request code, or -1 if unknown 84 */ 85 86 dhcp_ipc_type_t 87 dhcp_string_to_request(const char *request) 88 { 89 static struct { 90 const char *string; 91 dhcp_ipc_type_t type; 92 } types[] = { 93 { "drop", DHCP_DROP }, 94 { "extend", DHCP_EXTEND }, 95 { "inform", DHCP_INFORM }, 96 { "ping", DHCP_PING }, 97 { "release", DHCP_RELEASE }, 98 { "start", DHCP_START }, 99 { "status", DHCP_STATUS } 100 }; 101 102 unsigned int i; 103 104 for (i = 0; i < (sizeof (types) / sizeof (*types)); i++) 105 if (strcmp(types[i].string, request) == 0) 106 return (types[i].type); 107 108 return (-1); 109 } 110 111 /* 112 * dhcp_start_agent(): starts the agent if not already running 113 * 114 * input: int: number of seconds to wait for agent to start (-1 is forever) 115 * output: int: 0 on success, -1 on failure 116 */ 117 118 int 119 dhcp_start_agent(int timeout) 120 { 121 int error; 122 time_t start_time = time(NULL); 123 dhcp_ipc_request_t *request; 124 dhcp_ipc_reply_t *reply; 125 126 /* 127 * just send a dummy request to the agent to find out if it's 128 * up. we do this instead of directly connecting to it since 129 * we want to make sure we follow its IPC conventions 130 * (otherwise, it will log warnings to syslog). 131 */ 132 133 request = dhcp_ipc_alloc_request(DHCP_PING, "", NULL, 0, 134 DHCP_TYPE_NONE); 135 if (request == NULL) 136 return (-1); 137 138 error = dhcp_ipc_make_request(request, &reply, 0); 139 if (error == 0) { 140 free(reply); 141 free(request); 142 return (0); 143 } 144 if (error != DHCP_IPC_E_CONNECT) { 145 free(request); 146 return (-1); 147 } 148 149 switch (fork()) { 150 151 case -1: 152 free(request); 153 return (-1); 154 155 case 0: 156 (void) execl(DHCP_AGENT_PATH, DHCP_AGENT_PATH, (char *)0); 157 _exit(EXIT_FAILURE); 158 159 default: 160 break; 161 } 162 163 while ((timeout != -1) && (time(NULL) - start_time < timeout)) { 164 error = dhcp_ipc_make_request(request, &reply, 0); 165 if (error == 0) { 166 free(reply); 167 free(request); 168 return (0); 169 } else if (error != DHCP_IPC_E_CONNECT) 170 break; 171 (void) sleep(1); 172 } 173 174 free(request); 175 return (-1); 176 } 177 178 /* 179 * dhcp_status_hdr_string(): Return a string suitable to use as the header 180 * when printing DHCP_STATUS reply. 181 * output: const char *: newline terminated printable string 182 */ 183 const char * 184 dhcp_status_hdr_string(void) 185 { 186 return (DHCP_STATUS_HDR); 187 } 188 189 /* 190 * time_to_string(): Utility routine for printing time 191 * 192 * input: time_t *: time_t to stringify 193 * output: const char *: printable time 194 */ 195 static const char * 196 time_to_string(time_t abs_time) 197 { 198 static char time_buf[24]; 199 time_t tm = abs_time; 200 201 if (tm == DHCP_PERM) 202 return ("Never"); 203 204 if (strftime(time_buf, sizeof (time_buf), "%m/%d/%Y %R", 205 localtime(&tm)) == 0) 206 return ("<unknown>"); 207 208 return (time_buf); 209 } 210 211 /* 212 * dhcp_status_reply_to_string(): Return DHCP IPC reply of type DHCP_STATUS 213 * as a printable string 214 * 215 * input: dhcp_reply_t *: contains the status structure to print 216 * output: const char *: newline terminated printable string 217 */ 218 const char * 219 dhcp_status_reply_to_string(dhcp_ipc_reply_t *reply) 220 { 221 static char str[1024]; 222 size_t reply_size; 223 dhcp_status_t *status; 224 225 status = dhcp_ipc_get_data(reply, &reply_size, NULL); 226 if (reply_size < DHCP_STATUS_VER1_SIZE) 227 return ("<Internal error: status msg size>\n"); 228 229 (void) snprintf(str, sizeof (str), DHCP_STATUS_STR, 230 status->if_name, dhcp_state_to_string(status->if_state), 231 status->if_sent, status->if_recv, status->if_bad_offers); 232 233 if (status->if_dflags & DHCP_IF_PRIMARY) 234 (void) strlcat(str, "[PRIMARY] ", sizeof (str)); 235 236 if (status->if_dflags & DHCP_IF_BOOTP) 237 (void) strlcat(str, "[BOOTP] ", sizeof (str)); 238 239 if (status->if_dflags & DHCP_IF_FAILED) 240 (void) strlcat(str, "[FAILED] ", sizeof (str)); 241 242 if (status->if_dflags & DHCP_IF_BUSY) 243 (void) strlcat(str, "[BUSY] ", sizeof (str)); 244 245 (void) strlcat(str, "\n", sizeof (str)); 246 247 switch (status->if_state) { 248 case BOUND: 249 case RENEWING: 250 case REBINDING: 251 break; 252 default: 253 return (str); 254 } 255 256 (void) strlcat(str, "(Began, Expires, Renew) = (", sizeof (str)); 257 (void) strlcat(str, time_to_string(status->if_began), sizeof (str)); 258 (void) strlcat(str, ", ", sizeof (str)); 259 (void) strlcat(str, time_to_string(status->if_lease), sizeof (str)); 260 (void) strlcat(str, ", ", sizeof (str)); 261 (void) strlcat(str, time_to_string(status->if_t1), sizeof (str)); 262 (void) strlcat(str, ")\n", sizeof (str)); 263 return (str); 264 } 265