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