3 * ===================================
4 * HARP | Host ATM Research Platform
5 * ===================================
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.
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.
21 * Copyright 1994-1998 Network Computing Services, Inc.
23 * Copies of this Software may be made, however, the above copyright
24 * notice must be reproduced on all copies.
26 * @(#) $FreeBSD: src/usr.sbin/atm/scspd/scsp_subr.c,v 1.3 1999/08/28 01:15:34 peter Exp $
27 * @(#) $DragonFly: src/usr.sbin/atm/scspd/scsp_subr.c,v 1.4 2004/12/18 22:48:02 swildner Exp $
32 * Server Cache Synchronization Protocol (SCSP) Support
33 * ----------------------------------------------------
39 #include <sys/types.h>
40 #include <sys/param.h>
41 #include <sys/socket.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_sigmgr.h>
50 #include <netatm/atm_sys.h>
51 #include <netatm/atm_ioctl.h>
52 #include <netatm/uni/unisig_var.h>
67 * Hash an SCSP cache key
70 * ckp pointer to an SCSP cache key structure
77 scsp_hash(Scsp_ckey
*ckp
)
82 * Turn cache key into a positive integer
85 for (i
= ckp
->key_len
-1, j
= 0;
86 i
> 0 && j
< sizeof(int);
88 h
= (h
<< 8) + ckp
->key
[i
];
92 * Return the hashed value
94 return(h
% SCSP_HASHSZ
);
99 * Compare two SCSP IDs
102 * id1p pointer to an SCSP ID structure
103 * id2p pointer to an SCSP ID structure
106 * < 0 id1 is less than id2
107 * 0 id1 and id2 are equal
108 * > 0 id1 is greater than id2
112 scsp_cmp_id(Scsp_id
*id1p
, Scsp_id
*id2p
)
117 * Compare the two IDs, byte for byte
119 for (i
= 0; i
< id1p
->id_len
&& i
< id2p
->id_len
; i
++) {
120 diff
= id1p
->id
[i
] - id2p
->id
[i
];
127 * IDs are equal. If lengths differ, the longer ID is
128 * greater than the shorter.
130 return(id1p
->id_len
- id2p
->id_len
);
135 * Compare two SCSP cache keys
138 * ck1p pointer to an SCSP cache key structure
139 * ck2p pointer to an SCSP cache key structure
142 * < 0 ck1 is less than ck2
143 * 0 ck1 and ck2 are equal
144 * > 0 ck1 is greater than ck2
148 scsp_cmp_key(Scsp_ckey
*ck1p
, Scsp_ckey
*ck2p
)
153 * Compare the two keys, byte for byte
155 for (i
= 0; i
< ck1p
->key_len
&& i
< ck2p
->key_len
; i
++) {
156 diff
= ck1p
->key
[i
] - ck2p
->key
[i
];
162 * Keys are equal. If lengths differ, the longer key is
163 * greater than the shorter.
165 return(ck1p
->key_len
- ck2p
->key_len
);
170 * Check whether the host system is an ATMARP server for
171 * the LIS associated with a given interface
174 * netif pointer to the network interface name
178 * 0 host is not a server
182 scsp_is_atmarp_server(char *netif
)
185 int buf_len
= sizeof(struct air_asrv_rsp
);
186 struct atminfreq air
;
187 struct air_asrv_rsp
*asrv_info
;
190 * Get interface information from the kernel
192 strcpy(air
.air_int_intf
, netif
);
193 air
.air_opcode
= AIOCS_INF_ASV
;
194 buf_len
= do_info_ioctl(&air
, buf_len
);
199 * Check the interface's ATMARP server address
201 asrv_info
= (struct air_asrv_rsp
*) air
.air_buf_addr
;
202 rc
= (asrv_info
->asp_addr
.address_format
== T_ATM_ABSENT
) &&
203 (asrv_info
->asp_subaddr
.address_format
==
211 * Make a copy of a cache summary entry
214 * csep pointer to CSE entry to copy
218 * else pointer to new CSE entry
222 scsp_dup_cse(Scsp_cse
*csep
)
227 * Allocate memory for the duplicate
229 dupp
= (Scsp_cse
*)UM_ALLOC(sizeof(Scsp_cse
));
231 scsp_mem_err("scsp_dup_cse: sizeof(Scsp_cse)");
235 * Copy data to the duplicate
237 UM_COPY(csep
, dupp
, sizeof(Scsp_cse
));
238 dupp
->sc_next
= NULL
;
245 * Make a copy of a CSA or CSAS record
248 * csap pointer to CSE entry to copy
252 * else pointer to new CSA or CSAS record
256 scsp_dup_csa(Scsp_csa
*csap
)
259 Scsp_atmarp_csa
*adp
;
262 * Allocate memory for the duplicate
264 dupp
= (Scsp_csa
*)UM_ALLOC(sizeof(Scsp_csa
));
266 scsp_mem_err("scsp_dup_csa: sizeof(Scsp_csa)");
270 * Copy data to the duplicate
272 UM_COPY(csap
, dupp
, sizeof(Scsp_csa
));
276 * Copy protocol-specific data, if it's present
278 if (csap
->atmarp_data
) {
279 adp
= (Scsp_atmarp_csa
*)UM_ALLOC(sizeof(Scsp_atmarp_csa
));
281 scsp_mem_err("scsp_dup_csa: sizeof(Scsp_atmarp_csa)");
283 UM_COPY(csap
->atmarp_data
, adp
, sizeof(Scsp_atmarp_csa
));
284 dupp
->atmarp_data
= adp
;
292 * Copy a cache summary entry into a CSAS
295 * csep pointer to CSE entry to copy
299 * else pointer to CSAS record summarizing the entry
303 scsp_cse2csas(Scsp_cse
*csep
)
308 * Allocate memory for the duplicate
310 csap
= (Scsp_csa
*)UM_ALLOC(sizeof(Scsp_csa
));
312 scsp_mem_err("scsp_cse2csas: sizeof(Scsp_csa)");
314 UM_ZERO(csap
, sizeof(Scsp_csa
));
317 * Copy data to the CSAS entry
319 csap
->seq
= csep
->sc_seq
;
320 csap
->key
= csep
->sc_key
;
321 csap
->oid
= csep
->sc_oid
;
328 * Copy an ATMARP cache entry into a cache summary entry
331 * aap pointer to ATMARP cache entry to copy
335 * else pointer to CSE record summarizing the entry
339 scsp_atmarp2cse(Scsp_atmarp_msg
*aap
)
344 * Allocate memory for the duplicate
346 csep
= (Scsp_cse
*)UM_ALLOC(sizeof(Scsp_cse
));
348 scsp_mem_err("scsp_atmarp2cse: sizeof(Scsp_cse)");
350 UM_ZERO(csep
, sizeof(Scsp_cse
));
353 * Copy data to the CSE entry
355 csep
->sc_seq
= aap
->sa_seq
;
356 csep
->sc_key
= aap
->sa_key
;
357 csep
->sc_oid
= aap
->sa_oid
;
364 * Clean up a DCS block. This routine is called to clear out any
365 * lingering state information when the CA FSM reverts to an 'earlier'
366 * state (Down or Master/Slave Negotiation).
369 * dcsp pointer to a DCS control block for the neighbor
376 scsp_dcs_cleanup(Scsp_dcs
*dcsp
)
378 Scsp_cse
*csep
, *ncsep
;
379 Scsp_csa
*csap
, *next_csap
;
380 Scsp_csu_rexmt
*rxp
, *rx_next
;
383 * Free any CSAS entries waiting to be sent
385 for (csep
= dcsp
->sd_ca_csas
; csep
; csep
= ncsep
) {
386 ncsep
= csep
->sc_next
;
387 UNLINK(csep
, Scsp_cse
, dcsp
->sd_ca_csas
, sc_next
);
392 * Free any entries on the CRL
394 for (csap
= dcsp
->sd_crl
; csap
; csap
= next_csap
) {
395 next_csap
= csap
->next
;
396 UNLINK(csap
, Scsp_csa
, dcsp
->sd_crl
, next
);
401 * Free any saved CA message and cancel the CA
402 * retransmission timer
404 if (dcsp
->sd_ca_rexmt_msg
) {
405 scsp_free_msg(dcsp
->sd_ca_rexmt_msg
);
406 dcsp
->sd_ca_rexmt_msg
= NULL
;
408 HARP_CANCEL(&dcsp
->sd_ca_rexmt_t
);
411 * Free any saved CSU Solicit message and cancel the CSUS
412 * retransmission timer
414 if (dcsp
->sd_csus_rexmt_msg
) {
415 scsp_free_msg(dcsp
->sd_csus_rexmt_msg
);
416 dcsp
->sd_csus_rexmt_msg
= NULL
;
418 HARP_CANCEL(&dcsp
->sd_csus_rexmt_t
);
421 * Free any entries on the CSU Request retransmission queue
423 for (rxp
= dcsp
->sd_csu_rexmt
; rxp
; rxp
= rx_next
) {
424 rx_next
= rxp
->sr_next
;
425 HARP_CANCEL(&rxp
->sr_t
);
426 for (csap
= rxp
->sr_csa
; csap
; csap
= next_csap
) {
427 next_csap
= csap
->next
;
430 UNLINK(rxp
, Scsp_csu_rexmt
, dcsp
->sd_csu_rexmt
,
438 * Delete an SCSP DCS block and any associated information
441 * dcsp pointer to a DCS control block to delete
448 scsp_dcs_delete(Scsp_dcs
*dcsp
)
450 Scsp_cse
*csep
, *next_cse
;
451 Scsp_csu_rexmt
*rxp
, *next_rxp
;
452 Scsp_csa
*csap
, *next_csa
;
455 * Cancel any pending DCS timers
457 HARP_CANCEL(&dcsp
->sd_open_t
);
458 HARP_CANCEL(&dcsp
->sd_hello_h_t
);
459 HARP_CANCEL(&dcsp
->sd_hello_rcv_t
);
460 HARP_CANCEL(&dcsp
->sd_ca_rexmt_t
);
461 HARP_CANCEL(&dcsp
->sd_csus_rexmt_t
);
464 * Unlink the DCS block from the server block
466 UNLINK(dcsp
, Scsp_dcs
, dcsp
->sd_server
->ss_dcs
, sd_next
);
469 * Close the VCC to the DCS, if one is open
471 if (dcsp
->sd_sock
!= -1) {
472 close(dcsp
->sd_sock
);
476 * Free any saved CA message
478 if (dcsp
->sd_ca_rexmt_msg
) {
479 scsp_free_msg(dcsp
->sd_ca_rexmt_msg
);
483 * Free any pending CSAs waiting for cache alignment
485 for (csep
= dcsp
->sd_ca_csas
; csep
; csep
= next_cse
) {
486 next_cse
= csep
->sc_next
;
491 * Free anything on the cache request list
493 for (csap
= dcsp
->sd_crl
; csap
; csap
= next_csa
) {
494 next_csa
= csap
->next
;
499 * Free any saved CSUS message
501 if (dcsp
->sd_csus_rexmt_msg
) {
502 scsp_free_msg(dcsp
->sd_csus_rexmt_msg
);
506 * Free anything on the CSU Request retransmit queue
508 for (rxp
= dcsp
->sd_csu_rexmt
; rxp
; rxp
= next_rxp
) {
510 * Cancel the retransmit timer
512 HARP_CANCEL(&rxp
->sr_t
);
515 * Free the CSAs to be retransmitted
517 for (csap
= rxp
->sr_csa
; csap
; csap
= next_csa
) {
518 next_csa
= csap
->next
;
523 * Free the CSU Req retransmission control block
525 next_rxp
= rxp
->sr_next
;
537 * Shut down a server. This routine is called when a connection to
538 * a server is lost. It will clear the server's state without deleting
542 * ssp pointer to a server control block
549 scsp_server_shutdown(Scsp_server
*ssp
)
558 if (scsp_trace_mode
& (SCSP_TRACE_IF_MSG
| SCSP_TRACE_CFSM
)) {
559 scsp_trace("Server %s being shut down\n",
564 * Terminate up all the DCS connections and clean
565 * up the control blocks
567 for (dcsp
= ssp
->ss_dcs
; dcsp
; dcsp
= dcsp
->sd_next
) {
568 if (dcsp
->sd_sock
!= -1) {
569 close(dcsp
->sd_sock
);
572 HARP_CANCEL(&dcsp
->sd_open_t
);
573 HARP_CANCEL(&dcsp
->sd_hello_h_t
);
574 HARP_CANCEL(&dcsp
->sd_hello_rcv_t
);
575 scsp_dcs_cleanup(dcsp
);
576 dcsp
->sd_hello_state
= SCSP_HFSM_DOWN
;
577 dcsp
->sd_ca_state
= SCSP_CAFSM_DOWN
;
578 dcsp
->sd_client_state
= SCSP_CIFSM_NULL
;
582 * Clean up the server control block
584 if (ssp
->ss_sock
!= -1) {
588 if (ssp
->ss_dcs_lsock
!= -1) {
589 close(ssp
->ss_dcs_lsock
);
590 ssp
->ss_dcs_lsock
= -1;
592 ssp
->ss_state
= SCSP_SS_NULL
;
595 * Free the entries in the server's summary cache
597 for (i
= 0; i
< SCSP_HASHSZ
; i
++) {
598 while (ssp
->ss_cache
[i
]) {
599 csep
= ssp
->ss_cache
[i
];
600 UNLINK(csep
, Scsp_cse
, ssp
->ss_cache
[i
],
609 * Delete an SCSP server block and any associated information
612 * ssp pointer to a server control block to delete
619 scsp_server_delete(Scsp_server
*ssp
)
622 Scsp_dcs
*dcsp
, *next_dcs
;
623 Scsp_cse
*csep
, *next_cse
;
626 * Unlink the server block from the chain
628 UNLINK(ssp
, Scsp_server
, scsp_server_head
, ss_next
);
631 * Free the DCS blocks associated with the server
633 for (dcsp
= ssp
->ss_dcs
; dcsp
; dcsp
= next_dcs
) {
634 next_dcs
= dcsp
->sd_next
;
635 scsp_dcs_delete(dcsp
);
639 * Free the entries in the server's summary cache
641 for (i
= 0; i
< SCSP_HASHSZ
; i
++) {
642 for (csep
= ssp
->ss_cache
[i
]; csep
; csep
= next_cse
) {
643 next_cse
= csep
->sc_next
;
649 * Free the server block
651 UM_FREE(ssp
->ss_name
);
657 * Get informtion about a server from the kernel
660 * ssp pointer to the server block
663 * 0 server info is OK
664 * errno server is not ready
668 scsp_get_server_info(Scsp_server
*ssp
)
670 int i
, len
, mtu
, rc
, sel
;
671 struct atminfreq air
;
672 struct air_netif_rsp
*netif_rsp
= NULL
;
673 struct air_int_rsp
*intf_rsp
= NULL
;
674 struct air_cfg_rsp
*cfg_rsp
= NULL
;
675 struct sockaddr_in
*ip_addr
;
679 * Make sure we're the server for the interface
681 if (!scsp_is_atmarp_server(ssp
->ss_intf
)) {
683 goto server_info_done
;
687 * Get the IP address and physical interface name
688 * associated with the network interface
690 UM_ZERO(&air
, sizeof(struct atminfreq
));
691 air
.air_opcode
= AIOCS_INF_NIF
;
692 strcpy(air
.air_netif_intf
, ssp
->ss_intf
);
693 len
= do_info_ioctl(&air
, sizeof(struct air_netif_rsp
));
696 goto server_info_done
;
698 netif_rsp
= (struct air_netif_rsp
*)air
.air_buf_addr
;
700 ip_addr
= (struct sockaddr_in
*)&netif_rsp
->anp_proto_addr
;
701 if (ip_addr
->sin_family
!= AF_INET
||
702 ip_addr
->sin_addr
.s_addr
== 0) {
704 goto server_info_done
;
708 * Get the MTU for the network interface
710 mtu
= get_mtu(ssp
->ss_intf
);
713 goto server_info_done
;
717 * Get the ATM address associated with the
720 UM_ZERO(&air
, sizeof(struct atminfreq
));
721 air
.air_opcode
= AIOCS_INF_INT
;
722 strcpy(air
.air_int_intf
, netif_rsp
->anp_phy_intf
);
723 len
= do_info_ioctl(&air
, sizeof(struct air_int_rsp
));
726 goto server_info_done
;
728 intf_rsp
= (struct air_int_rsp
*)air
.air_buf_addr
;
731 * Make sure we're running UNI signalling
733 if (intf_rsp
->anp_sig_proto
!= ATM_SIG_UNI30
&&
734 intf_rsp
->anp_sig_proto
!= ATM_SIG_UNI31
&&
735 intf_rsp
->anp_sig_proto
!= ATM_SIG_UNI40
) {
737 goto server_info_done
;
741 * Check the physical interface's state
743 if (intf_rsp
->anp_sig_state
!= UNISIG_ACTIVE
) {
745 goto server_info_done
;
749 * Make sure the interface's address is valid
751 if (intf_rsp
->anp_addr
.address_format
!= T_ATM_ENDSYS_ADDR
&&
752 !(intf_rsp
->anp_addr
.address_format
==
754 intf_rsp
->anp_subaddr
.address_format
==
755 T_ATM_ENDSYS_ADDR
)) {
757 goto server_info_done
;
761 * Find the selector byte value for the interface
763 for (i
=0; i
<strlen(ssp
->ss_intf
); i
++) {
764 if (ssp
->ss_intf
[i
] >= '0' &&
765 ssp
->ss_intf
[i
] <= '9')
768 sel
= atoi(&ssp
->ss_intf
[i
]);
771 * Get configuration information associated with the
774 UM_ZERO(&air
, sizeof(struct atminfreq
));
775 air
.air_opcode
= AIOCS_INF_CFG
;
776 strcpy(air
.air_int_intf
, netif_rsp
->anp_phy_intf
);
777 len
= do_info_ioctl(&air
, sizeof(struct air_cfg_rsp
));
780 goto server_info_done
;
782 cfg_rsp
= (struct air_cfg_rsp
*)air
.air_buf_addr
;
785 * Update the server entry
787 UM_COPY(&ip_addr
->sin_addr
, ssp
->ss_lsid
.id
, ssp
->ss_id_len
);
788 ssp
->ss_lsid
.id_len
= ssp
->ss_id_len
;
789 ssp
->ss_mtu
= mtu
+ 8;
790 ATM_ADDR_COPY(&intf_rsp
->anp_addr
, &ssp
->ss_addr
);
791 ATM_ADDR_COPY(&intf_rsp
->anp_subaddr
, &ssp
->ss_subaddr
);
792 if (ssp
->ss_addr
.address_format
== T_ATM_ENDSYS_ADDR
) {
793 anp
= (Atm_addr_nsap
*)ssp
->ss_addr
.address
;
795 } else if (ssp
->ss_addr
.address_format
== T_ATM_E164_ADDR
&&
796 ssp
->ss_subaddr
.address_format
==
798 anp
= (Atm_addr_nsap
*)ssp
->ss_subaddr
.address
;
801 ssp
->ss_media
= cfg_rsp
->acp_cfg
.ac_media
;
820 * Process a CA message
823 * dcsp pointer to a DCS control block for the neighbor
824 * cap pointer to the CA part of the received message
831 scsp_process_ca(Scsp_dcs
* dcsp
, Scsp_ca
*cap
)
833 Scsp_csa
*csap
, *next_csap
;
835 Scsp_server
*ssp
= dcsp
->sd_server
;
838 * Process CSAS records from the CA message
840 for (csap
= cap
->ca_csa_rec
; csap
; csap
= next_csap
) {
841 next_csap
= csap
->next
;
842 SCSP_LOOKUP(ssp
, &csap
->key
, csep
);
843 if (!csep
|| (scsp_cmp_id(&csap
->oid
,
844 &csep
->sc_oid
) == 0 &&
845 csap
->seq
> csep
->sc_seq
)) {
847 * CSAS entry not in cache or more
848 * up to date than cache, add it to CRL
850 UNLINK(csap
, Scsp_csa
, cap
->ca_csa_rec
, next
);
851 LINK2TAIL(csap
, Scsp_csa
, dcsp
->sd_crl
, next
);
858 * Process a Cache Response message from a server
861 * ssp pointer to the server block
862 * smp pointer to the message
869 scsp_process_cache_rsp(Scsp_server
*ssp
, Scsp_if_msg
*smp
)
872 Scsp_atmarp_msg
*aap
;
876 * Loop through the message, processing each cache entry
879 len
-= sizeof(Scsp_if_msg_hdr
);
880 aap
= &smp
->si_atmarp
;
882 switch(smp
->si_proto
) {
883 case SCSP_ATMARP_PROTO
:
885 * If we already have an entry with this key,
888 SCSP_LOOKUP(ssp
, &aap
->sa_key
, csep
);
890 SCSP_DELETE(ssp
, csep
);
895 * Copy the data from the server to a cache
898 csep
= scsp_atmarp2cse(aap
);
901 * Point past this entry
903 len
-= sizeof(Scsp_atmarp_msg
);
906 case SCSP_NHRP_PROTO
:
909 * Not implemented yet
915 * Add the new summary entry to the cache
923 * Propagate a CSA to all the DCSs in the server group except
924 * the one the CSA was received from
927 * dcsp pointer to a the DCS the CSA came from
928 * csap pointer to a the CSA
932 * errno error encountered
936 scsp_propagate_csa(Scsp_dcs
*dcsp
, Scsp_csa
*csap
)
939 Scsp_server
*ssp
= dcsp
->sd_server
;
944 * Check the hop count in the CSA
950 * Pass the cache entry on to the server's other DCSs
952 for (dcsp1
= ssp
->ss_dcs
; dcsp1
; dcsp1
= dcsp1
->sd_next
) {
954 * Skip this DCS if it's the one we got
963 csap1
= scsp_dup_csa(csap
);
966 * Decrement the hop count
971 * Send the copy of the CSA to the CA FSM for the DCS
973 rc
= scsp_cafsm(dcsp1
, SCSP_CAFSM_CACHE_UPD
,
984 * Update SCSP's cache given a CSA or CSAS
987 * dcsp pointer to a DCS
988 * csap pointer to a CSA
995 scsp_update_cache(Scsp_dcs
*dcsp
, Scsp_csa
*csap
)
1000 * Check whether we already have this in the cache
1002 SCSP_LOOKUP(dcsp
->sd_server
, &csap
->key
, csep
);
1005 * If we don't already have it and it's not being deleted,
1006 * build a new cache summary entry
1008 if (!csep
&& !csap
->null
) {
1010 * Get memory for a new entry
1012 csep
= (Scsp_cse
*)UM_ALLOC(sizeof(Scsp_cse
));
1014 scsp_mem_err("scsp_update_cache: sizeof(Scsp_cse)");
1016 UM_ZERO(csep
, sizeof(Scsp_cse
));
1019 * Fill out the new cache summary entry
1021 csep
->sc_seq
= csap
->seq
;
1022 csep
->sc_key
= csap
->key
;
1023 csep
->sc_oid
= csap
->oid
;
1026 * Add the new entry to the cache
1028 SCSP_ADD(dcsp
->sd_server
, csep
);
1032 * Update or delete the entry
1036 * The null flag is set--delete the entry
1039 SCSP_DELETE(dcsp
->sd_server
, csep
);
1044 * Update the existing entry
1046 csep
->sc_seq
= csap
->seq
;
1047 csep
->sc_oid
= csap
->oid
;
1055 * Called as the result of a SIGHUP interrupt. Reread the
1056 * configuration file and solicit the cache from the server.
1066 scsp_reconfigure(void)
1072 * Log a message saying we're reconfiguring
1074 scsp_log(LOG_ERR
, "Reconfiguring ...");
1077 * Re-read the configuration file
1079 rc
= scsp_config(scsp_config_file
);
1081 scsp_log(LOG_ERR
, "Found %d error%s in configuration file",
1082 rc
, ((rc
== 1) ? "" : "s"));
1087 * If a connection to a server is open, get the cache from
1090 for (ssp
= scsp_server_head
; ssp
; ssp
= ssp
->ss_next
) {
1091 if (ssp
->ss_sock
!= -1) {
1092 rc
= scsp_send_cache_ind(ssp
);