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.
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 __RCSID("@(#) $FreeBSD$");
72 * Hash an SCSP cache key
75 * ckp pointer to an SCSP cache key structure
88 * Turn cache key into a positive integer
91 for (i = ckp->key_len-1, j = 0;
92 i > 0 && j < sizeof(int);
94 h = (h << 8) + ckp->key[i];
98 * Return the hashed value
100 return(h % SCSP_HASHSZ);
105 * Compare two SCSP IDs
108 * id1p pointer to an SCSP ID structure
109 * id2p pointer to an SCSP ID structure
112 * < 0 id1 is less than id2
113 * 0 id1 and id2 are equal
114 * > 0 id1 is greater than id2
118 scsp_cmp_id(id1p, id2p)
125 * Compare the two IDs, byte for byte
127 for (i = 0; i < id1p->id_len && i < id2p->id_len; i++) {
128 diff = id1p->id[i] - id2p->id[i];
135 * IDs are equal. If lengths differ, the longer ID is
136 * greater than the shorter.
138 return(id1p->id_len - id2p->id_len);
143 * Compare two SCSP cache keys
146 * ck1p pointer to an SCSP cache key structure
147 * ck2p pointer to an SCSP cache key structure
150 * < 0 ck1 is less than ck2
151 * 0 ck1 and ck2 are equal
152 * > 0 ck1 is greater than ck2
156 scsp_cmp_key(ck1p, ck2p)
163 * Compare the two keys, byte for byte
165 for (i = 0; i < ck1p->key_len && i < ck2p->key_len; i++) {
166 diff = ck1p->key[i] - ck2p->key[i];
172 * Keys are equal. If lengths differ, the longer key is
173 * greater than the shorter.
175 return(ck1p->key_len - ck2p->key_len);
180 * Check whether the host system is an ATMARP server for
181 * the LIS associated with a given interface
184 * netif pointer to the network interface name
188 * 0 host is not a server
192 scsp_is_atmarp_server(netif)
197 struct atminfreq air;
198 struct air_asrv_rsp *asrv_info;
201 * Get interface information from the kernel
203 strcpy(air.air_int_intf, netif);
204 air.air_opcode = AIOCS_INF_ASV;
205 buf_len = do_info_ioctl(&air, sizeof(struct air_asrv_rsp));
206 if ((ssize_t)buf_len == -1)
210 * Check the interface's ATMARP server address
212 asrv_info = (struct air_asrv_rsp *) air.air_buf_addr;
213 rc = (asrv_info->asp_addr.address_format == T_ATM_ABSENT) &&
214 (asrv_info->asp_subaddr.address_format ==
222 * Make a copy of a cache summary entry
225 * csep pointer to CSE entry to copy
229 * else pointer to new CSE entry
239 * Allocate memory for the duplicate
241 dupp = malloc(sizeof(Scsp_cse));
243 scsp_mem_err("scsp_dup_cse: sizeof(Scsp_cse)");
246 * Copy data to the duplicate
248 bcopy(csep, dupp, sizeof(Scsp_cse));
249 dupp->sc_next = (Scsp_cse *)0;
255 * Make a copy of a CSA or CSAS record
258 * csap pointer to CSE entry to copy
262 * else pointer to new CSA or CSAS record
270 Scsp_atmarp_csa *adp;
273 * Allocate memory for the duplicate
275 dupp = malloc(sizeof(Scsp_csa));
277 scsp_mem_err("scsp_dup_csa: sizeof(Scsp_csa)");
280 * Copy data to the duplicate
282 bcopy(csap, dupp, sizeof(Scsp_csa));
283 dupp->next = (Scsp_csa *)0;
286 * Copy protocol-specific data, if it's present
288 if (csap->atmarp_data) {
289 adp = malloc(sizeof(Scsp_atmarp_csa));
291 scsp_mem_err("scsp_dup_csa: sizeof(Scsp_atmarp_csa)");
292 bcopy(csap->atmarp_data, adp, sizeof(Scsp_atmarp_csa));
293 dupp->atmarp_data = adp;
300 * Copy a cache summary entry into a CSAS
303 * csep pointer to CSE entry to copy
307 * else pointer to CSAS record summarizing the entry
317 * Allocate memory for the duplicate
319 csap = calloc(1, sizeof(Scsp_csa));
321 scsp_mem_err("scsp_cse2csas: sizeof(Scsp_csa)");
324 * Copy data to the CSAS entry
326 csap->seq = csep->sc_seq;
327 csap->key = csep->sc_key;
328 csap->oid = csep->sc_oid;
335 * Copy an ATMARP cache entry into a cache summary entry
338 * aap pointer to ATMARP cache entry to copy
342 * else pointer to CSE record summarizing the entry
347 Scsp_atmarp_msg *aap;
352 * Allocate memory for the duplicate
354 csep = calloc(1, sizeof(Scsp_cse));
356 scsp_mem_err("scsp_atmarp2cse: sizeof(Scsp_cse)");
359 * Copy data to the CSE entry
361 csep->sc_seq = aap->sa_seq;
362 csep->sc_key = aap->sa_key;
363 csep->sc_oid = aap->sa_oid;
370 * Clean up a DCS block. This routine is called to clear out any
371 * lingering state information when the CA FSM reverts to an 'earlier'
372 * state (Down or Master/Slave Negotiation).
375 * dcsp pointer to a DCS control block for the neighbor
382 scsp_dcs_cleanup(dcsp)
385 Scsp_cse *csep, *ncsep;
386 Scsp_csa *csap, *next_csap;
387 Scsp_csu_rexmt *rxp, *rx_next;
390 * Free any CSAS entries waiting to be sent
392 for (csep = dcsp->sd_ca_csas; csep; csep = ncsep) {
393 ncsep = csep->sc_next;
394 UNLINK(csep, Scsp_cse, dcsp->sd_ca_csas, sc_next);
399 * Free any entries on the CRL
401 for (csap = dcsp->sd_crl; csap; csap = next_csap) {
402 next_csap = csap->next;
403 UNLINK(csap, Scsp_csa, dcsp->sd_crl, next);
408 * Free any saved CA message and cancel the CA
409 * retransmission timer
411 if (dcsp->sd_ca_rexmt_msg) {
412 scsp_free_msg(dcsp->sd_ca_rexmt_msg);
413 dcsp->sd_ca_rexmt_msg = (Scsp_msg *)0;
415 HARP_CANCEL(&dcsp->sd_ca_rexmt_t);
418 * Free any saved CSU Solicit message and cancel the CSUS
419 * retransmission timer
421 if (dcsp->sd_csus_rexmt_msg) {
422 scsp_free_msg(dcsp->sd_csus_rexmt_msg);
423 dcsp->sd_csus_rexmt_msg = (Scsp_msg *)0;
425 HARP_CANCEL(&dcsp->sd_csus_rexmt_t);
428 * Free any entries on the CSU Request retransmission queue
430 for (rxp = dcsp->sd_csu_rexmt; rxp; rxp = rx_next) {
431 rx_next = rxp->sr_next;
432 HARP_CANCEL(&rxp->sr_t);
433 for (csap = rxp->sr_csa; csap; csap = next_csap) {
434 next_csap = csap->next;
437 UNLINK(rxp, Scsp_csu_rexmt, dcsp->sd_csu_rexmt,
445 * Delete an SCSP DCS block and any associated information
448 * dcsp pointer to a DCS control block to delete
455 scsp_dcs_delete(dcsp)
458 Scsp_cse *csep, *next_cse;
459 Scsp_csu_rexmt *rxp, *next_rxp;
460 Scsp_csa *csap, *next_csa;
463 * Cancel any pending DCS timers
465 HARP_CANCEL(&dcsp->sd_open_t);
466 HARP_CANCEL(&dcsp->sd_hello_h_t);
467 HARP_CANCEL(&dcsp->sd_hello_rcv_t);
468 HARP_CANCEL(&dcsp->sd_ca_rexmt_t);
469 HARP_CANCEL(&dcsp->sd_csus_rexmt_t);
472 * Unlink the DCS block from the server block
474 UNLINK(dcsp, Scsp_dcs, dcsp->sd_server->ss_dcs, sd_next);
477 * Close the VCC to the DCS, if one is open
479 if (dcsp->sd_sock != -1) {
480 (void)close(dcsp->sd_sock);
484 * Free any saved CA message
486 if (dcsp->sd_ca_rexmt_msg) {
487 scsp_free_msg(dcsp->sd_ca_rexmt_msg);
491 * Free any pending CSAs waiting for cache alignment
493 for (csep = dcsp->sd_ca_csas; csep; csep = next_cse) {
494 next_cse = csep->sc_next;
499 * Free anything on the cache request list
501 for (csap = dcsp->sd_crl; csap; csap = next_csa) {
502 next_csa = csap->next;
507 * Free any saved CSUS message
509 if (dcsp->sd_csus_rexmt_msg) {
510 scsp_free_msg(dcsp->sd_csus_rexmt_msg);
514 * Free anything on the CSU Request retransmit queue
516 for (rxp = dcsp->sd_csu_rexmt; rxp; rxp = next_rxp) {
518 * Cancel the retransmit timer
520 HARP_CANCEL(&rxp->sr_t);
523 * Free the CSAs to be retransmitted
525 for (csap = rxp->sr_csa; csap; csap = next_csa) {
526 next_csa = csap->next;
531 * Free the CSU Req retransmission control block
533 next_rxp = rxp->sr_next;
545 * Shut down a server. This routine is called when a connection to
546 * a server is lost. It will clear the server's state without deleting
550 * ssp pointer to a server control block
557 scsp_server_shutdown(ssp)
567 if (scsp_trace_mode & (SCSP_TRACE_IF_MSG | SCSP_TRACE_CFSM)) {
568 scsp_trace("Server %s being shut down\n",
573 * Terminate up all the DCS connections and clean
574 * up the control blocks
576 for (dcsp = ssp->ss_dcs; dcsp; dcsp = dcsp->sd_next) {
577 if (dcsp->sd_sock != -1) {
578 (void)close(dcsp->sd_sock);
581 HARP_CANCEL(&dcsp->sd_open_t);
582 HARP_CANCEL(&dcsp->sd_hello_h_t);
583 HARP_CANCEL(&dcsp->sd_hello_rcv_t);
584 scsp_dcs_cleanup(dcsp);
585 dcsp->sd_hello_state = SCSP_HFSM_DOWN;
586 dcsp->sd_ca_state = SCSP_CAFSM_DOWN;
587 dcsp->sd_client_state = SCSP_CIFSM_NULL;
591 * Clean up the server control block
593 if (ssp->ss_sock != -1) {
594 (void)close(ssp->ss_sock);
597 if (ssp->ss_dcs_lsock != -1) {
598 (void)close(ssp->ss_dcs_lsock);
599 ssp->ss_dcs_lsock = -1;
601 ssp->ss_state = SCSP_SS_NULL;
604 * Free the entries in the server's summary cache
606 for (i = 0; i < SCSP_HASHSZ; i++) {
607 while (ssp->ss_cache[i]) {
608 csep = ssp->ss_cache[i];
609 UNLINK(csep, Scsp_cse, ssp->ss_cache[i],
618 * Delete an SCSP server block and any associated information
621 * ssp pointer to a server control block to delete
628 scsp_server_delete(ssp)
632 Scsp_dcs *dcsp, *next_dcs;
633 Scsp_cse *csep, *next_cse;
636 * Unlink the server block from the chain
638 UNLINK(ssp, Scsp_server, scsp_server_head, ss_next);
641 * Free the DCS blocks associated with the server
643 for (dcsp = ssp->ss_dcs; dcsp; dcsp = next_dcs) {
644 next_dcs = dcsp->sd_next;
645 scsp_dcs_delete(dcsp);
649 * Free the entries in the server's summary cache
651 for (i = 0; i < SCSP_HASHSZ; i++) {
652 for (csep = ssp->ss_cache[i]; csep; csep = next_cse) {
653 next_cse = csep->sc_next;
659 * Free the server block
667 * Get informtion about a server from the kernel
670 * ssp pointer to the server block
673 * 0 server info is OK
674 * errno server is not ready
678 scsp_get_server_info(ssp)
683 struct atminfreq air;
684 struct air_netif_rsp *netif_rsp = (struct air_netif_rsp *)0;
685 struct air_int_rsp *intf_rsp = (struct air_int_rsp *)0;
686 struct air_cfg_rsp *cfg_rsp = (struct air_cfg_rsp *)0;
687 struct sockaddr_in *ip_addr;
691 * Make sure we're the server for the interface
693 if (!scsp_is_atmarp_server(ssp->ss_intf)) {
695 goto server_info_done;
699 * Get the IP address and physical interface name
700 * associated with the network interface
702 bzero(&air, sizeof(struct atminfreq));
703 air.air_opcode = AIOCS_INF_NIF;
704 strcpy(air.air_netif_intf, ssp->ss_intf);
705 len = do_info_ioctl(&air, sizeof(struct air_netif_rsp));
706 if ((ssize_t)len == -1 || len == 0) {
708 goto server_info_done;
710 netif_rsp = (struct air_netif_rsp *)air.air_buf_addr;
712 ip_addr = (struct sockaddr_in *)&netif_rsp->anp_proto_addr;
713 if (ip_addr->sin_family != AF_INET ||
714 ip_addr->sin_addr.s_addr == 0) {
716 goto server_info_done;
720 * Get the MTU for the network interface
722 mtu = get_mtu(ssp->ss_intf);
725 goto server_info_done;
729 * Get the ATM address associated with the
732 bzero(&air, sizeof(struct atminfreq));
733 air.air_opcode = AIOCS_INF_INT;
734 strcpy(air.air_int_intf, netif_rsp->anp_phy_intf);
735 len = do_info_ioctl(&air, sizeof(struct air_int_rsp));
736 if ((ssize_t)len == -1 || len == 0) {
738 goto server_info_done;
740 intf_rsp = (struct air_int_rsp *)air.air_buf_addr;
743 * Make sure we're running UNI signalling
745 if (intf_rsp->anp_sig_proto != ATM_SIG_UNI30 &&
746 intf_rsp->anp_sig_proto != ATM_SIG_UNI31 &&
747 intf_rsp->anp_sig_proto != ATM_SIG_UNI40) {
749 goto server_info_done;
753 * Check the physical interface's state
755 if (intf_rsp->anp_sig_state != UNISIG_ACTIVE) {
757 goto server_info_done;
761 * Make sure the interface's address is valid
763 if (intf_rsp->anp_addr.address_format != T_ATM_ENDSYS_ADDR &&
764 !(intf_rsp->anp_addr.address_format ==
766 intf_rsp->anp_subaddr.address_format ==
767 T_ATM_ENDSYS_ADDR)) {
769 goto server_info_done;
773 * Find the selector byte value for the interface
775 for (i=0; i<strlen(ssp->ss_intf); i++) {
776 if (ssp->ss_intf[i] >= '0' &&
777 ssp->ss_intf[i] <= '9')
780 sel = atoi(&ssp->ss_intf[i]);
783 * Get configuration information associated with the
786 bzero(&air, sizeof(struct atminfreq));
787 air.air_opcode = AIOCS_INF_CFG;
788 strcpy(air.air_int_intf, netif_rsp->anp_phy_intf);
789 len = do_info_ioctl(&air, sizeof(struct air_cfg_rsp));
790 if ((ssize_t)len == -1 || len == 0) {
792 goto server_info_done;
794 cfg_rsp = (struct air_cfg_rsp *)air.air_buf_addr;
797 * Update the server entry
799 bcopy(&ip_addr->sin_addr, ssp->ss_lsid.id, ssp->ss_id_len);
800 ssp->ss_lsid.id_len = ssp->ss_id_len;
801 ssp->ss_mtu = mtu + 8;
802 ATM_ADDR_COPY(&intf_rsp->anp_addr, &ssp->ss_addr);
803 ATM_ADDR_COPY(&intf_rsp->anp_subaddr, &ssp->ss_subaddr);
804 if (ssp->ss_addr.address_format == T_ATM_ENDSYS_ADDR) {
805 anp = (Atm_addr_nsap *)ssp->ss_addr.address;
807 } else if (ssp->ss_addr.address_format == T_ATM_E164_ADDR &&
808 ssp->ss_subaddr.address_format ==
810 anp = (Atm_addr_nsap *)ssp->ss_subaddr.address;
813 ssp->ss_media = cfg_rsp->acp_cfg.ac_media;
832 * Process a CA message
835 * dcsp pointer to a DCS control block for the neighbor
836 * cap pointer to the CA part of the received message
843 scsp_process_ca(dcsp, cap)
847 Scsp_csa *csap, *next_csap;
849 Scsp_server *ssp = dcsp->sd_server;
852 * Process CSAS records from the CA message
854 for (csap = cap->ca_csa_rec; csap; csap = next_csap) {
855 next_csap = csap->next;
856 SCSP_LOOKUP(ssp, &csap->key, csep);
857 if (!csep || (scsp_cmp_id(&csap->oid,
858 &csep->sc_oid) == 0 &&
859 csap->seq > csep->sc_seq)) {
861 * CSAS entry not in cache or more
862 * up to date than cache, add it to CRL
864 UNLINK(csap, Scsp_csa, cap->ca_csa_rec, next);
865 LINK2TAIL(csap, Scsp_csa, dcsp->sd_crl, next);
872 * Process a Cache Response message from a server
875 * ssp pointer to the server block
876 * smp pointer to the message
883 scsp_process_cache_rsp(ssp, smp)
888 Scsp_atmarp_msg *aap;
892 * Loop through the message, processing each cache entry
895 len -= sizeof(Scsp_if_msg_hdr);
896 aap = &smp->si_atmarp;
898 switch(smp->si_proto) {
899 case SCSP_ATMARP_PROTO:
901 * If we already have an entry with this key,
904 SCSP_LOOKUP(ssp, &aap->sa_key, csep);
906 SCSP_DELETE(ssp, csep);
911 * Copy the data from the server to a cache
914 csep = scsp_atmarp2cse(aap);
917 * Point past this entry
919 len -= sizeof(Scsp_atmarp_msg);
922 case SCSP_NHRP_PROTO:
925 * Not implemented yet
931 * Add the new summary entry to the cache
939 * Propagate a CSA to all the DCSs in the server group except
940 * the one the CSA was received from
943 * dcsp pointer to a the DCS the CSA came from
944 * csap pointer to a the CSA
948 * errno error encountered
952 scsp_propagate_csa(dcsp, csap)
957 Scsp_server *ssp = dcsp->sd_server;
962 * Check the hop count in the CSA
968 * Pass the cache entry on to the server's other DCSs
970 for (dcsp1 = ssp->ss_dcs; dcsp1; dcsp1 = dcsp1->sd_next) {
972 * Skip this DCS if it's the one we got
981 csap1 = scsp_dup_csa(csap);
984 * Decrement the hop count
989 * Send the copy of the CSA to the CA FSM for the DCS
991 rc = scsp_cafsm(dcsp1, SCSP_CAFSM_CACHE_UPD,
1002 * Update SCSP's cache given a CSA or CSAS
1005 * dcsp pointer to a DCS
1006 * csap pointer to a CSA
1013 scsp_update_cache(dcsp, csap)
1020 * Check whether we already have this in the cache
1022 SCSP_LOOKUP(dcsp->sd_server, &csap->key, csep);
1025 * If we don't already have it and it's not being deleted,
1026 * build a new cache summary entry
1028 if (!csep && !csap->null) {
1030 * Get memory for a new entry
1032 csep = calloc(1, sizeof(Scsp_cse));
1034 scsp_mem_err("scsp_update_cache: sizeof(Scsp_cse)");
1037 * Fill out the new cache summary entry
1039 csep->sc_seq = csap->seq;
1040 csep->sc_key = csap->key;
1041 csep->sc_oid = csap->oid;
1044 * Add the new entry to the cache
1046 SCSP_ADD(dcsp->sd_server, csep);
1050 * Update or delete the entry
1054 * The null flag is set--delete the entry
1057 SCSP_DELETE(dcsp->sd_server, csep);
1062 * Update the existing entry
1064 csep->sc_seq = csap->seq;
1065 csep->sc_oid = csap->oid;
1073 * Called as the result of a SIGHUP interrupt. Reread the
1074 * configuration file and solicit the cache from the server.
1090 * Log a message saying we're reconfiguring
1092 scsp_log(LOG_ERR, "Reconfiguring ...");
1095 * Re-read the configuration file
1097 rc = scsp_config(scsp_config_file);
1099 scsp_log(LOG_ERR, "Found %d error%s in configuration file",
1100 rc, ((rc == 1) ? "" : "s"));
1105 * If a connection to a server is open, get the cache from
1108 for (ssp = scsp_server_head; ssp; ssp = ssp->ss_next) {
1109 if (ssp->ss_sock != -1) {
1110 rc = scsp_send_cache_ind(ssp);