8dcac54708029fc59c397711c5e7ffd0e1e2a491
[dragonfly.git] / usr.sbin / atm / scspd / scsp_subr.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_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.3 2003/11/15 20:33:43 eirikn Exp $
28  */
29
30
31 /*
32  * Server Cache Synchronization Protocol (SCSP) Support
33  * ----------------------------------------------------
34  *
35  * SCSP subroutines
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_sigmgr.h>
50 #include <netatm/atm_sys.h>
51 #include <netatm/atm_ioctl.h>
52 #include <netatm/uni/unisig_var.h>
53
54 #include <errno.h>
55 #include <libatm.h>
56 #include <stdio.h>
57 #include <stdlib.h>
58 #include <string.h>
59 #include <syslog.h>
60 #include <unistd.h>
61
62 #include "scsp_msg.h"
63 #include "scsp_if.h"
64 #include "scsp_var.h"
65
66 /*
67  * Hash an SCSP cache key
68  *
69  * Arguments:
70  *      ckp     pointer to an SCSP cache key structure
71  *
72  * Returns:
73  *      hashed value
74  *
75  */
76 int
77 scsp_hash(Scsp_ckey *ckp)
78 {
79         int     i, j, h;
80
81         /*
82          * Turn cache key into a positive integer
83          */
84         h = 0;
85         for (i = ckp->key_len-1, j = 0;
86                         i > 0 && j < sizeof(int);
87                         i--, j++)
88                 h = (h << 8) + ckp->key[i];
89         h = abs(h);
90
91         /*
92          * Return the hashed value
93          */
94         return(h % SCSP_HASHSZ);
95 }
96
97
98 /*
99  * Compare two SCSP IDs
100  *
101  * Arguments:
102  *      id1p    pointer to an SCSP ID structure
103  *      id2p    pointer to an SCSP ID structure
104  *
105  * Returns:
106  *      < 0     id1 is less than id2
107  *      0       id1 and id2 are equal
108  *      > 0     id1 is greater than id2
109  *
110  */
111 int
112 scsp_cmp_id(Scsp_id *id1p, Scsp_id *id2p)
113 {
114         int     diff, i;
115
116         /*
117          * Compare the two IDs, byte for byte
118          */
119         for (i = 0; i < id1p->id_len && i < id2p->id_len; i++) {
120                 diff = id1p->id[i] - id2p->id[i];
121                 if (diff) {
122                         return(diff);
123                 }
124         }
125
126         /*
127          * IDs are equal.  If lengths differ, the longer ID is
128          * greater than the shorter.
129          */
130         return(id1p->id_len - id2p->id_len);
131 }
132
133
134 /*
135  * Compare two SCSP cache keys
136  *
137  * Arguments:
138  *      ck1p    pointer to an SCSP cache key structure
139  *      ck2p    pointer to an SCSP cache key structure
140  *
141  * Returns:
142  *      < 0     ck1 is less than ck2
143  *      0       ck1 and ck2 are equal
144  *      > 0     ck1 is greater than ck2
145  *
146  */
147 int
148 scsp_cmp_key(Scsp_ckey *ck1p, Scsp_ckey *ck2p)
149 {
150         int     diff, i;
151
152         /*
153          * Compare the two keys, byte for byte
154          */
155         for (i = 0; i < ck1p->key_len && i < ck2p->key_len; i++) {
156                 diff = ck1p->key[i] - ck2p->key[i];
157                 if (diff)
158                         return(diff);
159         }
160
161         /*
162          * Keys are equal.  If lengths differ, the longer key is
163          * greater than the shorter.
164          */
165         return(ck1p->key_len - ck2p->key_len);
166 }
167
168
169 /*
170  * Check whether the host system is an ATMARP server for
171  * the LIS associated with a given interface
172  *
173  * Arguments:
174  *      netif   pointer to the network interface name
175  *
176  * Returns:
177  *      1       host is a server
178  *      0       host is not a server
179  *
180  */
181 int
182 scsp_is_atmarp_server(char *netif)
183 {
184         int                     rc;
185         int                     buf_len = sizeof(struct air_asrv_rsp);
186         struct atminfreq        air;
187         struct air_asrv_rsp     *asrv_info;
188
189         /*
190          * Get interface information from the kernel
191          */
192         strcpy(air.air_int_intf, netif);
193         air.air_opcode = AIOCS_INF_ASV;
194         buf_len = do_info_ioctl(&air, buf_len);
195         if (buf_len < 0)
196                 return(0);
197
198         /*
199          * Check the interface's ATMARP server address
200          */
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 ==
204                                 T_ATM_ABSENT);
205         UM_FREE(asrv_info);
206         return(rc);
207 }
208
209
210 /*
211  * Make a copy of a cache summary entry
212  *
213  * Arguments:
214  *      csep    pointer to CSE entry to copy
215  *
216  * Returns:
217  *      0       copy failed
218  *      else    pointer to new CSE entry
219  *
220  */
221 Scsp_cse *
222 scsp_dup_cse(Scsp_cse *csep)
223 {
224         Scsp_cse        *dupp;
225
226         /*
227          * Allocate memory for the duplicate
228          */
229         dupp = (Scsp_cse *)UM_ALLOC(sizeof(Scsp_cse));
230         if (!dupp) {
231                 scsp_mem_err("scsp_dup_cse: sizeof(Scsp_cse)");
232         }
233
234         /*
235          * Copy data to the duplicate
236          */
237         UM_COPY(csep, dupp, sizeof(Scsp_cse));
238         dupp->sc_next = (Scsp_cse *)0;
239
240         return(dupp);
241 }
242
243
244 /*
245  * Make a copy of a CSA or CSAS record
246  *
247  * Arguments:
248  *      csap    pointer to CSE entry to copy
249  *
250  * Returns:
251  *      0       copy failed
252  *      else    pointer to new CSA or CSAS record
253  *
254  */
255 Scsp_csa *
256 scsp_dup_csa(Scsp_csa *csap)
257 {
258         Scsp_csa        *dupp;
259         Scsp_atmarp_csa *adp;
260
261         /*
262          * Allocate memory for the duplicate
263          */
264         dupp = (Scsp_csa *)UM_ALLOC(sizeof(Scsp_csa));
265         if (!dupp) {
266                 scsp_mem_err("scsp_dup_csa: sizeof(Scsp_csa)");
267         }
268
269         /*
270          * Copy data to the duplicate
271          */
272         UM_COPY(csap, dupp, sizeof(Scsp_csa));
273         dupp->next = (Scsp_csa *)0;
274
275         /*
276          * Copy protocol-specific data, if it's present
277          */
278         if (csap->atmarp_data) {
279                 adp = (Scsp_atmarp_csa *)UM_ALLOC(sizeof(Scsp_atmarp_csa));
280                 if (!adp) {
281                         scsp_mem_err("scsp_dup_csa: sizeof(Scsp_atmarp_csa)");
282                 }
283                 UM_COPY(csap->atmarp_data, adp, sizeof(Scsp_atmarp_csa));
284                 dupp->atmarp_data  = adp;
285         }
286
287         return(dupp);
288 }
289
290
291 /*
292  * Copy a cache summary entry into a CSAS
293  *
294  * Arguments:
295  *      csep    pointer to CSE entry to copy
296  *
297  * Returns:
298  *      0       copy failed
299  *      else    pointer to CSAS record summarizing the entry
300  *
301  */
302 Scsp_csa *
303 scsp_cse2csas(Scsp_cse *csep)
304 {
305         Scsp_csa        *csap;
306
307         /*
308          * Allocate memory for the duplicate
309          */
310         csap = (Scsp_csa *)UM_ALLOC(sizeof(Scsp_csa));
311         if (!csap) {
312                 scsp_mem_err("scsp_cse2csas: sizeof(Scsp_csa)");
313         }
314         UM_ZERO(csap, sizeof(Scsp_csa));
315
316         /*
317          * Copy data to the CSAS entry
318          */
319         csap->seq = csep->sc_seq;
320         csap->key = csep->sc_key;
321         csap->oid = csep->sc_oid;
322
323         return(csap);
324 }
325
326
327 /*
328  * Copy an ATMARP cache entry into a cache summary entry
329  *
330  * Arguments:
331  *      aap     pointer to ATMARP cache entry to copy
332  *
333  * Returns:
334  *      0       copy failed
335  *      else    pointer to CSE record summarizing the entry
336  *
337  */
338 Scsp_cse *
339 scsp_atmarp2cse(Scsp_atmarp_msg *aap)
340 {
341         Scsp_cse        *csep;
342
343         /*
344          * Allocate memory for the duplicate
345          */
346         csep = (Scsp_cse *)UM_ALLOC(sizeof(Scsp_cse));
347         if (!csep) {
348                 scsp_mem_err("scsp_atmarp2cse: sizeof(Scsp_cse)");
349         }
350         UM_ZERO(csep, sizeof(Scsp_cse));
351
352         /*
353          * Copy data to the CSE entry
354          */
355         csep->sc_seq = aap->sa_seq;
356         csep->sc_key = aap->sa_key;
357         csep->sc_oid = aap->sa_oid;
358
359         return(csep);
360 }
361
362
363 /*
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).
367  *
368  * Arguments:
369  *      dcsp    pointer to a DCS control block for the neighbor
370  *
371  * Returns:
372  *      none
373  *
374  */
375 void
376 scsp_dcs_cleanup(Scsp_dcs *dcsp)
377 {
378         Scsp_cse        *csep, *ncsep;
379         Scsp_csa        *csap, *next_csap;
380         Scsp_csu_rexmt  *rxp, *rx_next;
381
382         /*
383          * Free any CSAS entries waiting to be sent
384          */
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);
388                 UM_FREE(csep);
389         }
390
391         /*
392          * Free any entries on the CRL
393          */
394         for (csap = dcsp->sd_crl; csap; csap = next_csap) {
395                 next_csap = csap->next;
396                 UNLINK(csap, Scsp_csa, dcsp->sd_crl, next);
397                 SCSP_FREE_CSA(csap);
398         }
399
400         /*
401          * Free any saved CA message and cancel the CA
402          * retransmission timer
403          */
404         if (dcsp->sd_ca_rexmt_msg) {
405                 scsp_free_msg(dcsp->sd_ca_rexmt_msg);
406                 dcsp->sd_ca_rexmt_msg = (Scsp_msg *)0;
407         }
408         HARP_CANCEL(&dcsp->sd_ca_rexmt_t);
409
410         /*
411          * Free any saved CSU Solicit message and cancel the CSUS
412          * retransmission timer
413          */
414         if (dcsp->sd_csus_rexmt_msg) {
415                 scsp_free_msg(dcsp->sd_csus_rexmt_msg);
416                 dcsp->sd_csus_rexmt_msg = (Scsp_msg *)0;
417         }
418         HARP_CANCEL(&dcsp->sd_csus_rexmt_t);
419
420         /*
421          * Free any entries on the CSU Request retransmission queue
422          */
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;
428                         SCSP_FREE_CSA(csap);
429                 }
430                 UNLINK(rxp, Scsp_csu_rexmt, dcsp->sd_csu_rexmt,
431                                 sr_next);
432                 UM_FREE(rxp);
433         }
434 }
435
436
437 /*
438  * Delete an SCSP DCS block and any associated information
439  *
440  * Arguments:
441  *      dcsp    pointer to a DCS control block to delete
442  *
443  * Returns:
444  *      none
445  *
446  */
447 void
448 scsp_dcs_delete(Scsp_dcs *dcsp)
449 {
450         Scsp_cse        *csep, *next_cse;
451         Scsp_csu_rexmt  *rxp, *next_rxp;
452         Scsp_csa        *csap, *next_csa;
453
454         /*
455          * Cancel any pending DCS timers
456          */
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);
462
463         /*
464          * Unlink the DCS block from the server block
465          */
466         UNLINK(dcsp, Scsp_dcs, dcsp->sd_server->ss_dcs, sd_next);
467
468         /*
469          * Close the VCC to the DCS, if one is open
470          */
471         if (dcsp->sd_sock != -1) {
472                 (void)close(dcsp->sd_sock);
473         }
474
475         /*
476          * Free any saved CA message
477          */
478         if (dcsp->sd_ca_rexmt_msg) {
479                 scsp_free_msg(dcsp->sd_ca_rexmt_msg);
480         }
481
482         /*
483          * Free any pending CSAs waiting for cache alignment
484          */
485         for (csep = dcsp->sd_ca_csas; csep; csep = next_cse) {
486                 next_cse = csep->sc_next;
487                 UM_FREE(csep);
488         }
489
490         /*
491          * Free anything on the cache request list
492          */
493         for (csap = dcsp->sd_crl; csap; csap = next_csa) {
494                 next_csa = csap->next;
495                 SCSP_FREE_CSA(csap);
496         }
497
498         /*
499          * Free any saved CSUS message
500          */
501         if (dcsp->sd_csus_rexmt_msg) {
502                 scsp_free_msg(dcsp->sd_csus_rexmt_msg);
503         }
504
505         /*
506          * Free anything on the CSU Request retransmit queue
507          */
508         for (rxp = dcsp->sd_csu_rexmt; rxp; rxp = next_rxp) {
509                 /*
510                  * Cancel the retransmit timer
511                  */
512                 HARP_CANCEL(&rxp->sr_t);
513
514                 /*
515                  * Free the CSAs to be retransmitted
516                  */
517                 for (csap = rxp->sr_csa; csap; csap = next_csa) {
518                         next_csa = csap->next;
519                         SCSP_FREE_CSA(csap);
520                 }
521
522                 /*
523                  * Free the CSU Req retransmission control block
524                  */
525                 next_rxp = rxp->sr_next;
526                 UM_FREE(rxp);
527         }
528
529         /*
530          * Free the DCS block
531          */
532         UM_FREE(dcsp);
533 }
534
535
536 /*
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
539  * the server.
540  *
541  * Arguments:
542  *      ssp     pointer to a server control block
543  *
544  * Returns:
545  *      none
546  *
547  */
548 void
549 scsp_server_shutdown(Scsp_server *ssp)
550 {
551         int             i;
552         Scsp_dcs        *dcsp;
553         Scsp_cse        *csep;
554
555         /*
556          * Trace the shutdown
557          */
558         if (scsp_trace_mode & (SCSP_TRACE_IF_MSG | SCSP_TRACE_CFSM)) {
559                 scsp_trace("Server %s being shut down\n",
560                                 ssp->ss_name);
561         }
562
563         /*
564          * Terminate up all the DCS connections and clean
565          * up the control blocks
566          */
567         for (dcsp = ssp->ss_dcs; dcsp; dcsp = dcsp->sd_next) {
568                 if (dcsp->sd_sock != -1) {
569                         (void)close(dcsp->sd_sock);
570                         dcsp->sd_sock = -1;
571                 }
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;
579         }
580
581         /*
582          * Clean up the server control block
583          */
584         if (ssp->ss_sock != -1) {
585                 (void)close(ssp->ss_sock);
586                 ssp->ss_sock = -1;
587         }
588         if (ssp->ss_dcs_lsock != -1) {
589                 (void)close(ssp->ss_dcs_lsock);
590                 ssp->ss_dcs_lsock = -1;
591         }
592         ssp->ss_state = SCSP_SS_NULL;
593
594         /*
595          * Free the entries in the server's summary cache
596          */
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],
601                                         sc_next);
602                         UM_FREE(csep);
603                 }
604         }
605 }
606
607
608 /*
609  * Delete an SCSP server block and any associated information
610  *
611  * Arguments:
612  *      ssp     pointer to a server control block to delete
613  *
614  * Returns:
615  *      none
616  *
617  */
618 void
619 scsp_server_delete(Scsp_server *ssp)
620 {
621         int             i;
622         Scsp_dcs        *dcsp, *next_dcs;
623         Scsp_cse        *csep, *next_cse;
624
625         /*
626          * Unlink the server block from the chain
627          */
628         UNLINK(ssp, Scsp_server, scsp_server_head, ss_next);
629
630         /*
631          * Free the DCS blocks associated with the server
632          */
633         for (dcsp = ssp->ss_dcs; dcsp; dcsp = next_dcs) {
634                 next_dcs = dcsp->sd_next;
635                 scsp_dcs_delete(dcsp);
636         }
637
638         /*
639          * Free the entries in the server's summary cache
640          */
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;
644                         UM_FREE(csep);
645                 }
646         }
647
648         /*
649          * Free the server block
650          */
651         UM_FREE(ssp->ss_name);
652         UM_FREE(ssp);
653 }
654
655
656 /*
657  * Get informtion about a server from the kernel
658  *
659  * Arguments:
660  *      ssp     pointer to the server block
661  *
662  * Returns:
663  *      0       server info is OK
664  *      errno   server is not ready
665  *
666  */
667 int
668 scsp_get_server_info(Scsp_server *ssp)
669 {
670         int                     i, len, mtu, rc, sel;
671         struct atminfreq        air;
672         struct air_netif_rsp    *netif_rsp = (struct air_netif_rsp *)0;
673         struct air_int_rsp      *intf_rsp = (struct air_int_rsp *)0;
674         struct air_cfg_rsp      *cfg_rsp = (struct air_cfg_rsp *)0;
675         struct sockaddr_in      *ip_addr;
676         Atm_addr_nsap           *anp;
677
678         /*
679          * Make sure we're the server for the interface
680          */
681         if (!scsp_is_atmarp_server(ssp->ss_intf)) {
682                 rc = EINVAL;
683                 goto server_info_done;
684         }
685
686         /*
687          * Get the IP address and physical interface name
688          * associated with the network interface
689          */
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));
694         if (len <= 0) {
695                 rc = EIO;
696                 goto server_info_done;
697         }
698         netif_rsp = (struct air_netif_rsp *)air.air_buf_addr;
699
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) {
703                 rc = EADDRNOTAVAIL;
704                 goto server_info_done;
705         }
706
707         /*
708          * Get the MTU for the network interface
709          */
710         mtu = get_mtu(ssp->ss_intf);
711         if (mtu < 0) {
712                 rc = EIO;
713                 goto server_info_done;
714         }
715
716         /*
717          * Get the ATM address associated with the
718          * physical interface
719          */
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));
724         if (len <= 0) {
725                 rc = EIO;
726                 goto server_info_done;
727         }
728         intf_rsp = (struct air_int_rsp *)air.air_buf_addr;
729
730         /*
731          * Make sure we're running UNI signalling
732          */
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) {
736                 rc = EINVAL;
737                 goto server_info_done;
738         }
739
740         /*
741          * Check the physical interface's state
742          */
743         if (intf_rsp->anp_sig_state != UNISIG_ACTIVE) {
744                 rc = EHOSTDOWN;
745                 goto server_info_done;
746         }
747
748         /*
749          * Make sure the interface's address is valid
750          */
751         if (intf_rsp->anp_addr.address_format != T_ATM_ENDSYS_ADDR &&
752                         !(intf_rsp->anp_addr.address_format ==
753                                 T_ATM_E164_ADDR &&
754                         intf_rsp->anp_subaddr.address_format ==
755                                 T_ATM_ENDSYS_ADDR)) {
756                 rc = EINVAL;
757                 goto server_info_done;
758         }
759
760         /*
761          * Find the selector byte value for the interface
762          */
763         for (i=0; i<strlen(ssp->ss_intf); i++) {
764                 if (ssp->ss_intf[i] >= '0' &&
765                                 ssp->ss_intf[i] <= '9')
766                         break;
767         }
768         sel = atoi(&ssp->ss_intf[i]);
769
770         /*
771          * Get configuration information associated with the
772          * physical interface
773          */
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));
778         if (len <= 0) {
779                 rc = EIO;
780                 goto server_info_done;
781         }
782         cfg_rsp = (struct air_cfg_rsp *)air.air_buf_addr;
783
784         /*
785          * Update the server entry
786          */
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;
794                 anp->aan_sel = sel;
795         } else if (ssp->ss_addr.address_format == T_ATM_E164_ADDR &&
796                         ssp->ss_subaddr.address_format ==
797                                 T_ATM_ENDSYS_ADDR) {
798                 anp = (Atm_addr_nsap *)ssp->ss_subaddr.address;
799                 anp->aan_sel = sel;
800         }
801         ssp->ss_media = cfg_rsp->acp_cfg.ac_media;
802         rc = 0;
803
804         /*
805          * Free dynamic data
806          */
807 server_info_done:
808         if (netif_rsp)
809                 UM_FREE(netif_rsp);
810         if (intf_rsp)
811                 UM_FREE(intf_rsp);
812         if (cfg_rsp)
813                 UM_FREE(cfg_rsp);
814
815         return(rc);
816 }
817
818
819 /*
820  * Process a CA message
821  *
822  * Arguments:
823  *      dcsp    pointer to a DCS control block for the neighbor
824  *      cap     pointer to the CA part of the received message
825  *
826  * Returns:
827  *      none
828  *
829  */
830 void
831 scsp_process_ca(Scsp_dcs* dcsp, Scsp_ca *cap)
832 {
833         Scsp_csa        *csap, *next_csap;
834         Scsp_cse        *csep;
835         Scsp_server     *ssp = dcsp->sd_server;
836
837         /*
838          * Process CSAS records from the CA message
839          */
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)) {
846                         /*
847                          * CSAS entry not in cache or more
848                          * up to date than cache, add it to CRL
849                          */
850                         UNLINK(csap, Scsp_csa, cap->ca_csa_rec, next);
851                         LINK2TAIL(csap, Scsp_csa, dcsp->sd_crl, next);
852                 }
853         }
854 }
855
856
857 /*
858  * Process a Cache Response message from a server
859  *
860  * Arguments:
861  *      ssp     pointer to the server block
862  *      smp     pointer to the message
863  *
864  * Returns:
865  *      none
866  *
867  */
868 void
869 scsp_process_cache_rsp(Scsp_server *ssp, Scsp_if_msg *smp)
870 {
871         int             len;
872         Scsp_atmarp_msg *aap;
873         Scsp_cse        *csep;
874
875         /*
876          * Loop through the message, processing each cache entry
877          */
878         len = smp->si_len;
879         len -= sizeof(Scsp_if_msg_hdr);
880         aap = &smp->si_atmarp;
881         while (len > 0) {
882                 switch(smp->si_proto) {
883                 case SCSP_ATMARP_PROTO:
884                         /*
885                          * If we already have an entry with this key,
886                          * delete it
887                          */
888                         SCSP_LOOKUP(ssp, &aap->sa_key, csep);
889                         if (csep) {
890                                 SCSP_DELETE(ssp, csep);
891                                 UM_FREE(csep);
892                         }
893
894                         /*
895                          * Copy the data from the server to a cache
896                          * summary entry
897                          */
898                         csep = scsp_atmarp2cse(aap);
899
900                         /*
901                          * Point past this entry
902                          */
903                         len -= sizeof(Scsp_atmarp_msg);
904                         aap++;
905                         break;
906                 case SCSP_NHRP_PROTO:
907                 default:
908                         /*
909                          * Not implemented yet
910                          */
911                         return;
912                 }
913
914                 /*
915                  * Add the new summary entry to the cache
916                  */
917                 SCSP_ADD(ssp, csep);
918         }
919 }
920
921
922 /*
923  * Propagate a CSA to all the DCSs in the server group except
924  * the one the CSA was received from
925  *
926  * Arguments:
927  *      dcsp    pointer to a the DCS the CSA came from
928  *      csap    pointer to a the CSA
929  *
930  * Returns:
931  *      0       success
932  *      errno   error encountered
933  *
934  */
935 int
936 scsp_propagate_csa(Scsp_dcs *dcsp, Scsp_csa *csap)
937 {
938         int             rc, ret_rc = 0;
939         Scsp_server     *ssp = dcsp->sd_server;
940         Scsp_dcs        *dcsp1;
941         Scsp_csa        *csap1;
942
943         /*
944          * Check the hop count in the CSA
945          */
946         if (csap->hops <= 1)
947                 return(0);
948
949         /*
950          * Pass the cache entry on to the server's other DCSs
951          */
952         for (dcsp1 = ssp->ss_dcs; dcsp1; dcsp1 = dcsp1->sd_next) {
953                 /*
954                  * Skip this DCS if it's the one we got
955                  * the entry from
956                  */
957                 if (dcsp1 == dcsp)
958                         continue;
959
960                 /*
961                  * Copy the  CSA
962                  */
963                 csap1 = scsp_dup_csa(csap);
964
965                 /*
966                  * Decrement the hop count
967                  */
968                 csap1->hops--;
969
970                 /*
971                  * Send the copy of the CSA to the CA FSM for the DCS
972                  */
973                 rc = scsp_cafsm(dcsp1, SCSP_CAFSM_CACHE_UPD,
974                                 (void *) csap1);
975                 if (rc)
976                         ret_rc = rc;
977         }
978
979         return(ret_rc);
980 }
981
982
983 /*
984  * Update SCSP's cache given a CSA or CSAS
985  *
986  * Arguments:
987  *      dcsp    pointer to a DCS 
988  *      csap    pointer to a CSA
989  *
990  * Returns:
991  *      none
992  *
993  */
994 void
995 scsp_update_cache(Scsp_dcs *dcsp, Scsp_csa *csap)
996 {
997         Scsp_cse        *csep;
998
999         /*
1000          * Check whether we already have this in the cache
1001          */
1002         SCSP_LOOKUP(dcsp->sd_server, &csap->key, csep);
1003
1004         /*
1005          * If we don't already have it and it's not being deleted,
1006          * build a new cache summary entry
1007          */
1008         if (!csep && !csap->null) {
1009                 /*
1010                  * Get memory for a new entry
1011                  */
1012                 csep = (Scsp_cse *)UM_ALLOC(sizeof(Scsp_cse));
1013                 if (!csep) {
1014                         scsp_mem_err("scsp_update_cache: sizeof(Scsp_cse)");
1015                 }
1016                 UM_ZERO(csep, sizeof(Scsp_cse));
1017
1018                 /*
1019                  * Fill out the new cache summary entry
1020                  */
1021                 csep->sc_seq = csap->seq;
1022                 csep->sc_key = csap->key;
1023                 csep->sc_oid = csap->oid;
1024
1025                 /*
1026                  * Add the new entry to the cache
1027                  */
1028                 SCSP_ADD(dcsp->sd_server, csep);
1029         } 
1030
1031         /*
1032          * Update or delete the entry
1033          */
1034         if (csap->null) {
1035                 /*
1036                  * The null flag is set--delete the entry
1037                  */
1038                 if (csep) {
1039                         SCSP_DELETE(dcsp->sd_server, csep);
1040                         UM_FREE(csep);
1041                 }
1042         } else {
1043                 /*
1044                  * Update the existing entry
1045                  */
1046                 csep->sc_seq = csap->seq;
1047                 csep->sc_oid = csap->oid;
1048         }
1049 }
1050
1051
1052 /*
1053  * Reconfigure SCSP
1054  *
1055  * Called as the result of a SIGHUP interrupt.  Reread the
1056  * configuration file and solicit the cache from the server.
1057  *
1058  * Arguments:
1059  *      none
1060  *
1061  * Returns:
1062  *      none
1063  *
1064  */
1065 void
1066 scsp_reconfigure(void)
1067 {
1068         int             rc;
1069         Scsp_server     *ssp;
1070
1071         /*
1072          * Log a message saying we're reconfiguring
1073          */
1074         scsp_log(LOG_ERR, "Reconfiguring ...");
1075
1076         /*
1077          * Re-read the configuration file
1078          */
1079         rc = scsp_config(scsp_config_file);
1080         if (rc) {
1081                 scsp_log(LOG_ERR, "Found %d error%s in configuration file",
1082                                 rc, ((rc == 1) ? "" : "s"));
1083                 exit(1);
1084         }
1085
1086         /*
1087          * If a connection to a server is open, get the cache from
1088          * the server
1089          */
1090         for (ssp = scsp_server_head; ssp; ssp = ssp->ss_next) {
1091                 if (ssp->ss_sock != -1) {
1092                         rc = scsp_send_cache_ind(ssp);
1093                 }
1094         }
1095 }