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