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