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