Merge from vendor branch BZIP:
[dragonfly.git] / usr.sbin / atm / scspd / scsp_cafsm.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_cafsm.c,v 1.3 1999/08/28 01:15:32 peter Exp $
27  *      @(#) $DragonFly: src/usr.sbin/atm/scspd/scsp_cafsm.c,v 1.5 2004/12/18 22:48:02 swildner Exp $
28  */
29
30
31 /*
32  * Server Cache Synchronization Protocol (SCSP) Support
33  * ----------------------------------------------------
34  *
35  * Cache Alignment 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/port.h>
45 #include <netatm/queue.h>
46 #include <netatm/atm.h>
47 #include <netatm/atm_if.h>
48 #include <netatm/atm_sap.h>
49 #include <netatm/atm_sys.h>
50 #include <netatm/atm_ioctl.h>
51
52 #include <errno.h>
53 #include <libatm.h>
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <string.h>
57 #include <syslog.h>
58
59 #include "scsp_msg.h"
60 #include "scsp_if.h"
61 #include "scsp_var.h"
62
63 /*
64  * CA FSM actions
65  */
66 #define CA_ACTION_CNT   20
67 int     scsp_ca_act_00(Scsp_dcs *, void *);
68 int     scsp_ca_act_01(Scsp_dcs *, void *);
69 int     scsp_ca_act_02(Scsp_dcs *, void *);
70 int     scsp_ca_act_03(Scsp_dcs *, void *);
71 int     scsp_ca_act_04(Scsp_dcs *, void *);
72 int     scsp_ca_act_05(Scsp_dcs *, void *);
73 int     scsp_ca_act_06(Scsp_dcs *, void *);
74 int     scsp_ca_act_07(Scsp_dcs *, void *);
75 int     scsp_ca_act_08(Scsp_dcs *, void *);
76 int     scsp_ca_act_09(Scsp_dcs *, void *);
77 int     scsp_ca_act_10(Scsp_dcs *, void *);
78 int     scsp_ca_act_11(Scsp_dcs *, void *);
79 int     scsp_ca_act_12(Scsp_dcs *, void *);
80 int     scsp_ca_act_13(Scsp_dcs *, void *);
81 int     scsp_ca_act_14(Scsp_dcs *, void *);
82 int     scsp_ca_act_15(Scsp_dcs *, void *);
83 int     scsp_ca_act_16(Scsp_dcs *, void *);
84 int     scsp_ca_act_17(Scsp_dcs *, void *);
85 int     scsp_ca_act_18(Scsp_dcs *, void *);
86 int     scsp_ca_act_19(Scsp_dcs *, void *);
87
88 static int (*scsp_ca_act_vec[CA_ACTION_CNT])() = {
89         scsp_ca_act_00,
90         scsp_ca_act_01,
91         scsp_ca_act_02,
92         scsp_ca_act_03,
93         scsp_ca_act_04,
94         scsp_ca_act_05,
95         scsp_ca_act_06,
96         scsp_ca_act_07,
97         scsp_ca_act_08,
98         scsp_ca_act_09,
99         scsp_ca_act_10,
100         scsp_ca_act_11,
101         scsp_ca_act_12,
102         scsp_ca_act_13,
103         scsp_ca_act_14,
104         scsp_ca_act_15,
105         scsp_ca_act_16,
106         scsp_ca_act_17,
107         scsp_ca_act_18,
108         scsp_ca_act_19
109 };
110
111 /*
112  * CA FSM state table
113  */
114 static int ca_state_table[SCSP_CAFSM_EVENT_CNT][SCSP_CAFSM_STATE_CNT] = {
115         /* 0   1   2   3   4   5              */
116         {  1,  1,  1,  1,  1,  1 },     /*  0 */
117         {  2,  2,  2,  2,  2,  2 },     /*  1 */
118         {  0,  3,  4,  5, 15, 15 },     /*  2 */
119         {  0, 17, 17, 17,  7,  7 },     /*  3 */
120         {  0, 17, 17, 17,  8,  8 },     /*  4 */
121         {  0, 17, 17, 17, 10, 10 },     /*  5 */
122         {  0,  6,  6,  0,  9,  9 },     /*  6 */
123         {  0,  0,  0,  0, 12, 12 },     /*  7 */
124         {  0,  0,  0,  0, 13, 13 },     /*  8 */
125         { 18, 14, 14, 14, 11, 11 },     /*  9 */
126         {  0, 19,  0,  0, 16, 16 },     /* 10 */
127 };
128
129
130 /*
131  * Cache Alignment finite state machine
132  *
133  * Arguments:
134  *      dcsp    pointer to a DCS control block for the neighbor
135  *      event   the event which has occurred
136  *      p       pointer to further parameter, if there is one
137  *
138  * Returns:
139  *      0       success
140  *      errno   error encountered
141  *
142  */
143 int
144 scsp_cafsm(Scsp_dcs *dcsp, int event, void *p)
145 {
146         int     action, rc, state;
147
148         /*
149          * Select an action from the state table
150          */
151         state = dcsp->sd_ca_state;
152         action = ca_state_table[event][state];
153         if (scsp_trace_mode & SCSP_TRACE_CAFSM) {
154                 scsp_trace("CAFSM: state=%d, event=%d, action=%d\n",
155                                 state, event, action);
156         }
157         if (action >= CA_ACTION_CNT || action < 0) {
158                 scsp_log(LOG_ERR, "CA FSM--invalid action state=%d, event=%d, action=%d",
159                                 state, event, action);
160                 abort();
161         }
162
163         /*
164          * Perform the selected action
165          */
166         rc = scsp_ca_act_vec[action](dcsp, p);
167
168         return(rc);
169 }
170
171
172 /*
173  * CA finite state machine action 0
174  * Unexpected action -- log an error message and go to Master/Slave
175  * Negotiation.  The unexpected action is probably from a protocol
176  * error.
177  *
178  * Arguments:
179  *      dcsp    pointer to DCS control block
180  *      p       ignored
181  *
182  * Returns:
183  *      EOPNOTSUPP      always returns EOPNOTSUPP
184  *
185  */
186 int
187 scsp_ca_act_00(Scsp_dcs *dcsp, void *p)
188 {
189         int     rc;
190
191         /*
192          * Log an error message
193          */
194         scsp_log(LOG_ERR, "CA FSM error--unexpected action, state=%d",
195                         dcsp->sd_ca_state);
196
197         /*
198          * Set the new state
199          */
200         dcsp->sd_ca_state = SCSP_CAFSM_NEG;
201
202         /*
203          * Clear out the DCS block
204          */
205         scsp_dcs_cleanup(dcsp);
206
207         /*
208          * Notify the client I/F FSM
209          */
210         rc = scsp_cfsm(dcsp, SCSP_CIFSM_CA_DOWN, (Scsp_msg *)0,
211                         (Scsp_if_msg *)0);
212
213         return(rc);
214 }
215
216
217 /*
218  * CA finite state machine action 1
219  * Hello FSM has reached Bidirectional state -- go to Master/Slave
220  * Negotiation state, make a copy of the client's cache, send first CA
221  * message.
222  *
223  * Arguments:
224  *      dcsp    pointer to DCS control block
225  *      p       ignored
226  *
227  * Returns:
228  *      0       success
229  *      errno   error encountered
230  *
231  */
232 int
233 scsp_ca_act_01(Scsp_dcs *dcsp, void *p)
234 {
235         int             i, rc;
236         Scsp_cse        *csep, *dupp;
237
238         /*
239          * Set the new state
240          */
241         dcsp->sd_ca_state = SCSP_CAFSM_NEG;
242
243         /*
244          * Make a copy of client's cache entries for cache alignment
245          */
246         for (i = 0; i < SCSP_HASHSZ; i++) {
247                 for (csep = dcsp->sd_server->ss_cache[i];
248                                 csep; csep = csep->sc_next) {
249                         dupp = scsp_dup_cse(csep);
250                         LINK2TAIL(dupp, Scsp_cse, dcsp->sd_ca_csas,
251                                                 sc_next);
252                 }
253         }
254
255         /*
256          * Select an initial sequence number
257          */
258         dcsp->sd_ca_seq = (int)time((time_t *)0);
259
260         /*
261          * Send a CA message
262          */
263         rc = scsp_send_ca(dcsp);
264         if (rc == 0) {
265                 HARP_TIMER(&dcsp->sd_ca_rexmt_t, dcsp->sd_ca_rexmt_int,
266                                 scsp_ca_retran_timeout);
267         }
268
269         return(rc);
270 }
271
272
273 /*
274  * CA finite state machine action 2
275  * Hello FSM has gone down -- go to Down state
276  *
277  * Arguments:
278  *      dcsp    pointer to DCS control block
279  *      p       ignored
280  *
281  * Returns:
282  *      0       success
283  *      errno   error encountered
284  *
285  */
286 int
287 scsp_ca_act_02(Scsp_dcs *dcsp, void *p)
288 {
289         int             rc;
290
291         /*
292          * Set the new state
293          */
294         dcsp->sd_ca_state = SCSP_CAFSM_DOWN;
295
296         /*
297          * Clear out the DCS block
298          */
299         scsp_dcs_cleanup(dcsp);
300
301         /*
302          * Notify the client I/F FSM
303          */
304         rc = scsp_cfsm(dcsp, SCSP_CIFSM_CA_DOWN, (Scsp_msg *)0,
305                         (Scsp_if_msg *)0);
306
307         return(rc);
308 }
309
310
311 /*
312  * CA finite state machine action 3
313  * CA message received -- select Cache Summarize Master or Slave state
314  *
315  * Arguments:
316  *      dcsp    pointer to DCS control block
317  *      p       pointer to received message
318  *
319  * Returns:
320  *      0       success
321  *      errno   error encountered
322  *
323  */
324 int
325 scsp_ca_act_03(Scsp_dcs *dcsp, void *p)
326 {
327         int             rc = 0;
328         Scsp_msg        *msg = (Scsp_msg *)p;
329
330         /*
331          * Check for slave role for LS
332          */
333         if (msg->sc_ca->ca_m &&
334                         msg->sc_ca->ca_i &&
335                         msg->sc_ca->ca_o &&
336                         msg->sc_ca->ca_mcp.rec_cnt == 0 &&
337                         scsp_cmp_id(&msg->sc_ca->ca_mcp.sid,
338                                 &msg->sc_ca->ca_mcp.rid) > 0) {
339
340                 /*
341                  * Stop the retransmit timer
342                  */
343                 HARP_CANCEL(&dcsp->sd_ca_rexmt_t);
344
345                 /*
346                  * Set the new state
347                  */
348                 dcsp->sd_ca_state = SCSP_CAFSM_SLAVE;
349                 scsp_cfsm(dcsp, SCSP_CIFSM_CA_SUMM,
350                                 (Scsp_msg *)0, (Scsp_if_msg *)0);
351
352                 /*
353                  * Save the master's sequence number
354                  */
355                 dcsp->sd_ca_seq = msg->sc_ca->ca_seq;
356
357                 /*
358                  * Send a CA message
359                  */
360                 rc = scsp_send_ca(dcsp);
361         } else
362         /*
363          * Check for master role for LS
364          */
365         if (!msg->sc_ca->ca_m &&
366                         !msg->sc_ca->ca_i &&
367                         scsp_cmp_id(&msg->sc_ca->ca_mcp.sid,
368                                 &msg->sc_ca->ca_mcp.rid) < 0) {
369                 /*
370                  * Stop the retransmit timer
371                  */
372                 HARP_CANCEL(&dcsp->sd_ca_rexmt_t);
373
374                 /*
375                  * Set the new state
376                  */
377                 dcsp->sd_ca_state = SCSP_CAFSM_MASTER;
378                 rc = scsp_cfsm(dcsp, SCSP_CIFSM_CA_SUMM,
379                                 (Scsp_msg *)0, (Scsp_if_msg *)0);
380
381                 /*
382                  * Process the CA message
383                  */
384                 scsp_process_ca(dcsp, msg->sc_ca);
385
386                 /*
387                  * Increment the sequence number
388                  */
389                 dcsp->sd_ca_seq++;
390
391                 /*
392                  * Send a CA in reply
393                  */
394                 rc = scsp_send_ca(dcsp);
395                 if (rc == 0) {
396                         HARP_TIMER(&dcsp->sd_ca_rexmt_t,
397                                         dcsp->sd_ca_rexmt_int,
398                                         scsp_ca_retran_timeout);
399                 }
400         } else {
401                 /*
402                  * Ignore the message, go to Master/Slave Negotiation
403                  */
404                 dcsp->sd_ca_state = SCSP_CAFSM_NEG;
405         }
406
407         return(rc);
408 }
409
410
411 /*
412  * CA finite state machine action 4
413  * CA message received while in Cache Summarize Master state -- process
414  * CA message
415  *
416  * Arguments:
417  *      dcsp    pointer to DCS control block
418  *      p       pointer to received message
419  *
420  * Returns:
421  *      0       success
422  *      errno   error encountered
423  *
424  */
425 int
426 scsp_ca_act_04(Scsp_dcs *dcsp, void *p)
427 {
428         int             rc = 0;
429         Scsp_msg        *msg = (Scsp_msg *)p;
430
431         /*
432          * If the other side thinks he's the master, or if the
433          * initialization bit is set, or if the message is out
434          * of sequence, go back to Master/Slave Negotiation state
435          */
436         if (msg->sc_ca->ca_m || msg->sc_ca->ca_i ||
437                         msg->sc_ca->ca_seq < dcsp->sd_ca_seq - 1 ||
438                         msg->sc_ca->ca_seq > dcsp->sd_ca_seq) {
439                 HARP_CANCEL(&dcsp->sd_ca_rexmt_t);
440                 dcsp->sd_ca_state = SCSP_CAFSM_NEG;
441                 scsp_dcs_cleanup(dcsp);
442                 return(scsp_ca_act_01(dcsp, (Scsp_msg *)0));
443         }
444
445         /*
446          * Ignore any duplicate messages
447          */
448         if (msg->sc_ca->ca_seq == dcsp->sd_ca_seq - 1) {
449                 return(0);
450         }
451
452         /*
453          * Stop the retransmission timer
454          */
455         HARP_CANCEL(&dcsp->sd_ca_rexmt_t);
456
457         /*
458          * Process the CA message
459          */
460         scsp_process_ca(dcsp, msg->sc_ca);
461
462         /*
463          * Increment the CA sequence number
464          */
465         dcsp->sd_ca_seq++;
466
467         /*
468          * If we have no more CSAS records to send and the slave sent
469          * a message with the 'O' bit off, we're done with Summarize
470          * state
471          */
472         if (!dcsp->sd_ca_csas && !msg->sc_ca->ca_o) {
473                 /*
474                  * Free any CA message saved for retransmission
475                  */
476                 if (dcsp->sd_ca_rexmt_msg) {
477                         scsp_free_msg(dcsp->sd_ca_rexmt_msg);
478                         dcsp->sd_ca_rexmt_msg = (Scsp_msg *)0;
479                 }
480
481                 /*
482                  * If the CRL is empty, we go directly to Aligned state;
483                  * otherwise, we go to Update Cache and send a CSUS
484                  */
485                 if (!dcsp->sd_crl) {
486                         /*
487                          * Go to Aligned state
488                          */
489                         dcsp->sd_ca_state = SCSP_CAFSM_ALIGNED;
490                         rc = scsp_cfsm(dcsp, SCSP_CIFSM_CA_ALIGN,
491                                         (Scsp_msg *)0,
492                                         (Scsp_if_msg *)0);
493                 } else {
494                         /*
495                          * Go to Cache Update state
496                          */
497                         dcsp->sd_ca_state = SCSP_CAFSM_UPDATE;
498                         scsp_cfsm(dcsp, SCSP_CIFSM_CA_UPD,
499                                         (Scsp_msg *)0,
500                                         (Scsp_if_msg *)0);
501                         rc = scsp_send_csus(dcsp);
502                 }
503         } else {
504                 /*
505                  * There are more CSAS records to be exchanged--
506                  * continue the cache exchange
507                  */
508                 rc = scsp_send_ca(dcsp);
509         }
510
511         return(rc);
512 }
513
514
515 /*
516  * CA finite state machine action 5
517  * CA message received while in Cache Summarize Slave state -- process
518  * CA message
519  *
520  * Arguments:
521  *      dcsp    pointer to DCS control block
522  *      p       pointer to received message
523  *
524  * Returns:
525  *      0       success
526  *      errno   error encountered
527  *
528  */
529 int
530 scsp_ca_act_05(Scsp_dcs *dcsp, void *p)
531 {
532         int             rc = 0;
533         Scsp_msg        *msg = (Scsp_msg *)p;
534
535         /*
536          * If the other side thinks we're the master, or if the
537          * initialization bit is set, or if the message is out
538          * of sequence, go back to Master/Slave Negotiation state
539          */
540         if (!msg->sc_ca->ca_m || msg->sc_ca->ca_i ||
541                         msg->sc_ca->ca_seq < dcsp->sd_ca_seq ||
542                         msg->sc_ca->ca_seq > dcsp->sd_ca_seq + 1) {
543                 HARP_CANCEL(&dcsp->sd_ca_rexmt_t);
544                 dcsp->sd_ca_state = SCSP_CAFSM_NEG;
545                 scsp_dcs_cleanup(dcsp);
546                 return(scsp_ca_act_01(dcsp, (Scsp_msg *)0));
547         }
548
549         /*
550          * If this is a duplicate, retransmit the last message
551          */
552         if (msg->sc_ca->ca_seq == dcsp->sd_ca_seq) {
553                 if (dcsp->sd_ca_rexmt_msg) {
554                         rc = scsp_send_msg(dcsp, dcsp->sd_ca_rexmt_msg);
555                         if (rc == 0) {
556                                 HARP_TIMER(&dcsp->sd_ca_rexmt_t,
557                                                 dcsp->sd_ca_rexmt_int,
558                                                 scsp_ca_retran_timeout);
559                         }
560                 }
561                 return(rc);
562         }
563
564         /*
565          * Free the last CA message
566          */
567         if (dcsp->sd_ca_rexmt_msg) {
568                 scsp_free_msg(dcsp->sd_ca_rexmt_msg);
569                 dcsp->sd_ca_rexmt_msg = (Scsp_msg *)0;
570         }
571
572         /*
573          * Process the CA message
574          */
575         scsp_process_ca(dcsp, msg->sc_ca);
576
577         /*
578          * Increment the CA sequence number
579          */
580         dcsp->sd_ca_seq++;
581
582         /*
583          * Answer the CA message
584          */
585         rc = scsp_send_ca(dcsp);
586         if (rc)
587                 return(rc);
588
589         /*
590          * If we're done sending CSAS records and the other side is,
591          * too, we're done with Summarize state
592          */
593         if (!dcsp->sd_ca_csas && !msg->sc_ca->ca_o) {
594                 /*
595                  * If the CRL is empty, we go directly to Aligned state;
596                  * otherwise, we go to Update Cache and send a CSUS
597                  */
598                 if (!dcsp->sd_crl) {
599                         /*
600                          * Go to Aligned state
601                          */
602                         dcsp->sd_ca_state = SCSP_CAFSM_ALIGNED;
603                         rc = scsp_cfsm(dcsp, SCSP_CIFSM_CA_ALIGN,
604                                         (Scsp_msg *)0,
605                                         (Scsp_if_msg *)0);
606                 } else {
607                         /*
608                          * Go to Cache Update state
609                          */
610                         dcsp->sd_ca_state = SCSP_CAFSM_UPDATE;
611                         HARP_CANCEL(&dcsp->sd_ca_rexmt_t);
612                         HARP_TIMER(&dcsp->sd_ca_rexmt_t,
613                                         dcsp->sd_ca_rexmt_int,
614                                         scsp_ca_retran_timeout);
615                         scsp_cfsm(dcsp, SCSP_CIFSM_CA_UPD,
616                                         (Scsp_msg *)0,
617                                         (Scsp_if_msg *)0);
618                         rc = scsp_send_csus(dcsp);
619                 }
620         }
621
622         return(rc);
623 }
624
625
626 /*
627  * CA finite state machine action 6
628  * Retransmit timer expired -- retransmit last CA message
629  *
630  * Arguments:
631  *      dcsp    pointer to DCS control block
632  *      p       ignored
633  *
634  * Returns:
635  *      0       success
636  *      errno   error encountered
637  *
638  */
639 int
640 scsp_ca_act_06(Scsp_dcs *dcsp, void *p)
641 {
642         int     rc;
643
644         /*
645          * Resend the CA message
646          */
647         rc = scsp_send_msg(dcsp, dcsp->sd_ca_rexmt_msg);
648
649         /*
650          * Restart the retransmit timer
651          */
652         if (rc == 0) {
653                 HARP_TIMER(&dcsp->sd_ca_rexmt_t, dcsp->sd_ca_rexmt_int,
654                                 scsp_ca_retran_timeout);
655         }
656
657         return(rc);
658 }
659
660
661 /*
662  * CA finite state machine action 7
663  * CSU Solicit received -- send it to the client interface FSM
664  *
665  * Arguments:
666  *      dcsp    pointer to DCS control block
667  *      p       pointer to received message
668  *
669  * Returns:
670  *      0       success
671  *      errno   error encountered
672  *
673  */
674 int
675 scsp_ca_act_07(Scsp_dcs *dcsp, void *p)
676 {
677         int             rc;
678         Scsp_msg        *msg = (Scsp_msg *)p;
679
680         /*
681          * Cancel the CA retransmit timer and free any CA message
682          * saved for retransmission
683          */
684         if (dcsp->sd_ca_rexmt_msg) {
685                 HARP_CANCEL(&dcsp->sd_ca_rexmt_t);
686                 scsp_free_msg(dcsp->sd_ca_rexmt_msg);
687                 dcsp->sd_ca_rexmt_msg = (Scsp_msg *)0;
688         }
689
690         /*
691          * Pass the CSUS to the client interface FSM
692          */
693         rc = scsp_cfsm(dcsp, SCSP_CIFSM_CSU_SOL, msg,
694                         (Scsp_if_msg *)0);
695
696         return(rc);
697 }
698
699
700 /*
701  * CA finite state machine action 8
702  * CSU Request received -- pass it to the client interface FSM
703  *
704  * Arguments:
705  *      dcsp    pointer to DCS control block
706  *      p       pointer to received message
707  *
708  * Returns:
709  *      0       success
710  *      errno   error encountered
711  *
712  */
713 int
714 scsp_ca_act_08(Scsp_dcs *dcsp, void *p)
715 {
716         int             rc;
717         Scsp_msg        *msg = (Scsp_msg *)p;
718         Scsp_csa        *csap;
719
720         /*
721          * Check whether this messages answers a CSUS
722          */
723         scsp_csus_ack(dcsp, msg);
724
725         /*
726          * If all CSAs requestd in CSUS messages have been
727          * received, the cache is aligned, so go to Aligned State
728          */
729         if (!dcsp->sd_csus_rexmt_msg && !dcsp->sd_crl &&
730                         dcsp->sd_ca_state != SCSP_CAFSM_ALIGNED) {
731                 dcsp->sd_ca_state = SCSP_CAFSM_ALIGNED;
732                 rc = scsp_cfsm(dcsp, SCSP_CIFSM_CA_ALIGN,
733                                 (Scsp_msg *)0, (Scsp_if_msg *)0);
734         }
735
736         /*
737          * Pass the CSU Req to the client interface FSM
738          */
739         rc = scsp_cfsm(dcsp, SCSP_CIFSM_CSU_REQ, msg,
740                         (Scsp_if_msg *)0);
741
742         /*
743          * Move the CSA chain from the message to the list of
744          * requests that need acknowledgements
745          */
746         for (csap = msg->sc_csu_msg->csu_csa_rec; csap;
747                         csap = csap->next) {
748                 LINK2TAIL(csap, Scsp_csa, dcsp->sd_csu_ack_pend, next);
749         }
750         msg->sc_csu_msg->csu_csa_rec = (Scsp_csa *)0;
751
752         return(rc);
753 }
754
755
756 /*
757  * CA finite state machine action 9
758  * CA Retransmit timer expired in Update Cache or Aligned state--free
759  * the saved CA message
760  *
761  * Arguments:
762  *      dcsp    pointer to DCS control block
763  *      p       ignored
764  *
765  * Returns:
766  *      0       success
767  *      errno   error encountered
768  *
769  */
770 int
771 scsp_ca_act_09(Scsp_dcs *dcsp, void *p)
772 {
773         /*
774          * Free any CA message saved for retransmission
775          */
776         if (dcsp->sd_ca_rexmt_msg) {
777                 scsp_free_msg(dcsp->sd_ca_rexmt_msg);
778                 dcsp->sd_ca_rexmt_msg = (Scsp_msg *)0;
779         }
780
781         return(0);
782 }
783
784
785 /*
786  * CA finite state machine action 10
787  * CSU Reply received -- Process the message
788  *
789  * Arguments:
790  *      dcsp    pointer to DCS control block
791  *      p       pointer to received message
792  *
793  * Returns:
794  *      0       success
795  *      errno   error encountered
796  *
797  */
798 int
799 scsp_ca_act_10(Scsp_dcs *dcsp, void *p)
800 {
801         int             rc = 0;
802         Scsp_msg        *msg = (Scsp_msg *)p;
803         Scsp_csu_rexmt  *rxp, *next_rxp;
804         Scsp_csa        *csap, *next_csap, *mcp;
805
806         /*
807          * Dequeue acknowledged CSAs.  For each CSAS in the received
808          * message, find the corresponding CSA on the CSU Request
809          * retransmit queue.  Remove the CSA from the queue;  if this
810          * results in the retransmit queue entry being empty, delete
811          * the entry.  If the DCS has a newer CSA, send a CSUS to
812          * request it.
813          *
814          * Caution--potentially confusing lack of indentation ahead.
815          */
816         for (mcp = msg->sc_csu_msg->csu_csa_rec; mcp;
817                         mcp = mcp->next) {
818         for (rxp = dcsp->sd_csu_rexmt; rxp; rxp = next_rxp) {
819         next_rxp = rxp->sr_next;
820         for (csap = rxp->sr_csa; csap; csap = next_csap) {
821                 next_csap = csap->next;
822                 if (scsp_cmp_key(&csap->key, &mcp->key) ||
823                                 scsp_cmp_id(&csap->oid, &mcp->oid))
824                         continue;
825                 /*
826                  * Found a CSA whose key and ID are equal to
827                  * those in the CSU Reply
828                  */
829                 if (csap->seq == mcp->seq) {
830                         /*
831                          * The queued seq no is equal to the
832                          * received seq no--the CSA is acknowledged
833                          */
834                         UNLINK(csap, Scsp_csa, rxp->sr_csa, next);
835                         SCSP_FREE_CSA(csap);
836                 } else if (csap->seq < mcp->seq) {
837                         /*
838                          * Queued seq no is less than received.
839                          * We must dequeue the CSA and send a
840                          * CSUS to request the more-up-to-date
841                          * cache entry.
842                          */
843                         UNLINK(mcp, Scsp_csa,
844                                         msg->sc_csu_msg->csu_csa_rec,
845                                         next);
846                         LINK2TAIL(mcp, Scsp_csa, dcsp->sd_crl, next);
847                         UNLINK(csap, Scsp_csa, rxp->sr_csa, next);
848                         SCSP_FREE_CSA(csap);
849                         if (!dcsp->sd_csus_rexmt_msg) {
850                                 rc = scsp_send_csus(dcsp);
851                                 if (rc) {
852                                         return(rc);
853                                 }
854                         }
855                 }
856                         /*
857                          * Queued seq no is greater than
858                          * received.  Ignore the received CSAS.
859                          */
860
861                 /*
862                  * If the retransmission block is empty, stop the
863                  * timer and free it
864                  */
865                 if (!rxp->sr_csa) {
866                         HARP_CANCEL(&rxp->sr_t);
867                         UNLINK(rxp, Scsp_csu_rexmt,
868                                         dcsp->sd_csu_rexmt, sr_next);
869                         UM_FREE(rxp);
870                 }
871
872                 break;
873         } /* for (csap = ... */
874         } /* for (rxp = ... */
875         } /* for (mcp = ... */
876
877         return(rc);
878 }
879
880
881 /*
882  * CA finite state machine action 11
883  * Updated cache entry -- update the summary cache and send a
884  * CSU Request
885  *
886  * Arguments:
887  *      dcsp    pointer to DCS control block
888  *      p       pointer to CSA describing new cache entry
889  *
890  * Returns:
891  *      0       success
892  *      errno   error encountered
893  *
894  */
895 int
896 scsp_ca_act_11(Scsp_dcs *dcsp, void *p)
897 {
898         int             rc, state;
899         Scsp_csa        *csap =  (Scsp_csa *)p;
900         Scsp_cse        *csep;
901
902         /*
903          * Get the state of the CSA
904          */
905         switch(dcsp->sd_server->ss_pid) {
906         case SCSP_PROTO_ATMARP:
907                 state = csap->atmarp_data->sa_state;
908                 break;
909         default:
910                 SCSP_FREE_CSA(csap);
911                 return(EINVAL);
912         }
913
914         if (state < SCSP_ASTATE_NEW || state > SCSP_ASTATE_DEL) {
915                 SCSP_FREE_CSA(csap);
916                 return(EINVAL);
917         }
918
919         /*
920          * Look up the cache summary entry for the CSA
921          */
922         SCSP_LOOKUP(dcsp->sd_server, &csap->key, csep);
923
924         /*
925          * Process ATMARP entries
926          */
927         if (dcsp->sd_server->ss_pid == SCSP_PROTO_ATMARP) {
928                 switch(state) {
929                 case SCSP_ASTATE_NEW:
930                 case SCSP_ASTATE_UPD:
931                         /*
932                          * Add the entry if we don't have it already
933                          */
934                         if (!csep) {
935                                 csep = (Scsp_cse *)UM_ALLOC(
936                                                 sizeof(Scsp_cse));
937                                 if (!csep)
938                                         scsp_mem_err("scsp_ca_act_11: sizeof(Scsp_cse)");
939                                 UM_ZERO(csep, sizeof(Scsp_cse));
940
941                                 csep->sc_key = csap->key;
942                                 SCSP_ADD(dcsp->sd_server, csep);
943                         }
944
945                         /*
946                          * Update the cache summary entry
947                          */
948                         csep->sc_seq = csap->seq;
949                         csep->sc_oid = csap->oid;
950                         break;
951                 case SCSP_ASTATE_DEL:
952                         /*
953                          * Delete any entry, but don't send the
954                          * delete to the DCS
955                          */
956                         if (csep) {
957                                 SCSP_DELETE(dcsp->sd_server, csep);
958                                 UM_FREE(csep);
959                         }
960
961                         SCSP_FREE_CSA(csap);
962                         return(0);
963                 }
964         }
965
966         /*
967          * Send the CSA in a CSU Request
968          */
969         csap->trans_ct = 0;
970         rc = scsp_send_csu_req(dcsp, csap);
971
972         return(rc);
973 }
974
975
976 /*
977  * CA finite state machine action 12
978  * CSUS retransmit timer expired--send a CSUS with any pending CSA
979  * records
980  *
981  * Arguments:
982  *      dcsp    pointer to DCS control block
983  *      p       ignored
984  *
985  * Returns:
986  *      0       success
987  *      errno   error encountered
988  *
989  */
990 int
991 scsp_ca_act_12(Scsp_dcs *dcsp, void *p)
992 {
993         int     rc;
994
995         rc = scsp_send_csus(dcsp);
996
997         return(rc);
998 }
999
1000
1001 /*
1002  * CA finite state machine action 13
1003  * CSU retransmit timer fired in Update or Aligned state--
1004  * retransmit CSU Req
1005  *
1006  * Arguments:
1007  *      dcsp    pointer to DCS control block
1008  *      p       pointer to retransmission block whose timer fired
1009  *
1010  * Returns:
1011  *      0       success
1012  *      errno   error encountered
1013  *
1014  */
1015 int
1016 scsp_ca_act_13(Scsp_dcs *dcsp, void *p)
1017 {
1018         int             rc = 0;
1019         Scsp_csu_rexmt  *rxp = (Scsp_csu_rexmt *)p;
1020         Scsp_csa        *csap, *csap1, *next_csap;
1021
1022         /*
1023          * Unlink and free the retransmit request block
1024          */
1025         csap = rxp->sr_csa;
1026         UNLINK(rxp, Scsp_csu_rexmt, dcsp->sd_csu_rexmt, sr_next);
1027         UM_FREE(rxp);
1028
1029         /*
1030          * Increment the transmission count for the CSAs in the request
1031          */
1032         for (csap1 = csap; csap1; csap1 = next_csap) {
1033                 next_csap = csap1->next;
1034                 csap1->trans_ct++;
1035                 if (csap1->trans_ct >= dcsp->sd_csu_rexmt_max) {
1036                         /*
1037                          * We've already sent this as many times as
1038                          * the limit allows.  Drop this CSA.
1039                          */
1040                         UNLINK(csap1, Scsp_csa, csap, next);
1041                         SCSP_FREE_CSA(csap1);
1042                 }
1043         }
1044
1045         /*
1046          * Send another CSU Request with the CSA list, if it isn't
1047          * empty now
1048          */
1049         if (csap) {
1050                 rc = scsp_send_csu_req(dcsp, csap);
1051         }
1052
1053         return(rc);
1054 }
1055
1056
1057 /*
1058  * CA finite state machine action 14
1059  * Updated cache entry in Master/Slave Negotiation, Master, or
1060  * Slave state--add entry to cache and CSA list
1061  *
1062  * Arguments:
1063  *      dcsp    pointer to DCS control block
1064  *      p       pointer to new cache summary entry
1065  *
1066  * Returns:
1067  *      0       success
1068  *      errno   error encountered
1069  *
1070  */
1071 int
1072 scsp_ca_act_14(Scsp_dcs *dcsp, void *p)
1073 {
1074         Scsp_csa        *csap =  (Scsp_csa *)p;
1075         Scsp_cse        *csep, *csep1;
1076
1077         /*
1078          * Check to see whether we already have this
1079          */
1080         SCSP_LOOKUP(dcsp->sd_server, &csap->key, csep);
1081
1082         /*
1083          * If we don't already have it and it's not being deleted,
1084          * build a new cache summary entry
1085          */
1086         if (!csep && !csap->null) {
1087                 /*
1088                  * Get memory for a new entry
1089                  */
1090                 csep = (Scsp_cse *)UM_ALLOC(sizeof(Scsp_cse));
1091                 if (!csep) {
1092                         scsp_mem_err("scsp_ca_act_14: sizeof(Scsp_cse)");
1093                 }
1094                 UM_ZERO(csep, sizeof(Scsp_cse));
1095
1096                 /*
1097                  * Fill out the new cache entry
1098                  */
1099                 csep->sc_seq = csap->seq;
1100                 csep->sc_key = csap->key;
1101                 csep->sc_oid = csap->oid;
1102
1103                 /*
1104                  * Duplicate the new cache entry
1105                  */
1106                 csep1 = scsp_dup_cse(csep);
1107
1108                 /*
1109                  * Add entry to the summary cache and the CSAS list
1110                  */
1111                 SCSP_ADD(dcsp->sd_server, csep);
1112                 LINK2TAIL(csep1, Scsp_cse, dcsp->sd_ca_csas, sc_next);
1113         } else {
1114                 /*
1115                  * We already have the entry.  Find it on the CSAS
1116                  * list.
1117                  */
1118                 for (csep1 = dcsp->sd_ca_csas; csep1;
1119                                 csep1 = csep1->sc_next) {
1120                         if (scsp_cmp_key(&csep->sc_key,
1121                                         &csep1->sc_key) == 0)
1122                                 break;
1123                 }
1124
1125                 /*
1126                  * Update or delete the entry
1127                  */
1128                 if (csap->null) {
1129                         /*
1130                          * The null flag is set--delete the entry
1131                          */
1132                         SCSP_DELETE(dcsp->sd_server, csep);
1133                         UM_FREE(csep);
1134                         if (csep1) {
1135                                 UNLINK(csep1, Scsp_cse,
1136                                                 dcsp->sd_ca_csas,
1137                                                 sc_next);
1138                                 UM_FREE(csep1);
1139                         }
1140                 } else {
1141                         /*
1142                          * Update the entry
1143                          */
1144                         csep->sc_seq = csap->seq;
1145                         csep->sc_oid = csap->oid;
1146                         if (!csep1) {
1147                                 csep1 = scsp_dup_cse(csep);
1148                                 LINK2TAIL(csep1, Scsp_cse,
1149                                         dcsp->sd_ca_csas, sc_next);
1150                         } else {
1151                                 csep1->sc_seq = csap->seq;
1152                                 csep1->sc_oid = csap->oid;
1153                         }
1154                 }
1155         }
1156
1157         return(0);
1158 }
1159
1160
1161 /*
1162  * CA finite state machine action 15
1163  * CA message received in Update Cache state--if we have a saved CA
1164  * message, retransmit it;  otherwise, go to Master/Slave Negotiation
1165  * state
1166  *
1167  * Arguments:
1168  *      dcsp    pointer to DCS control block
1169  *      p       ignored
1170  *
1171  * Returns:
1172  *      0       success
1173  *      errno   error encountered
1174  *
1175  */
1176 int
1177 scsp_ca_act_15(Scsp_dcs *dcsp, void *p)
1178 {
1179         int             rc;
1180         Scsp_msg        *msg = (Scsp_msg *)p;
1181
1182         /*
1183          * If we don't have a saved CA message, or the sequence no. in
1184          * the received message isn't right, fall back to Master/Slave
1185          * Negotiation state
1186          */
1187         if (!dcsp->sd_ca_rexmt_msg ||
1188                         msg->sc_ca->ca_seq != dcsp->sd_ca_seq) {
1189                 dcsp->sd_ca_state = SCSP_CAFSM_NEG;
1190                 scsp_dcs_cleanup(dcsp);
1191                 rc = scsp_ca_act_01(dcsp, (Scsp_msg *)0);
1192         } else {
1193                 /*
1194                  * Retransmit the saved CA message and reset the
1195                  * CA timer
1196                  */
1197                 rc = scsp_send_msg(dcsp, dcsp->sd_ca_rexmt_msg);
1198                 if (rc == 0) {
1199                         HARP_CANCEL(&dcsp->sd_ca_rexmt_t);
1200                         HARP_TIMER(&dcsp->sd_ca_rexmt_t,
1201                                         dcsp->sd_ca_rexmt_int,
1202                                         scsp_ca_retran_timeout);
1203                 }
1204         }
1205
1206         return(rc);
1207 }
1208
1209
1210 /*
1211  * CA finite state machine action 16
1212  * Update Response received from client in Update Cache or Aligned
1213  * state.  Move the acknowledged CSA to the acknowledged queue.  If
1214  * the list of CSAs pending acknowledgement is empty, send a CSU
1215  * Reply.
1216  *
1217  * Arguments:
1218  *      dcsp    pointer to DCS control block
1219  *      p       pointer to message from client
1220  *
1221  * Returns:
1222  *      0       success
1223  *      errno   error encountered
1224  *
1225  */
1226 int
1227 scsp_ca_act_16(Scsp_dcs *dcsp, void *p)
1228 {
1229         int             found, rc = 0;
1230         Scsp_if_msg     *cmsg = (Scsp_if_msg *)p;
1231         Scsp_csa        *csap;
1232
1233         /*
1234          * Find the acknowledged CSA
1235          */      
1236         for (csap = dcsp->sd_csu_ack_pend, found = 0; csap && !found;
1237                         csap = csap->next) {
1238                 switch (dcsp->sd_server->ss_pid) {
1239                 case SCSP_PROTO_ATMARP:
1240                         found = ((scsp_cmp_key(&csap->key,
1241                                 &cmsg->si_atmarp.sa_key) == 0) &&
1242                                 (scsp_cmp_id(&csap->oid,
1243                                 &cmsg->si_atmarp.sa_oid) == 0));
1244                         break;
1245                 default: 
1246                         /*
1247                          * Protocol not implemented
1248                          */
1249                         return(EPROTONOSUPPORT);
1250                 }
1251                 if (found)
1252                         break;
1253         }
1254
1255         if (!found) {
1256                 if (scsp_trace_mode & SCSP_TRACE_CAFSM) {
1257                         scsp_trace("scsp_ca_act_16: can't find CSA entry for Update Response\n");
1258                 }
1259                 return(0);
1260         }
1261
1262         if (cmsg->si_rc == SCSP_RSP_OK) {
1263                 /*
1264                  * The server accepted the cache entry
1265                  */
1266
1267                 /*
1268                  * Update SCSP's cache
1269                  */
1270                 scsp_update_cache(dcsp, csap);
1271
1272                 /*
1273                  * Send this CSA to any other DCSs in the server group
1274                  */
1275                 rc = scsp_propagate_csa(dcsp, csap);
1276         }
1277
1278         /*
1279          * Move the CSA from the ACK pending queue to the
1280          * acknowledged queue
1281          */
1282         UNLINK(csap, Scsp_csa, dcsp->sd_csu_ack_pend, next);
1283         LINK2TAIL(csap, Scsp_csa, dcsp->sd_csu_ack, next);
1284         if (!dcsp->sd_csu_ack_pend) {
1285                 /*
1286                  * ACK pending list is empty--send a CSU Reply
1287                  */
1288                 csap = dcsp->sd_csu_ack;
1289                 dcsp->sd_csu_ack = (Scsp_csa *)0;
1290                 rc = scsp_send_csu_reply(dcsp, csap);
1291         }
1292
1293         return(rc);
1294 }
1295
1296
1297 /*
1298  * CA finite state machine action 17
1299  * Ignore an event.
1300  *
1301  * Arguments:
1302  *      dcsp    pointer to DCS control block
1303  *      p       ignored
1304  *
1305  * Returns:
1306  *      always returns 0
1307  *
1308  */
1309 int
1310 scsp_ca_act_17(Scsp_dcs *dcsp, void *p)
1311 {
1312         return(0);
1313 }
1314
1315
1316 /*
1317  * CA finite state machine action 18
1318  * Updated cache entry in Down state--add entry to summary cache
1319  *
1320  * Arguments:
1321  *      dcsp    pointer to DCS control block
1322  *      p       pointer to new cache summary entry
1323  *
1324  * Returns:
1325  *      0       success
1326  *      errno   error encountered
1327  *
1328  */
1329 int
1330 scsp_ca_act_18(Scsp_dcs *dcsp, void *p)
1331 {
1332         Scsp_csa        *csap =  (Scsp_csa *)p;
1333
1334         /*
1335          * Update the cache as appropriate
1336          */
1337         scsp_update_cache(dcsp, csap);
1338
1339         return(0);
1340 }
1341
1342
1343 /*
1344  * CA finite state machine action 19
1345  * Update Response received from client in Master/Slave Negotiation
1346  * state.  Update the cache as appropriate.
1347  *
1348  * Arguments:
1349  *      dcsp    pointer to DCS control block
1350  *      p       pointer to message from client
1351  *
1352  * Returns:
1353  *      0       success
1354  *      errno   error encountered
1355  *
1356  */
1357 int
1358 scsp_ca_act_19(Scsp_dcs *dcsp, void *p)
1359 {
1360         Scsp_if_msg     *cmsg = (Scsp_if_msg *)p;
1361         Scsp_csa        *csap;
1362
1363         /*
1364          * Ignore the message if the client rejected the update
1365          */
1366         if (cmsg->si_rc != SCSP_RSP_OK) {
1367                 return(0);
1368         }
1369
1370         /*
1371          * Create a CSAS from the client's update
1372          */      
1373         csap = (Scsp_csa *)UM_ALLOC(sizeof(Scsp_csa));
1374         if (!csap) {
1375                 scsp_mem_err("scsp_ca_act_19: sizeof(Scsp_csa)");
1376         }
1377         UM_ZERO(csap, sizeof(Scsp_csa));
1378
1379         csap->hops = 1;
1380         switch (dcsp->sd_server->ss_pid) {
1381         case SCSP_PROTO_ATMARP:
1382                 csap->null = cmsg->si_atmarp.sa_state ==
1383                                 SCSP_ASTATE_DEL;
1384                 csap->seq = cmsg->si_atmarp.sa_seq;
1385                 csap->key = cmsg->si_atmarp.sa_key;
1386                 csap->oid = cmsg->si_atmarp.sa_oid;
1387                 break;
1388         default:
1389                 return(EINVAL);
1390         }
1391
1392         /*
1393          * Update SCSP's cache
1394          */
1395         scsp_update_cache(dcsp, csap);
1396
1397         return(0);
1398 }