More minor IPI work.
[dragonfly/vkernel-mp.git] / usr.sbin / atm / scspd / scsp_hfsm.c
blob36c210b616b9db0443f8732b8ba86e6945013c20
1 /*
3 * ===================================
4 * HARP | Host ATM Research Platform
5 * ===================================
8 * This Host ATM Research Platform ("HARP") file (the "Software") is
9 * made available by Network Computing Services, Inc. ("NetworkCS")
10 * "AS IS". NetworkCS does not provide maintenance, improvements or
11 * support of any kind.
13 * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
14 * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
15 * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
16 * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
17 * In no event shall NetworkCS be responsible for any damages, including
18 * but not limited to consequential damages, arising from or relating to
19 * any use of the Software or related support.
21 * Copyright 1994-1998 Network Computing Services, Inc.
23 * Copies of this Software may be made, however, the above copyright
24 * notice must be reproduced on all copies.
26 * @(#) $FreeBSD: src/usr.sbin/atm/scspd/scsp_hfsm.c,v 1.3 1999/08/28 01:15:33 peter Exp $
27 * @(#) $DragonFly: src/usr.sbin/atm/scspd/scsp_hfsm.c,v 1.4 2003/11/15 21:33:43 eirikn Exp $
32 * Server Cache Synchronization Protocol (SCSP) Support
33 * ----------------------------------------------------
35 * HELLO finite state machine
39 #include <sys/types.h>
40 #include <sys/param.h>
41 #include <sys/socket.h>
42 #include <net/if.h>
43 #include <netinet/in.h>
44 #include <netatm/queue.h>
45 #include <netatm/atm.h>
46 #include <netatm/atm_if.h>
47 #include <netatm/atm_sap.h>
48 #include <netatm/atm_sys.h>
49 #include <netatm/atm_ioctl.h>
51 #include <errno.h>
52 #include <libatm.h>
53 #include <stdio.h>
54 #include <syslog.h>
56 #include "scsp_msg.h"
57 #include "scsp_if.h"
58 #include "scsp_var.h"
61 * HELLO FSM actions
63 #define HELLO_ACTION_CNT 7
64 int scsp_hello_act_00(Scsp_dcs *, Scsp_msg *);
65 int scsp_hello_act_01(Scsp_dcs *, Scsp_msg *);
66 int scsp_hello_act_02(Scsp_dcs *, Scsp_msg *);
67 int scsp_hello_act_03(Scsp_dcs *, Scsp_msg *);
68 int scsp_hello_act_04(Scsp_dcs *, Scsp_msg *);
69 int scsp_hello_act_05(Scsp_dcs *, Scsp_msg *);
70 int scsp_hello_act_06(Scsp_dcs *, Scsp_msg *);
72 static int (*scsp_action_vector[HELLO_ACTION_CNT])() = {
73 scsp_hello_act_00,
74 scsp_hello_act_01,
75 scsp_hello_act_02,
76 scsp_hello_act_03,
77 scsp_hello_act_04,
78 scsp_hello_act_05,
79 scsp_hello_act_06
83 * HELLO FSM state table
85 static int hello_state_table[SCSP_HFSM_EVENT_CNT][SCSP_HFSM_STATE_CNT] = {
86 /* 0 1 2 3 */
87 { 1, 1, 1, 1 }, /* 0 */
88 { 0, 2, 2, 2 }, /* 1 */
89 { 0, 3, 3, 3 }, /* 2 */
90 { 0, 0, 4, 4 }, /* 3 */
91 { 0, 5, 5, 6 }, /* 4 */
95 * HELLO finite state machine
97 * Arguments:
98 * dcsp pointer to a DCS control block for the neighbor
99 * event the event which has occurred
100 * msg pointer to received message, if there is one
102 * Returns:
103 * 0 success
104 * errno error encountered
108 scsp_hfsm(Scsp_dcs *dcsp, int event, Scsp_msg *msg)
110 int action, rc, state;
113 * Select an action from the state table
115 state = dcsp->sd_hello_state;
116 action = hello_state_table[event][state];
117 if (scsp_trace_mode & SCSP_TRACE_HFSM) {
118 scsp_trace("HFSM: state=%d, event=%d, action=%d\n",
119 state, event, action);
121 if (action >= HELLO_ACTION_CNT || action <= 0) {
122 scsp_log(LOG_ERR, "Hello FSM--invalid action %d; state=%d, event=%d",
123 action, dcsp->sd_hello_state, event);
124 abort();
128 * Perform the selected action
130 rc = scsp_action_vector[action](dcsp, msg);
132 return(rc);
137 * HELLO finite state machine action 0
138 * Unexpected action -- log an error message
140 * Arguments:
141 * dcsp pointer to DCS control block
142 * msg pointer to received message (ignored)
144 * Returns:
145 * EOPNOTSUPP always returns EOPNOTSUPP
149 scsp_hello_act_00(Scsp_dcs *dcsp, Scsp_msg *msg)
151 scsp_log(LOG_ERR, "Hello FSM error--unexpected action, state=%d",
152 dcsp->sd_hello_state);
153 return(EOPNOTSUPP);
158 * HELLO finite state machine action 1
159 * VCC open -- send HELLO message, start hello timer, go to Waiting
160 * state
162 * Arguments:
163 * dcsp pointer to DCS control block
164 * msg pointer to received message (ignored)
166 * Returns:
167 * 0 success
168 * errno error encountered
172 scsp_hello_act_01(Scsp_dcs *dcsp, Scsp_msg *msg)
174 int rc;
177 * Cancel the VCC open timer if it's running
179 HARP_CANCEL(&dcsp->sd_open_t);
182 * Go to Waiting state
184 dcsp->sd_hello_state = SCSP_HFSM_WAITING;
187 * Send a Hello message
189 rc = scsp_send_hello(dcsp);
190 if (rc == 0) {
192 * Success--start the Hello timer
194 HARP_TIMER(&dcsp->sd_hello_h_t, SCSP_HELLO_Interval,
195 scsp_hello_timeout);
198 return(rc);
203 * HELLO finite state machine action 2
204 * VCC closed -- notify CA FSM, go to Down state, try to re-open VCC
206 * Arguments:
207 * dcsp pointer to DCS control block
208 * msg pointer to received message (ignored)
210 * Returns:
211 * 0 success
212 * errno error encountered
216 scsp_hello_act_02(Scsp_dcs *dcsp, Scsp_msg *msg)
218 int rc;
221 * Cancel any current timers
223 HARP_CANCEL(&dcsp->sd_hello_h_t);
224 HARP_CANCEL(&dcsp->sd_hello_rcv_t);
227 * Log the loss of the VCC
229 if (dcsp->sd_hello_state > SCSP_HFSM_WAITING) {
230 scsp_log(LOG_ERR, "VC to %s closed",
231 format_atm_addr(&dcsp->sd_addr));
235 * Tell the CA FSM that the conection to the DCS is lost
237 rc = scsp_cafsm(dcsp, SCSP_CAFSM_HELLO_DOWN, (void *)0);
240 * Go to Down state
242 dcsp->sd_hello_state = SCSP_HFSM_DOWN;
245 * If our ID is lower than the DCS's, wait a second before
246 * trying to connect. This should keep both of us from
247 * trying to connect at the same time, resulting in two
248 * VCCs being open.
250 if (scsp_cmp_id(&dcsp->sd_server->ss_lsid,
251 &dcsp->sd_dcsid) < 0) {
253 * Our ID is lower--start the VCC open timer for one
254 * second so we'll try to open the VCC if the DCS
255 * doesn't do it by then
257 HARP_TIMER(&dcsp->sd_open_t, 1, scsp_open_timeout);
258 } else {
260 * Our ID is higher--try to reopen the VCC immediately
262 if (scsp_dcs_connect(dcsp)) {
264 * Conncect failed -- set a timer and try
265 * again later
267 HARP_TIMER(&dcsp->sd_open_t, SCSP_Open_Interval,
268 scsp_open_timeout);
272 return(0);
277 * HELLO finite state machine action 3
278 * Hello timer expired -- send HELLO message, restart hello timer
280 * Arguments:
281 * dcsp pointer to DCS control block
282 * msg pointer to received message (ignored)
284 * Returns:
285 * 0 success
286 * errno error encountered
290 scsp_hello_act_03(Scsp_dcs *dcsp, Scsp_msg *msg)
292 int rc;
295 * Send a Hello message
297 rc = scsp_send_hello(dcsp);
298 if (rc == 0) {
300 * Success--restart the Hello timer
302 HARP_TIMER(&dcsp->sd_hello_h_t, SCSP_HELLO_Interval,
303 scsp_hello_timeout);
306 return(rc);
311 * HELLO finite state machine action 4
312 * Receive timer expired -- if we haven't received any Hellos, notify
313 * CA FSM and go to Waiting state; if we've received Hellos, but we
314 * weren't in the receiver ID list, go to Unidirectional state
316 * Arguments:
317 * dcsp pointer to DCS control block
318 * msg pointer to received message (ignored)
320 * Returns:
321 * 0 success
322 * errno error encountered
326 scsp_hello_act_04(Scsp_dcs *dcsp, Scsp_msg *msg)
328 int rc = 0;
331 * Check whether we'ver received any Hellos lately
333 if (dcsp->sd_hello_rcvd) {
335 * We've had Hellos since the receive timer was
336 * started--go to Unidirectional state
338 dcsp->sd_hello_rcvd = 0;
339 dcsp->sd_hello_state = SCSP_HFSM_UNI_DIR;
340 } else {
342 * We haven't seen any Hellos at all from the DCS in
343 * hello_interval * dead_factor seconds--go to Waiting
344 * state
346 dcsp->sd_hello_state = SCSP_HFSM_WAITING;
350 * Notify the CA FSM
352 rc = scsp_cafsm(dcsp, SCSP_CAFSM_HELLO_DOWN, (void *)0);
354 return(rc);
359 * HELLO finite state machine action 5
360 * Message received -- Ignore all but HELLO messages; if local server
361 * is in receiver list, notify CA FSM and go to Bidirectional state;
362 * otherwise, go to Unidirectional state
364 * Arguments:
365 * dcsp pointer to DCS control block
366 * msg pointer to received message
368 * Returns:
369 * 0 success
370 * errno error encountered
374 scsp_hello_act_05(Scsp_dcs *dcsp, Scsp_msg *msg)
376 int rc;
377 Scsp_id *ridp;
380 * Null message pointer means message decode failed, so
381 * message must have been invalid. Go to Waiting state.
383 if (msg == (Scsp_msg *)0) {
384 dcsp->sd_hello_state = SCSP_HFSM_WAITING;
385 HARP_CANCEL(&dcsp->sd_hello_rcv_t);
386 return(0);
390 * Ignore the message if it isn't a Hello
392 if (msg->sc_msg_type != SCSP_HELLO_MSG) {
393 return(0);
397 * Save relevant information about DCS, but don't let him give
398 * us zero for timeout values
400 if (msg->sc_hello->hello_int) {
401 dcsp->sd_hello_int = msg->sc_hello->hello_int;
402 } else {
403 dcsp->sd_hello_int = 1;
405 if (msg->sc_hello->dead_factor) {
406 dcsp->sd_hello_df = msg->sc_hello->dead_factor;
407 } else {
408 dcsp->sd_hello_df = 1;
410 dcsp->sd_dcsid = msg->sc_hello->hello_mcp.sid;
413 * Check the message for the local server's ID
415 for (ridp = &msg->sc_hello->hello_mcp.rid;
416 ridp;
417 ridp = ridp->next) {
418 if (scsp_cmp_id(&dcsp->sd_server->ss_lsid, ridp) == 0) {
420 * Cancel and restart the receive timer
422 HARP_CANCEL(&dcsp->sd_hello_rcv_t);
423 HARP_TIMER(&dcsp->sd_hello_rcv_t,
424 dcsp->sd_hello_int * dcsp->sd_hello_df,
425 scsp_hello_rcv_timeout);
428 * Go to Bidirectional state and notify the
429 * CA FSM that the connection is up
431 dcsp->sd_hello_state = SCSP_HFSM_BI_DIR;
432 rc = scsp_cafsm(dcsp,
433 SCSP_CAFSM_HELLO_UP,
434 (void *)0);
435 return(rc);
440 * We weren't in the receiver ID list, so go to
441 * Unidirectional state
443 dcsp->sd_hello_state = SCSP_HFSM_UNI_DIR;
445 return(0);
450 * HELLO finite state machine action 6
451 * Message received -- if message is not a HELLO, pass it to the CA
452 * FSM; otherwise, if local server is not in receiver list, notify
453 * CA FSM and go to Unidirectional state
455 * Arguments:
456 * dcsp pointer to DCS control block
457 * msg pointer to received message
459 * Returns:
460 * 0 success
461 * errno error encountered
465 scsp_hello_act_06(Scsp_dcs *dcsp, Scsp_msg *msg)
467 int rc = 0, rcv_found;
468 Scsp_id *ridp;
471 * Null message pointer means message decode failed, so
472 * message must have been invalid. Go to Waiting state.
474 if (msg == (Scsp_msg *)0) {
475 HARP_CANCEL(&dcsp->sd_hello_rcv_t);
476 dcsp->sd_hello_state = SCSP_HFSM_WAITING;
477 rc = scsp_cafsm(dcsp, SCSP_CAFSM_HELLO_DOWN, (void *)0);
478 return(rc);
482 * Process the message depending on its type
484 switch(msg->sc_msg_type) {
485 case SCSP_CA_MSG:
486 rc = scsp_cafsm(dcsp, SCSP_CAFSM_CA_MSG, (void *)msg);
487 break;
488 case SCSP_CSU_REQ_MSG:
489 rc = scsp_cafsm(dcsp, SCSP_CAFSM_CSU_REQ, (void *)msg);
490 break;
491 case SCSP_CSU_REPLY_MSG:
492 rc = scsp_cafsm(dcsp, SCSP_CAFSM_CSU_REPLY,
493 (void *)msg);
494 break;
495 case SCSP_CSUS_MSG:
496 rc = scsp_cafsm(dcsp, SCSP_CAFSM_CSUS_MSG, (void *)msg);
497 break;
498 case SCSP_HELLO_MSG:
500 * Make sure DCS info is consistent. The sender ID,
501 * family ID, protocol ID, and server group ID are
502 * checked.
504 if (scsp_cmp_id(&msg->sc_hello->hello_mcp.sid,
505 &dcsp->sd_dcsid) ||
506 (msg->sc_hello->family_id !=
507 dcsp->sd_server->ss_fid) ||
508 (msg->sc_hello->hello_mcp.pid !=
509 dcsp->sd_server->ss_pid) ||
510 (msg->sc_hello->hello_mcp.sgid !=
511 dcsp->sd_server->ss_sgid)) {
513 * Bad info--revert to waiting state
515 HARP_CANCEL(&dcsp->sd_hello_rcv_t);
516 dcsp->sd_hello_state = SCSP_HFSM_WAITING;
517 rc = scsp_cafsm(dcsp,
518 SCSP_CAFSM_HELLO_DOWN,
519 (void *)0);
520 return(rc);
524 * Mark the arrival of the Hello message
526 dcsp->sd_hello_rcvd = 1;
529 * Check the message for the local server's ID
531 for (ridp = &msg->sc_hello->hello_mcp.rid,
532 rcv_found = 0;
533 ridp;
534 ridp = ridp->next) {
535 rcv_found = (scsp_cmp_id(ridp,
536 &dcsp->sd_server->ss_lsid) == 0);
539 if (rcv_found) {
541 * The LS ID was in the list of receiver IDs--
542 * Reset the Hello receive timer
544 dcsp->sd_hello_rcvd = 0;
545 HARP_CANCEL(&dcsp->sd_hello_rcv_t);
546 HARP_TIMER(&dcsp->sd_hello_rcv_t,
547 dcsp->sd_hello_int *
548 dcsp->sd_hello_df,
549 scsp_hello_rcv_timeout);
551 break;
554 return(rc);