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