1/* 2 * Copyright (c) 2010 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of Apple Inc. ("Apple") nor the names of its 16 * contributors may be used to endorse or promote products derived from 17 * this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 * 30 * Portions of this software have been released under the following terms: 31 * 32 * (c) Copyright 1989-1993 OPEN SOFTWARE FOUNDATION, INC. 33 * (c) Copyright 1989-1993 HEWLETT-PACKARD COMPANY 34 * (c) Copyright 1989-1993 DIGITAL EQUIPMENT CORPORATION 35 * 36 * To anyone who acknowledges that this file is provided "AS IS" 37 * without any express or implied warranty: 38 * permission to use, copy, modify, and distribute this file for any 39 * purpose is hereby granted without fee, provided that the above 40 * copyright notices and this notice appears in all source code copies, 41 * and that none of the names of Open Software Foundation, Inc., Hewlett- 42 * Packard Company or Digital Equipment Corporation be used 43 * in advertising or publicity pertaining to distribution of the software 44 * without specific, written prior permission. Neither Open Software 45 * Foundation, Inc., Hewlett-Packard Company nor Digital 46 * Equipment Corporation makes any representations about the suitability 47 * of this software for any purpose. 48 * 49 * Copyright (c) 2007, Novell, Inc. All rights reserved. 50 * Redistribution and use in source and binary forms, with or without 51 * modification, are permitted provided that the following conditions 52 * are met: 53 * 54 * 1. Redistributions of source code must retain the above copyright 55 * notice, this list of conditions and the following disclaimer. 56 * 2. Redistributions in binary form must reproduce the above copyright 57 * notice, this list of conditions and the following disclaimer in the 58 * documentation and/or other materials provided with the distribution. 59 * 3. Neither the name of Novell Inc. nor the names of its contributors 60 * may be used to endorse or promote products derived from this 61 * this software without specific prior written permission. 62 * 63 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 64 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 65 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 66 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY 67 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 68 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 69 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 70 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 71 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 72 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 73 * 74 * @APPLE_LICENSE_HEADER_END@ 75 */ 76 77/* 78** 79** NAME 80** 81** cnsm.c 82** 83** FACILITY: 84** 85** Remote Procedure Call (RPC) 86** 87** ABSTRACT: 88** 89** The NCA Connection Protocol State Machine Service 90** 91** 92*/ 93 94#include <commonp.h> /* Common declarations for all RPC runtime */ 95#include <com.h> /* Common communications services */ 96#include <comprot.h> /* Common protocol services */ 97#include <cnp.h> /* NCA Connection private declarations */ 98#include <cnsm.h> 99 100/***********************************************************************/ 101 102 103/* 104**++ 105** 106** ROUTINE NAME: rpc__cn_sm_init 107** 108** SCOPE: PRIVATE - declared in cnsm.h 109** 110** DESCRIPTION: 111** 112** The routine will be used to initialize a state machine control 113** block. Depending on the type of state machine it will be called 114** in various places. It basically just fills in the table pointers 115** given, sets the state to closed and initializes the event list. 116** 117** INPUTS: 118** 119** state_tbl The state table this state machine is to use. 120** action_tbl The action routine table this state machine 121** is to use. 122** tbl_id The identifier of the particular action table 123** we are storing in the control block. 124** 125** INPUTS/OUTPUTS: none 126** 127** OUTPUTS: 128** 129** sm The state machine control block which is to 130** be initialized. 131** 132** IMPLICIT INPUTS: none 133** 134** IMPLICIT OUTPUTS: none 135** 136** FUNCTION VALUE: none 137** 138** SIDE EFFECTS: none 139** 140**-- 141**/ 142 143PRIVATE void rpc__cn_sm_init 144( 145rpc_cn_sm_state_entry_p_t *state_tbl, 146rpc_cn_sm_action_fn_p_t action_tbl, 147rpc_cn_sm_ctlblk_p_t sm, 148unsigned32 tbl_id 149) 150{ 151 152 /* 153 * Put the pointers to the given tables into the state machine 154 * control block. 155 */ 156 sm->state_tbl = state_tbl; 157 sm->action_tbl = action_tbl; 158 159 /* 160 * Set the initial state in the state machine control block to 161 * "closed". 162 */ 163 sm->cur_state = RPC_C_SM_CLOSED_STATE; 164 165 /* 166 * Store the tbl_id in the controlblock and use it later 167 * to selectively bypass calls to the event evaluation 168 * routine, going directly to the action routines. 169 */ 170 sm->tbl_id = tbl_id; 171 172 /* 173 * Initialize the state machine control block event list. 174 */ 175 rpc__cn_sm_init_event_list(sm); 176} 177 178 179/* 180**++ 181** 182** ROUTINE NAME: rpc__cn_sm_init_event_list 183** 184** SCOPE: PRIVATE - declared in cnsm.h 185** 186** DESCRIPTION: 187** 188** This routine will initialize the event list contained in the 189** specified state machine control block. This routine is called as 190** part of initializing the state machine control block. 191** 192** INPUTS: none 193** 194** INPUTS/OUTPUTS: none 195** 196** OUTPUTS: 197** 198** sm The state machine control block containing 199** the event list to be initialized. 200** 201** IMPLICIT INPUTS: none 202** 203** IMPLICIT OUTPUTS: none 204** 205** FUNCTION VALUE: none 206** 207** SIDE EFFECTS: none 208** 209**-- 210**/ 211 212PRIVATE void rpc__cn_sm_init_event_list 213( 214 rpc_cn_sm_ctlblk_t *sm 215) 216{ 217 /* 218 * Set up the event list so that it's empty. This means the state 219 * must be set to "empty" and the head and tail indices must be 220 * zeroed. 221 */ 222 sm->event_list_state = RPC_C_CN_SM_EVENT_LIST_EMPTY; 223 sm->event_list_hindex = 0; 224 sm->event_list_tindex = 0; 225} 226 227 228/* 229**++ 230** 231** ROUTINE NAME: rpc__cn_sm_eval_event 232** 233** SCOPE: PRIVATE - declared in cnsm.h 234** 235** DESCRIPTION: 236** 237** This routine will be used to evaluate an event for the specified 238** state machine. It handles the main work of running a state 239** machine. It will look up either action or state transition for 240** events. The lookup will return either a state or action. 241** Distinguish between states and actions by numeric range. 242** 243** INPUTS: 244** 245** event_id The number of the event to be processed. 246** event_param The special event related parameter which is 247** to be passed to the predicate and action 248** routines for the processing of this event. 249** spc_struct A special parameter which is to be passed to 250** the predicate and action routines for the 251** processing of this event and any subsequent 252** events which are inserted on the event list. 253** 254** INPUTS/OUTPUTS: 255** 256** sm The state machine control block to be used 257** in processing this event. 258** 259** OUTPUTS: none 260** 261** IMPLICIT INPUTS: none 262** 263** IMPLICIT OUTPUTS: none 264** 265** FUNCTION VALUE: The status returned by the last action 266** routine invoked. 267** 268** SIDE EFFECTS: none 269** 270**-- 271**/ 272 273PRIVATE unsigned32 rpc__cn_sm_eval_event 274( 275 unsigned32 event_id, 276 dce_pointer_t event_parameter, 277 dce_pointer_t spc_struct, 278 rpc_cn_sm_ctlblk_t *sm 279) 280{ 281 rpc_cn_sm_event_entry_t next_event; 282 unsigned8 action_index; 283 boolean more_events; 284 rpc_cn_sm_state_entry_t *state_entry_p; 285 286 /* 287 * Initialize action status to ok. This allows state transitions 288 * which do not invoke action routines to signal normal completion. 289 */ 290 sm->action_status = rpc_s_ok; 291 292 /* 293 * Set up the first event to be evaluated using the input args. 294 */ 295 next_event.event_id = event_id; 296 next_event.event_param = event_parameter; 297 298 /* 299 * Process the first event and any events which get added. 300 */ 301 more_events = true; 302 while (more_events) 303 { 304 /* 305 * Pick up the state table entry to the current state. The 306 * value in the state table is going to be either a next 307 * state or an action. If it is an action, we take that 308 * action and within the action routine, update sm->cur_state. 309 * In cases where there is no action but there is a next state, 310 * we can just store the next state. We distinguish between 311 * actions and state by their numeric value. Next states are 312 * always greater than or equal to rpc_c_cn_statebase. 313 * Since states are also used to access an array entry, we need 314 * to subtract the value we added in order to distinguish it 315 * from an action routine, before we can access the array. 316 */ 317 state_entry_p = sm->state_tbl[(sm->cur_state - 318 RPC_C_CN_STATEBASE)]; 319 320 /* 321 * Look up the index of the action routine using the current 322 * state and the id of the event being processed. 323 */ 324 action_index = state_entry_p[(next_event.event_id - 325 RPC_C_CN_STATEBASE )].action; 326 327 /* 328 * If there is no action to take, just transition to the next 329 * state which is the value returned from the state table 330 * lookup (state_entry_p). 331 */ 332 if (action_index >= RPC_C_CN_STATEBASE) 333 { 334 sm->cur_state = action_index; 335 } 336 else 337 { 338 /* 339 * Call the action routine. The spc_struct and event_param 340 * and sm will be passed to the action routine. Note 341 * that sm is changed within the action routines. Each 342 * action routine will update sm->cur_state. 343 */ 344 sm->cur_event = next_event.event_id; 345 sm->action_status = 346 (*(sm->action_tbl[action_index])) 347 (spc_struct, next_event.event_param, sm); 348 } 349 350 /* 351 * Get the next event, if any, off the event list in the 352 * state machine control block. RPC_CN_SM_GET_NEXT_EVENT 353 * will set more_events to true or false depending on 354 * whether there are more events to process. 355 */ 356 RPC_CN_SM_GET_NEXT_EVENT (sm, &next_event, more_events); 357 } 358 return (sm->action_status); 359} 360 361 362/* 363**++ 364** 365** ROUTINE NAME: rpc__cn_sm_insert_event 366** 367** SCOPE: PRIVATE - declared in cnsm.h 368** 369** DESCRIPTION: 370** 371** This routine inserts a new event entry on the state machine 372** control block event list. If the list is full the event can't be 373** inserted and false will be returned. 374** 375** INPUTS: 376** 377** event The event entry being inserted. 378** 379** INPUTS/OUTPUTS: 380** 381** sm The state machine control block containing 382** the event list. 383** 384** OUTPUTS: 385** 386** IMPLICIT INPUTS: none 387** 388** IMPLICIT OUTPUTS: none 389** 390** FUNCTION VALUE: none 391** 392** SIDE EFFECTS: none 393** 394**-- 395**/ 396 397PRIVATE void rpc__cn_sm_insert_event 398( 399 rpc_cn_sm_event_entry_p_t event, 400 rpc_cn_sm_ctlblk_t *sm 401) 402{ 403#ifdef DEBUG 404 /* 405 * Check whether the event list is full. This condition occurs 406 * when the head and tail indices are equal and the state 407 * indicates the list is not empty. 408 */ 409 if ((sm->event_list_hindex == sm->event_list_tindex) && 410 (sm->event_list_state != RPC_C_CN_SM_EVENT_LIST_EMPTY)) 411 { 412 /* 413 * rpc_m_eventlist_full 414 * "(%s) Event list full" 415 */ 416 rpc_dce_svc_printf ( 417 __FILE__, __LINE__, 418 "%s", 419 rpc_svc_cn_state, 420 svc_c_sev_fatal | svc_c_action_abort, 421 rpc_m_eventlist_full, 422 "rpc__cn_sm_insert_event" ); 423 } 424#endif 425 426 /* 427 * There's room on the event list. Add the new entry to the tail 428 * of the list. 429 */ 430 sm->event_list[sm->event_list_tindex].event_id = event->event_id; 431 sm->event_list[sm->event_list_tindex].event_param = event->event_param; 432 433 /* 434 * Add the event to the event list by incrementing the tail 435 * index and checking for wraparound. Also set the state of the 436 * event list to non-empty. 437 */ 438 sm->event_list_tindex = (sm->event_list_tindex + 1) & 439 (RPC_C_CN_SM_EVENT_LIST_MAX_ENTRIES - 1); 440 sm->event_list_state = ~RPC_C_CN_SM_EVENT_LIST_EMPTY; 441} 442