17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*d04ccbb3Scarlsonj * Common Development and Distribution License (the "License"). 6*d04ccbb3Scarlsonj * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*d04ccbb3Scarlsonj * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate 28*d04ccbb3Scarlsonj #include <stdlib.h> 297c478bd9Sstevel@tonic-gate #include <sys/types.h> 307c478bd9Sstevel@tonic-gate #include <dhcpmsg.h> 31*d04ccbb3Scarlsonj #include <dhcpagent_ipc.h> 327c478bd9Sstevel@tonic-gate 33*d04ccbb3Scarlsonj #include "agent.h" 34*d04ccbb3Scarlsonj #include "states.h" 357c478bd9Sstevel@tonic-gate #include "interface.h" 367c478bd9Sstevel@tonic-gate #include "ipc_action.h" 377c478bd9Sstevel@tonic-gate #include "util.h" 387c478bd9Sstevel@tonic-gate 397c478bd9Sstevel@tonic-gate static iu_tq_callback_t ipc_action_timeout; 407c478bd9Sstevel@tonic-gate 417c478bd9Sstevel@tonic-gate /* 427c478bd9Sstevel@tonic-gate * ipc_action_init(): initializes the ipc_action structure 437c478bd9Sstevel@tonic-gate * 44*d04ccbb3Scarlsonj * input: ipc_action_t *: the structure to initialize 457c478bd9Sstevel@tonic-gate * output: void 467c478bd9Sstevel@tonic-gate */ 477c478bd9Sstevel@tonic-gate 487c478bd9Sstevel@tonic-gate void 49*d04ccbb3Scarlsonj ipc_action_init(ipc_action_t *ia) 507c478bd9Sstevel@tonic-gate { 51*d04ccbb3Scarlsonj ia->ia_cmd = 0; 52*d04ccbb3Scarlsonj ia->ia_fd = -1; 53*d04ccbb3Scarlsonj ia->ia_tid = -1; 54*d04ccbb3Scarlsonj ia->ia_eid = -1; 55*d04ccbb3Scarlsonj ia->ia_request = NULL; 567c478bd9Sstevel@tonic-gate } 577c478bd9Sstevel@tonic-gate 587c478bd9Sstevel@tonic-gate /* 59*d04ccbb3Scarlsonj * ipc_action_start(): starts an ipc_action request on a DHCP state machine 607c478bd9Sstevel@tonic-gate * 61*d04ccbb3Scarlsonj * input: dhcp_smach_t *: the state machine to start the action on 62*d04ccbb3Scarlsonj * ipc_action_t *: request structure 63*d04ccbb3Scarlsonj * output: B_TRUE if the request is started successfully, B_FALSE otherwise 64*d04ccbb3Scarlsonj * original request is still valid on failure, consumed otherwise. 657c478bd9Sstevel@tonic-gate */ 667c478bd9Sstevel@tonic-gate 677c478bd9Sstevel@tonic-gate boolean_t 68*d04ccbb3Scarlsonj ipc_action_start(dhcp_smach_t *dsmp, ipc_action_t *iareq) 697c478bd9Sstevel@tonic-gate { 70*d04ccbb3Scarlsonj struct ipc_action *ia = &dsmp->dsm_ia; 717c478bd9Sstevel@tonic-gate 72*d04ccbb3Scarlsonj if (ia->ia_fd != -1 || ia->ia_tid != -1 || iareq->ia_fd == -1) { 73*d04ccbb3Scarlsonj dhcpmsg(MSG_CRIT, "ipc_action_start: attempted restart on %s", 74*d04ccbb3Scarlsonj dsmp->dsm_name); 75*d04ccbb3Scarlsonj return (B_FALSE); 767c478bd9Sstevel@tonic-gate } 777c478bd9Sstevel@tonic-gate 78*d04ccbb3Scarlsonj if (!async_cancel(dsmp)) { 79*d04ccbb3Scarlsonj dhcpmsg(MSG_WARNING, "ipc_action_start: unable to cancel " 80*d04ccbb3Scarlsonj "action on %s", dsmp->dsm_name); 817c478bd9Sstevel@tonic-gate return (B_FALSE); 827c478bd9Sstevel@tonic-gate } 837c478bd9Sstevel@tonic-gate 84*d04ccbb3Scarlsonj if (iareq->ia_request->timeout == DHCP_IPC_WAIT_DEFAULT) 85*d04ccbb3Scarlsonj iareq->ia_request->timeout = DHCP_IPC_DEFAULT_WAIT; 86*d04ccbb3Scarlsonj 87*d04ccbb3Scarlsonj if (iareq->ia_request->timeout == DHCP_IPC_WAIT_FOREVER) { 88*d04ccbb3Scarlsonj iareq->ia_tid = -1; 89*d04ccbb3Scarlsonj } else { 90*d04ccbb3Scarlsonj iareq->ia_tid = iu_schedule_timer(tq, 91*d04ccbb3Scarlsonj iareq->ia_request->timeout, ipc_action_timeout, dsmp); 92*d04ccbb3Scarlsonj 93*d04ccbb3Scarlsonj if (iareq->ia_tid == -1) { 94*d04ccbb3Scarlsonj dhcpmsg(MSG_ERROR, "ipc_action_start: failed to set " 95*d04ccbb3Scarlsonj "timer for %s on %s", 96*d04ccbb3Scarlsonj dhcp_ipc_type_to_string(iareq->ia_cmd), 97*d04ccbb3Scarlsonj dsmp->dsm_name); 98*d04ccbb3Scarlsonj return (B_FALSE); 99*d04ccbb3Scarlsonj } 100*d04ccbb3Scarlsonj 101*d04ccbb3Scarlsonj hold_smach(dsmp); 102*d04ccbb3Scarlsonj } 103*d04ccbb3Scarlsonj 104*d04ccbb3Scarlsonj *ia = *iareq; 105*d04ccbb3Scarlsonj 106*d04ccbb3Scarlsonj /* We've taken ownership, so the input request is now invalid */ 107*d04ccbb3Scarlsonj ipc_action_init(iareq); 108*d04ccbb3Scarlsonj 109*d04ccbb3Scarlsonj dhcpmsg(MSG_DEBUG, "ipc_action_start: started %s (command %d) on %s", 110*d04ccbb3Scarlsonj dhcp_ipc_type_to_string(ia->ia_cmd), ia->ia_cmd, dsmp->dsm_name); 111*d04ccbb3Scarlsonj 112*d04ccbb3Scarlsonj dsmp->dsm_dflags |= DHCP_IF_BUSY; 113*d04ccbb3Scarlsonj 114*d04ccbb3Scarlsonj /* This cannot fail due to the async_cancel above */ 115*d04ccbb3Scarlsonj (void) async_start(dsmp, ia->ia_cmd, B_TRUE); 116*d04ccbb3Scarlsonj 117*d04ccbb3Scarlsonj return (B_TRUE); 118*d04ccbb3Scarlsonj } 119*d04ccbb3Scarlsonj 1207c478bd9Sstevel@tonic-gate /* 1217c478bd9Sstevel@tonic-gate * ipc_action_finish(): completes an ipc_action request on an interface 1227c478bd9Sstevel@tonic-gate * 123*d04ccbb3Scarlsonj * input: dhcp_smach_t *: the state machine to complete the action on 1247c478bd9Sstevel@tonic-gate * int: the reason why the action finished (nonzero on error) 1257c478bd9Sstevel@tonic-gate * output: void 1267c478bd9Sstevel@tonic-gate */ 1277c478bd9Sstevel@tonic-gate 1287c478bd9Sstevel@tonic-gate void 129*d04ccbb3Scarlsonj ipc_action_finish(dhcp_smach_t *dsmp, int reason) 1307c478bd9Sstevel@tonic-gate { 131*d04ccbb3Scarlsonj struct ipc_action *ia = &dsmp->dsm_ia; 1327c478bd9Sstevel@tonic-gate 133*d04ccbb3Scarlsonj dsmp->dsm_dflags &= ~DHCP_IF_BUSY; 134*d04ccbb3Scarlsonj 135*d04ccbb3Scarlsonj if (dsmp->dsm_ia.ia_fd == -1) { 136*d04ccbb3Scarlsonj dhcpmsg(MSG_ERROR, 137*d04ccbb3Scarlsonj "ipc_action_finish: attempted to finish unknown action " 138*d04ccbb3Scarlsonj "on %s", dsmp->dsm_name); 1397c478bd9Sstevel@tonic-gate return; 140*d04ccbb3Scarlsonj } 141*d04ccbb3Scarlsonj 142*d04ccbb3Scarlsonj dhcpmsg(MSG_DEBUG, 143*d04ccbb3Scarlsonj "ipc_action_finish: finished %s (command %d) on %s: %d", 144*d04ccbb3Scarlsonj dhcp_ipc_type_to_string(ia->ia_cmd), (int)ia->ia_cmd, 145*d04ccbb3Scarlsonj dsmp->dsm_name, reason); 146*d04ccbb3Scarlsonj 147*d04ccbb3Scarlsonj /* 148*d04ccbb3Scarlsonj * if we can't cancel this timer, we're really in the 149*d04ccbb3Scarlsonj * twilight zone. however, as long as we don't drop the 150*d04ccbb3Scarlsonj * reference to the state machine, it shouldn't hurt us 151*d04ccbb3Scarlsonj */ 152*d04ccbb3Scarlsonj 153*d04ccbb3Scarlsonj if (dsmp->dsm_ia.ia_tid != -1 && 154*d04ccbb3Scarlsonj iu_cancel_timer(tq, dsmp->dsm_ia.ia_tid, NULL) == 1) { 155*d04ccbb3Scarlsonj dsmp->dsm_ia.ia_tid = -1; 156*d04ccbb3Scarlsonj release_smach(dsmp); 157*d04ccbb3Scarlsonj } 1587c478bd9Sstevel@tonic-gate 1597c478bd9Sstevel@tonic-gate if (reason == 0) 160*d04ccbb3Scarlsonj send_ok_reply(ia); 1617c478bd9Sstevel@tonic-gate else 162*d04ccbb3Scarlsonj send_error_reply(ia, reason); 1637c478bd9Sstevel@tonic-gate 164*d04ccbb3Scarlsonj async_finish(dsmp); 1657c478bd9Sstevel@tonic-gate } 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate /* 168*d04ccbb3Scarlsonj * ipc_action_timeout(): times out an ipc_action on a state machine (the 169*d04ccbb3Scarlsonj * request continues asynchronously, however) 1707c478bd9Sstevel@tonic-gate * 1717c478bd9Sstevel@tonic-gate * input: iu_tq_t *: unused 172*d04ccbb3Scarlsonj * void *: the dhcp_smach_t * the ipc_action was pending on 1737c478bd9Sstevel@tonic-gate * output: void 1747c478bd9Sstevel@tonic-gate */ 1757c478bd9Sstevel@tonic-gate 1767c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1777c478bd9Sstevel@tonic-gate static void 1787c478bd9Sstevel@tonic-gate ipc_action_timeout(iu_tq_t *tq, void *arg) 1797c478bd9Sstevel@tonic-gate { 180*d04ccbb3Scarlsonj dhcp_smach_t *dsmp = arg; 181*d04ccbb3Scarlsonj struct ipc_action *ia = &dsmp->dsm_ia; 1827c478bd9Sstevel@tonic-gate 183*d04ccbb3Scarlsonj dsmp->dsm_dflags &= ~DHCP_IF_BUSY; 184*d04ccbb3Scarlsonj 185*d04ccbb3Scarlsonj ia->ia_tid = -1; 1867c478bd9Sstevel@tonic-gate 1877c478bd9Sstevel@tonic-gate dhcpmsg(MSG_VERBOSE, "ipc timeout waiting for agent to complete " 188*d04ccbb3Scarlsonj "%s (command %d) for %s", dhcp_ipc_type_to_string(ia->ia_cmd), 189*d04ccbb3Scarlsonj ia->ia_cmd, dsmp->dsm_name); 1907c478bd9Sstevel@tonic-gate 191*d04ccbb3Scarlsonj send_error_reply(ia, DHCP_IPC_E_TIMEOUT); 192*d04ccbb3Scarlsonj 193*d04ccbb3Scarlsonj async_finish(dsmp); 194*d04ccbb3Scarlsonj release_smach(dsmp); 1957c478bd9Sstevel@tonic-gate } 1967c478bd9Sstevel@tonic-gate 1977c478bd9Sstevel@tonic-gate /* 198*d04ccbb3Scarlsonj * send_ok_reply(): sends an "ok" reply to a request and closes the ipc 199*d04ccbb3Scarlsonj * connection 2007c478bd9Sstevel@tonic-gate * 201*d04ccbb3Scarlsonj * input: ipc_action_t *: the request to reply to 2027c478bd9Sstevel@tonic-gate * output: void 203*d04ccbb3Scarlsonj * note: the request is freed (thus the request must be on the heap). 2047c478bd9Sstevel@tonic-gate */ 2057c478bd9Sstevel@tonic-gate 2067c478bd9Sstevel@tonic-gate void 207*d04ccbb3Scarlsonj send_ok_reply(ipc_action_t *ia) 2087c478bd9Sstevel@tonic-gate { 209*d04ccbb3Scarlsonj send_error_reply(ia, 0); 210*d04ccbb3Scarlsonj } 2117c478bd9Sstevel@tonic-gate 2127c478bd9Sstevel@tonic-gate /* 213*d04ccbb3Scarlsonj * send_error_reply(): sends an "error" reply to a request and closes the ipc 214*d04ccbb3Scarlsonj * connection 215*d04ccbb3Scarlsonj * 216*d04ccbb3Scarlsonj * input: ipc_action_t *: the request to reply to 217*d04ccbb3Scarlsonj * int: the error to send back on the ipc connection 218*d04ccbb3Scarlsonj * output: void 219*d04ccbb3Scarlsonj * note: the request is freed (thus the request must be on the heap). 2207c478bd9Sstevel@tonic-gate */ 2217c478bd9Sstevel@tonic-gate 222*d04ccbb3Scarlsonj void 223*d04ccbb3Scarlsonj send_error_reply(ipc_action_t *ia, int error) 224*d04ccbb3Scarlsonj { 225*d04ccbb3Scarlsonj send_data_reply(ia, error, DHCP_TYPE_NONE, NULL, 0); 2267c478bd9Sstevel@tonic-gate } 227*d04ccbb3Scarlsonj 228*d04ccbb3Scarlsonj /* 229*d04ccbb3Scarlsonj * send_data_reply(): sends a reply to a request and closes the ipc connection 230*d04ccbb3Scarlsonj * 231*d04ccbb3Scarlsonj * input: ipc_action_t *: the request to reply to 232*d04ccbb3Scarlsonj * int: the status to send back on the ipc connection (zero for 233*d04ccbb3Scarlsonj * success, DHCP_IPC_E_* otherwise). 234*d04ccbb3Scarlsonj * dhcp_data_type_t: the type of the payload in the reply 235*d04ccbb3Scarlsonj * const void *: the payload for the reply, or NULL if there is no 236*d04ccbb3Scarlsonj * payload 237*d04ccbb3Scarlsonj * size_t: the size of the payload 238*d04ccbb3Scarlsonj * output: void 239*d04ccbb3Scarlsonj * note: the request is freed (thus the request must be on the heap). 240*d04ccbb3Scarlsonj */ 241*d04ccbb3Scarlsonj 242*d04ccbb3Scarlsonj void 243*d04ccbb3Scarlsonj send_data_reply(ipc_action_t *ia, int error, dhcp_data_type_t type, 244*d04ccbb3Scarlsonj const void *buffer, size_t size) 245*d04ccbb3Scarlsonj { 246*d04ccbb3Scarlsonj dhcp_ipc_reply_t *reply; 247*d04ccbb3Scarlsonj int retval; 248*d04ccbb3Scarlsonj 249*d04ccbb3Scarlsonj if (ia->ia_fd == -1 || ia->ia_request == NULL) 250*d04ccbb3Scarlsonj return; 251*d04ccbb3Scarlsonj 252*d04ccbb3Scarlsonj reply = dhcp_ipc_alloc_reply(ia->ia_request, error, buffer, size, 253*d04ccbb3Scarlsonj type); 254*d04ccbb3Scarlsonj if (reply == NULL) { 255*d04ccbb3Scarlsonj dhcpmsg(MSG_ERR, "send_data_reply: cannot allocate reply"); 256*d04ccbb3Scarlsonj 257*d04ccbb3Scarlsonj } else if ((retval = dhcp_ipc_send_reply(ia->ia_fd, reply)) != 0) { 258*d04ccbb3Scarlsonj dhcpmsg(MSG_ERROR, "send_data_reply: dhcp_ipc_send_reply: %s", 259*d04ccbb3Scarlsonj dhcp_ipc_strerror(retval)); 260*d04ccbb3Scarlsonj } 261*d04ccbb3Scarlsonj 262*d04ccbb3Scarlsonj /* 263*d04ccbb3Scarlsonj * free the request since we've now used it to send our reply. 264*d04ccbb3Scarlsonj * we can also close the socket since the reply has been sent. 265*d04ccbb3Scarlsonj */ 266*d04ccbb3Scarlsonj 267*d04ccbb3Scarlsonj free(reply); 268*d04ccbb3Scarlsonj free(ia->ia_request); 269*d04ccbb3Scarlsonj if (ia->ia_eid != -1) 270*d04ccbb3Scarlsonj (void) iu_unregister_event(eh, ia->ia_eid, NULL); 271*d04ccbb3Scarlsonj (void) dhcp_ipc_close(ia->ia_fd); 272*d04ccbb3Scarlsonj ia->ia_request = NULL; 273*d04ccbb3Scarlsonj ia->ia_fd = -1; 274*d04ccbb3Scarlsonj ia->ia_eid = -1; 2757c478bd9Sstevel@tonic-gate } 276