kernel: Sync ACPICA with Intel's version 20140424.
[dragonfly.git] / usr.sbin / atm / scspd / scsp_hfsm.c
1 /*
2  *
3  * ===================================
4  * HARP  |  Host ATM Research Platform
5  * ===================================
6  *
7  *
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.
12  *
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.
20  *
21  * Copyright 1994-1998 Network Computing Services, Inc.
22  *
23  * Copies of this Software may be made, however, the above copyright
24  * notice must be reproduced on all copies.
25  *
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.5 2007/11/25 01:28:23 swildner Exp $
28  */
29
30
31 /*
32  * Server Cache Synchronization Protocol (SCSP) Support
33  * ----------------------------------------------------
34  *
35  * HELLO finite state machine
36  *
37  */
38
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>
50   
51 #include <errno.h>
52 #include <libatm.h>
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <syslog.h>
56
57 #include "scsp_msg.h"
58 #include "scsp_if.h"
59 #include "scsp_var.h"
60
61 /*
62  * HELLO FSM actions
63  */
64 #define HELLO_ACTION_CNT        7
65 int     scsp_hello_act_00(Scsp_dcs *, Scsp_msg *);
66 int     scsp_hello_act_01(Scsp_dcs *, Scsp_msg *);
67 int     scsp_hello_act_02(Scsp_dcs *, Scsp_msg *);
68 int     scsp_hello_act_03(Scsp_dcs *, Scsp_msg *);
69 int     scsp_hello_act_04(Scsp_dcs *, Scsp_msg *);
70 int     scsp_hello_act_05(Scsp_dcs *, Scsp_msg *);
71 int     scsp_hello_act_06(Scsp_dcs *, Scsp_msg *);
72
73 static int (*scsp_action_vector[HELLO_ACTION_CNT])() = {
74         scsp_hello_act_00,
75         scsp_hello_act_01,
76         scsp_hello_act_02,
77         scsp_hello_act_03,
78         scsp_hello_act_04,
79         scsp_hello_act_05,
80         scsp_hello_act_06
81 };
82
83 /*
84  * HELLO FSM state table
85  */
86 static int hello_state_table[SCSP_HFSM_EVENT_CNT][SCSP_HFSM_STATE_CNT] = {
87         /* 0  1  2  3                */
88         {  1, 1, 1, 1 },        /* 0 */
89         {  0, 2, 2, 2 },        /* 1 */
90         {  0, 3, 3, 3 },        /* 2 */
91         {  0, 0, 4, 4 },        /* 3 */
92         {  0, 5, 5, 6 },        /* 4 */
93 };
94
95 /*
96  * HELLO finite state machine
97  *
98  * Arguments:
99  *      dcsp    pointer to a DCS control block for the neighbor
100  *      event   the event which has occurred
101  *      msg     pointer to received message, if there is one
102  *
103  * Returns:
104  *      0       success
105  *      errno   error encountered
106  *
107  */
108 int
109 scsp_hfsm(Scsp_dcs *dcsp, int event, Scsp_msg *msg)
110 {
111         int     action, rc, state;
112
113         /*
114          * Select an action from the state table
115          */
116         state = dcsp->sd_hello_state;
117         action = hello_state_table[event][state];
118         if (scsp_trace_mode & SCSP_TRACE_HFSM) {
119                 scsp_trace("HFSM: state=%d, event=%d, action=%d\n",
120                                 state, event, action);
121         }
122         if (action >= HELLO_ACTION_CNT || action <= 0) {
123                 scsp_log(LOG_ERR, "Hello FSM--invalid action %d; state=%d, event=%d",
124                                 action, dcsp->sd_hello_state, event);
125                 abort();
126         }
127
128         /*
129          * Perform the selected action
130          */
131         rc = scsp_action_vector[action](dcsp, msg);
132
133         return(rc);
134 }
135
136
137 /*
138  * HELLO finite state machine action 0
139  * Unexpected action -- log an error message
140  *
141  * Arguments:
142  *      dcsp    pointer to DCS control block
143  *      msg     pointer to received message (ignored)
144  *
145  * Returns:
146  *      EOPNOTSUPP      always returns EOPNOTSUPP
147  *
148  */
149 int
150 scsp_hello_act_00(Scsp_dcs *dcsp, Scsp_msg *msg)
151 {
152         scsp_log(LOG_ERR, "Hello FSM error--unexpected action, state=%d",
153                         dcsp->sd_hello_state);
154         return(EOPNOTSUPP);
155 }
156
157
158 /*
159  * HELLO finite state machine action 1
160  * VCC open -- send HELLO message, start hello timer, go to Waiting
161  * state
162  *
163  * Arguments:
164  *      dcsp    pointer to DCS control block
165  *      msg     pointer to received message (ignored)
166  *
167  * Returns:
168  *      0       success
169  *      errno   error encountered
170  *
171  */
172 int
173 scsp_hello_act_01(Scsp_dcs *dcsp, Scsp_msg *msg)
174 {
175         int             rc;
176
177         /*
178          * Cancel the VCC open timer if it's running
179          */
180         HARP_CANCEL(&dcsp->sd_open_t);
181
182         /*
183          * Go to Waiting state
184          */
185         dcsp->sd_hello_state = SCSP_HFSM_WAITING;
186
187         /*
188          * Send a Hello message
189          */
190         rc = scsp_send_hello(dcsp);
191         if (rc == 0) {
192                 /*
193                  * Success--start the Hello timer
194                  */
195                 HARP_TIMER(&dcsp->sd_hello_h_t, SCSP_HELLO_Interval,
196                                 scsp_hello_timeout);
197         }
198
199         return(rc);
200 }
201
202
203 /*
204  * HELLO finite state machine action 2
205  * VCC closed -- notify CA FSM, go to Down state, try to re-open VCC
206  *
207  * Arguments:
208  *      dcsp    pointer to DCS control block
209  *      msg     pointer to received message (ignored)
210  *
211  * Returns:
212  *      0       success
213  *      errno   error encountered
214  *
215  */
216 int
217 scsp_hello_act_02(Scsp_dcs *dcsp, Scsp_msg *msg)
218 {
219         int             rc;
220
221         /*
222          * Cancel any current timers
223          */
224         HARP_CANCEL(&dcsp->sd_hello_h_t);
225         HARP_CANCEL(&dcsp->sd_hello_rcv_t);
226
227         /*
228          * Log the loss of the VCC
229          */
230         if (dcsp->sd_hello_state > SCSP_HFSM_WAITING) {
231                 scsp_log(LOG_ERR, "VC to %s closed",
232                                 format_atm_addr(&dcsp->sd_addr));
233         }
234
235         /*
236          * Tell the CA FSM that the conection to the DCS is lost
237          */
238         rc = scsp_cafsm(dcsp, SCSP_CAFSM_HELLO_DOWN, NULL);
239
240         /*
241          * Go to Down state
242          */
243         dcsp->sd_hello_state = SCSP_HFSM_DOWN;
244
245         /*
246          * If our ID is lower than the DCS's, wait a second before
247          * trying to connect.  This should keep both of us from
248          * trying to connect at the same time, resulting in two
249          * VCCs being open.
250          */
251         if (scsp_cmp_id(&dcsp->sd_server->ss_lsid,
252                         &dcsp->sd_dcsid) < 0) {
253                 /*
254                  * Our ID is lower--start the VCC open timer for one
255                  * second so we'll try to open the VCC if the DCS
256                  * doesn't do it by then
257                  */
258                 HARP_TIMER(&dcsp->sd_open_t, 1, scsp_open_timeout);
259         } else {
260                 /*
261                  * Our ID is higher--try to reopen the VCC immediately
262                  */
263                 if (scsp_dcs_connect(dcsp)) {
264                         /*
265                          * Conncect failed -- set a timer and try
266                          * again later
267                          */
268                         HARP_TIMER(&dcsp->sd_open_t, SCSP_Open_Interval,
269                                         scsp_open_timeout);
270                 }
271         }
272
273         return(0);
274 }
275
276
277 /*
278  * HELLO finite state machine action 3
279  * Hello timer expired -- send HELLO message, restart hello timer
280  *
281  * Arguments:
282  *      dcsp    pointer to DCS control block
283  *      msg     pointer to received message (ignored)
284  *
285  * Returns:
286  *      0       success
287  *      errno   error encountered
288  *
289  */
290 int
291 scsp_hello_act_03(Scsp_dcs *dcsp, Scsp_msg *msg)
292 {
293         int             rc;
294
295         /*
296          * Send a Hello message
297          */
298         rc = scsp_send_hello(dcsp);
299         if (rc == 0) {
300                 /*
301                  * Success--restart the Hello timer
302                  */
303                 HARP_TIMER(&dcsp->sd_hello_h_t, SCSP_HELLO_Interval,
304                                 scsp_hello_timeout);
305         }
306
307         return(rc);
308 }
309
310
311 /*
312  * HELLO finite state machine action 4
313  * Receive timer expired -- if we haven't received any Hellos, notify
314  * CA FSM and go to Waiting state;  if we've received Hellos, but we
315  * weren't in the receiver ID list, go to Unidirectional state
316  *
317  * Arguments:
318  *      dcsp    pointer to DCS control block
319  *      msg     pointer to received message (ignored)
320  *
321  * Returns:
322  *      0       success
323  *      errno   error encountered
324  *
325  */
326 int
327 scsp_hello_act_04(Scsp_dcs *dcsp, Scsp_msg *msg)
328 {
329         int     rc = 0;
330
331         /*
332          * Check whether we'ver received any Hellos lately
333          */
334         if (dcsp->sd_hello_rcvd) {
335                 /*
336                  * We've had Hellos since the receive timer was
337                  * started--go to Unidirectional state
338                  */
339                 dcsp->sd_hello_rcvd = 0;
340                 dcsp->sd_hello_state = SCSP_HFSM_UNI_DIR;
341         } else {
342                 /*
343                  * We haven't seen any Hellos at all from the DCS in
344                  * hello_interval * dead_factor seconds--go to Waiting
345                  * state
346                  */
347                 dcsp->sd_hello_state = SCSP_HFSM_WAITING;
348         }
349
350         /*
351          * Notify the CA FSM
352          */
353         rc = scsp_cafsm(dcsp, SCSP_CAFSM_HELLO_DOWN, NULL);
354
355         return(rc);
356 }
357
358
359 /*
360  * HELLO finite state machine action 5
361  * Message received -- Ignore all but HELLO messages;  if local server
362  * is in receiver list, notify CA FSM and go to Bidirectional state;
363  * otherwise, go to Unidirectional state
364  *
365  * Arguments:
366  *      dcsp    pointer to DCS control block
367  *      msg     pointer to received message
368  *
369  * Returns:
370  *      0       success
371  *      errno   error encountered
372  *
373  */
374 int
375 scsp_hello_act_05(Scsp_dcs *dcsp, Scsp_msg *msg)
376 {
377         int     rc;
378         Scsp_id *ridp;
379
380         /*
381          * Null message pointer means message decode failed, so
382          * message must have been invalid.  Go to Waiting state.
383          */
384         if (msg == NULL) {
385                 dcsp->sd_hello_state = SCSP_HFSM_WAITING;
386                 HARP_CANCEL(&dcsp->sd_hello_rcv_t);
387                 return(0);
388         }
389
390         /*
391          * Ignore the message if it isn't a Hello
392          */
393         if (msg->sc_msg_type != SCSP_HELLO_MSG) {
394                 return(0);
395         }
396
397         /*
398          * Save relevant information about DCS, but don't let him give
399          * us zero for timeout values
400          */
401         if (msg->sc_hello->hello_int) {
402                 dcsp->sd_hello_int = msg->sc_hello->hello_int;
403         } else {
404                 dcsp->sd_hello_int = 1;
405         }
406         if (msg->sc_hello->dead_factor) {
407                 dcsp->sd_hello_df = msg->sc_hello->dead_factor;
408         } else {
409                 dcsp->sd_hello_df = 1;
410         }
411         dcsp->sd_dcsid = msg->sc_hello->hello_mcp.sid;
412
413         /*
414          * Check the message for the local server's ID
415          */
416         for (ridp = &msg->sc_hello->hello_mcp.rid;
417                         ridp;
418                         ridp = ridp->next) {
419                 if (scsp_cmp_id(&dcsp->sd_server->ss_lsid, ridp) == 0) {
420                         /*
421                          * Cancel and restart the receive timer
422                          */
423                         HARP_CANCEL(&dcsp->sd_hello_rcv_t);
424                         HARP_TIMER(&dcsp->sd_hello_rcv_t,
425                                         dcsp->sd_hello_int * dcsp->sd_hello_df,
426                                         scsp_hello_rcv_timeout);
427
428                         /*
429                          * Go to Bidirectional state and notify the
430                          * CA FSM that the connection is up
431                          */
432                         dcsp->sd_hello_state = SCSP_HFSM_BI_DIR;
433                         rc = scsp_cafsm(dcsp,
434                                         SCSP_CAFSM_HELLO_UP,
435                                         NULL);
436                         return(rc);
437                 }
438         }
439
440         /*
441          * We weren't in the receiver ID list, so go to
442          * Unidirectional state
443          */
444         dcsp->sd_hello_state = SCSP_HFSM_UNI_DIR;
445
446         return(0);
447 }
448
449
450 /*
451  * HELLO finite state machine action 6
452  * Message received -- if message is not a HELLO, pass it to the CA
453  * FSM;  otherwise, if local server is not in receiver list, notify
454  * CA FSM and go to Unidirectional state
455  *
456  * Arguments:
457  *      dcsp    pointer to DCS control block
458  *      msg     pointer to received message
459  *
460  * Returns:
461  *      0       success
462  *      errno   error encountered
463  *
464  */
465 int
466 scsp_hello_act_06(Scsp_dcs *dcsp, Scsp_msg *msg)
467 {
468         int     rc = 0, rcv_found;
469         Scsp_id *ridp;
470
471         /*
472          * Null message pointer means message decode failed, so
473          * message must have been invalid.  Go to Waiting state.
474          */
475         if (msg == NULL) {
476                 HARP_CANCEL(&dcsp->sd_hello_rcv_t);
477                 dcsp->sd_hello_state = SCSP_HFSM_WAITING;
478                 rc = scsp_cafsm(dcsp, SCSP_CAFSM_HELLO_DOWN, NULL);
479                 return(rc);
480         }
481
482         /*
483          * Process the message depending on its type
484          */
485         switch(msg->sc_msg_type) {
486         case SCSP_CA_MSG:
487                 rc = scsp_cafsm(dcsp, SCSP_CAFSM_CA_MSG, (void *)msg);
488                 break;
489         case SCSP_CSU_REQ_MSG:
490                 rc = scsp_cafsm(dcsp, SCSP_CAFSM_CSU_REQ, (void *)msg);
491                 break;
492         case SCSP_CSU_REPLY_MSG:
493                 rc = scsp_cafsm(dcsp, SCSP_CAFSM_CSU_REPLY,
494                                 (void *)msg);
495                 break;
496         case SCSP_CSUS_MSG:
497                 rc = scsp_cafsm(dcsp, SCSP_CAFSM_CSUS_MSG, (void *)msg);
498                 break;
499         case SCSP_HELLO_MSG:
500                 /*
501                  * Make sure DCS info is consistent.  The sender ID,
502                  * family ID, protocol ID, and server group ID are
503                  * checked.
504                  */
505                 if (scsp_cmp_id(&msg->sc_hello->hello_mcp.sid,
506                                         &dcsp->sd_dcsid) ||
507                                 (msg->sc_hello->family_id !=
508                                         dcsp->sd_server->ss_fid) ||
509                                 (msg->sc_hello->hello_mcp.pid !=
510                                         dcsp->sd_server->ss_pid) ||
511                                 (msg->sc_hello->hello_mcp.sgid !=
512                                         dcsp->sd_server->ss_sgid)) {
513                         /*
514                          * Bad info--revert to waiting state
515                          */
516                         HARP_CANCEL(&dcsp->sd_hello_rcv_t);
517                         dcsp->sd_hello_state = SCSP_HFSM_WAITING;
518                         rc = scsp_cafsm(dcsp,
519                                         SCSP_CAFSM_HELLO_DOWN,
520                                         NULL);
521                         return(rc);
522                 }
523
524                 /*
525                  * Mark the arrival of the Hello message
526                  */
527                 dcsp->sd_hello_rcvd = 1;
528
529                 /*
530                  * Check the message for the local server's ID
531                  */
532                 for (ridp = &msg->sc_hello->hello_mcp.rid,
533                                         rcv_found = 0;
534                                 ridp;
535                                 ridp = ridp->next) {
536                         rcv_found = (scsp_cmp_id(ridp,
537                                 &dcsp->sd_server->ss_lsid) == 0);
538                 }
539
540                 if (rcv_found) {
541                         /*
542                          * The LS ID was in the list of receiver IDs--
543                          * Reset the Hello receive timer
544                          */
545                         dcsp->sd_hello_rcvd = 0;
546                         HARP_CANCEL(&dcsp->sd_hello_rcv_t);
547                         HARP_TIMER(&dcsp->sd_hello_rcv_t,
548                                         dcsp->sd_hello_int *
549                                                 dcsp->sd_hello_df,
550                                         scsp_hello_rcv_timeout);
551                 }
552                 break;
553         }
554
555         return(rc);
556 }