3 * ===================================
4 * HARP | Host ATM Research Platform
5 * ===================================
8 * This Host ATM Research Platform ("HARP") file (the "Software") is
9 * made available by Network Computing Services, Inc. ("NetworkCS")
10 * "AS IS". NetworkCS does not provide maintenance, improvements or
11 * support of any kind.
13 * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
14 * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
15 * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
16 * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
17 * In no event shall NetworkCS be responsible for any damages, including
18 * but not limited to consequential damages, arising from or relating to
19 * any use of the Software or related support.
21 * Copyright 1994-1998 Network Computing Services, Inc.
23 * Copies of this Software may be made, however, the above copyright
24 * notice must be reproduced on all copies.
26 * @(#) $FreeBSD: src/usr.sbin/atm/atmarpd/atmarp_scsp.c,v 1.3 1999/08/28 01:15:30 peter Exp $
27 * @(#) $DragonFly: src/usr.sbin/atm/atmarpd/atmarp_scsp.c,v 1.4 2004/12/18 22:48:02 swildner Exp $
31 * Server Cache Synchronization Protocol (SCSP) Support
32 * ----------------------------------------------------
34 * SCSP-ATMARP server interface: SCSP/ATMARP interface code
38 #include <sys/types.h>
39 #include <sys/param.h>
40 #include <sys/socket.h>
42 #include <netinet/in.h>
43 #include <netatm/port.h>
44 #include <netatm/queue.h>
45 #include <netatm/atm.h>
46 #include <netatm/atm_if.h>
47 #include <netatm/atm_sap.h>
48 #include <netatm/atm_sys.h>
49 #include <netatm/atm_ioctl.h>
50 #include <netatm/uni/uniip_var.h>
61 #include "../scspd/scsp_msg.h"
62 #include "../scspd/scsp_if.h"
63 #include "../scspd/scsp_var.h"
64 #include "atmarp_var.h"
67 * Send the cache for a LIS to SCSP
71 * aip pointer to interface block
74 * 0 cache sent to SCSP OK
75 * errno reason for failure
79 atmarp_scsp_cache(Atmarp_intf
*aip
, Scsp_if_msg
*msg
)
83 Scsp_if_msg
*smp
= NULL
;
87 * Figure out how big the message needs to be
89 len
= sizeof(Scsp_if_msg_hdr
);
90 for (i
= 0; i
< ATMARP_HASHSIZ
; i
++) {
91 for (aap
= aip
->ai_arptbl
[i
]; aap
; aap
= aap
->aa_next
) {
92 len
+= sizeof(Scsp_atmarp_msg
);
97 * Get memory for the cache message
99 smp
= (Scsp_if_msg
*)UM_ALLOC(len
);
101 atmarp_mem_err("atmarp_scsp_cache: len");
106 * Set header fields in SCSP message
108 smp
->si_type
= SCSP_CACHE_RSP
;
109 smp
->si_proto
= SCSP_PROTO_ATMARP
;
111 smp
->si_tok
= msg
->si_tok
;
114 * Loop through the cache, adding each entry to the SCSP
115 * Cache Response message
117 sap
= &smp
->si_atmarp
;
118 for (i
= 0; i
< ATMARP_HASHSIZ
; i
++) {
119 for (aap
= aip
->ai_arptbl
[i
]; aap
; aap
= aap
->aa_next
) {
120 sap
->sa_state
= SCSP_ASTATE_NEW
;
121 sap
->sa_cpa
= aap
->aa_dstip
;
122 ATM_ADDR_COPY(&aap
->aa_dstatm
, &sap
->sa_cha
);
123 ATM_ADDR_COPY(&aap
->aa_dstatmsub
, &sap
->sa_csa
);
124 sap
->sa_key
= aap
->aa_key
;
125 sap
->sa_oid
= aap
->aa_oid
;
126 sap
->sa_seq
= aap
->aa_seq
;
132 * Send the message to SCSP
134 rc
= atmarp_scsp_out(aip
, (char *)smp
, len
);
147 * Answer a reqeust for information about a cache entry
150 * aap pointer to entry
151 * state entry's new state
155 * errno reason for failure
159 atmarp_scsp_solicit(Atmarp_intf
*aip
, Scsp_if_msg
*smp
)
163 Scsp_if_msg
*rsp
= NULL
;
166 * Search the interface's ATMARP cache for an entry with
167 * the specified cache key and origin ID
169 for (i
= 0; i
< ATMARP_HASHSIZ
; i
++) {
170 for (aap
= aip
->ai_arptbl
[i
]; aap
; aap
= aap
->aa_next
) {
171 if (KEY_EQUAL(&aap
->aa_key
,
172 &smp
->si_sum
.ss_key
) &&
173 OID_EQUAL(&aap
->aa_oid
,
174 &smp
->si_sum
.ss_oid
))
182 * Get storage for a Solicit Response
184 rsp
= (Scsp_if_msg
*)UM_ALLOC(sizeof(Scsp_if_msg
));
186 atmarp_mem_err("atmarp_scsp_solicit: sizeof(Scsp_if_msg)");
188 UM_ZERO(rsp
, sizeof(Scsp_if_msg
));
191 * Fill out the Solicit Rsp
193 rsp
->si_type
= SCSP_SOLICIT_RSP
;
194 rsp
->si_proto
= smp
->si_proto
;
195 rsp
->si_tok
= smp
->si_tok
;
199 * Copy fields from the ATMARP entry to the SCSP
200 * Update Request message
202 rsp
->si_rc
= SCSP_RSP_OK
;
203 rsp
->si_len
= sizeof(Scsp_if_msg_hdr
) +
204 sizeof(Scsp_atmarp_msg
);
205 rsp
->si_atmarp
.sa_state
= SCSP_ASTATE_UPD
;
206 rsp
->si_atmarp
.sa_cpa
= aap
->aa_dstip
;
207 ATM_ADDR_COPY(&aap
->aa_dstatm
, &rsp
->si_atmarp
.sa_cha
);
208 ATM_ADDR_COPY(&aap
->aa_dstatmsub
, &rsp
->si_atmarp
.sa_csa
);
209 rsp
->si_atmarp
.sa_key
= aap
->aa_key
;
210 rsp
->si_atmarp
.sa_oid
= aap
->aa_oid
;
211 rsp
->si_atmarp
.sa_seq
= aap
->aa_seq
;
214 * Entry not found--set return code
216 rsp
->si_rc
= SCSP_RSP_NOT_FOUND
;
217 rsp
->si_len
= smp
->si_len
;
218 rsp
->si_sum
= smp
->si_sum
;
222 * Send the message to SCSP
224 rc
= atmarp_scsp_out(aip
, (char *)rsp
, rsp
->si_len
);
232 * Send a cache update to SCSP
235 * aap pointer to entry
236 * state entry's new state
240 * errno reason for failure
244 atmarp_scsp_update(Atmarp
*aap
, int state
)
247 Atmarp_intf
*aip
= aap
->aa_intf
;
248 Scsp_if_msg
*smp
= NULL
;
251 * Make sure the connection to SCSP is active
253 if (aip
->ai_state
== AI_STATE_NULL
) {
258 * Get memory for the cache message
260 smp
= (Scsp_if_msg
*)UM_ALLOC(sizeof(Scsp_if_msg
));
262 atmarp_mem_err("atmarp_scsp_update: sizeof(Scsp_if_msg)");
264 UM_ZERO(smp
, sizeof(Scsp_if_msg
));
267 * Set header fields in SCSP message
269 smp
->si_type
= SCSP_UPDATE_REQ
;
270 smp
->si_proto
= SCSP_PROTO_ATMARP
;
271 smp
->si_len
= sizeof(Scsp_if_msg_hdr
) + sizeof(Scsp_atmarp_msg
);
274 * Copy fields from the ATMARP entry to the SCSP
275 * Update Request message
277 smp
->si_atmarp
.sa_state
= state
;
278 smp
->si_atmarp
.sa_cpa
= aap
->aa_dstip
;
279 ATM_ADDR_COPY(&aap
->aa_dstatm
, &smp
->si_atmarp
.sa_cha
);
280 ATM_ADDR_COPY(&aap
->aa_dstatmsub
, &smp
->si_atmarp
.sa_csa
);
281 smp
->si_atmarp
.sa_key
= aap
->aa_key
;
282 smp
->si_atmarp
.sa_oid
= aap
->aa_oid
;
283 smp
->si_atmarp
.sa_seq
= aap
->aa_seq
;
286 * Send the message to SCSP
288 rc
= atmarp_scsp_out(aap
->aa_intf
, (char *)smp
, smp
->si_len
);
296 * Respond to a Cache Update Indication from SCSP
300 * aip pointer to interface control block
301 * smp pointer to message from SCSP
304 * 0 Message processed OK
305 * errno Reason for failure
309 atmarp_scsp_update_in(Atmarp_intf
*aip
, Scsp_if_msg
*smp
)
317 ATMARP_LOOKUP(aip
, smp
->si_atmarp
.sa_cpa
.s_addr
, aap
);
320 * Whether we accept the request depends on whether we
321 * already have an entry for it
325 * We don't have this entry--accept it
330 * We do have an entry for this host--check the
333 if (bcmp(&aip
->ai_ip_addr
.s_addr
,
334 smp
->si_atmarp
.sa_oid
.id
,
335 SCSP_ATMARP_ID_LEN
) == 0) {
337 * The received entry originated with us--
341 } else if (bcmp(&aip
->ai_ip_addr
.s_addr
,
343 SCSP_ATMARP_ID_LEN
) == 0) {
345 * We originated the entry we currently have--
346 * only accept the new one if SCSP has higher
347 * priority than the existing entry
349 accept
= aap
->aa_origin
< UAO_SCSP
;
352 * Accept the entry if it is more up-to-date
353 * than the existing entry
355 accept
= KEY_EQUAL(&aap
->aa_key
,
356 &smp
->si_atmarp
.sa_key
) &&
357 OID_EQUAL(&aap
->aa_oid
,
358 &smp
->si_atmarp
.sa_oid
) &&
359 (aap
->aa_seq
< smp
->si_atmarp
.sa_seq
);
364 * Add the entry to the cache, if appropriate
369 * Copy info from SCSP to a new cache entry
371 aap
= (Atmarp
*)UM_ALLOC(sizeof(Atmarp
));
373 atmarp_mem_err("atmarp_scsp_update_in: sizeof(Atmarp)");
374 UM_ZERO(aap
, sizeof(Atmarp
));
376 aap
->aa_dstip
= smp
->si_atmarp
.sa_cpa
;
377 aap
->aa_dstatm
= smp
->si_atmarp
.sa_cha
;
378 aap
->aa_dstatmsub
= smp
->si_atmarp
.sa_csa
;
379 aap
->aa_key
= smp
->si_atmarp
.sa_key
;
380 aap
->aa_oid
= smp
->si_atmarp
.sa_oid
;
381 aap
->aa_seq
= smp
->si_atmarp
.sa_seq
;
383 aap
->aa_origin
= UAO_SCSP
;
386 * Add the new entry to our cache
388 ATMARP_ADD(aip
, aap
);
391 * Update the existing entry
393 aap
->aa_dstip
= smp
->si_atmarp
.sa_cpa
;
394 aap
->aa_dstatm
= smp
->si_atmarp
.sa_cha
;
395 aap
->aa_dstatmsub
= smp
->si_atmarp
.sa_csa
;
396 aap
->aa_key
= smp
->si_atmarp
.sa_key
;
397 aap
->aa_oid
= smp
->si_atmarp
.sa_oid
;
398 aap
->aa_seq
= smp
->si_atmarp
.sa_seq
;
399 aap
->aa_origin
= UAO_SCSP
;
403 * Send the updated entry to the kernel
405 if (atmarp_update_kernel(aap
) == 0)
414 * Turn the received message into a response
416 smp
->si_type
= SCSP_UPDATE_RSP
;
420 * Send the message to SCSP
422 rc
= atmarp_scsp_out(aip
, (char *)smp
, smp
->si_len
);
429 * Read and process a message from SCSP
433 * aip interface for read
437 * errno reason for failure
441 atmarp_scsp_read(Atmarp_intf
*aip
)
446 Scsp_if_msg_hdr msg_hdr
;
449 * Read the header of the message from SCSP
451 len
= read(aip
->ai_scsp_sock
, (char *)&msg_hdr
,
456 } else if (len
!= sizeof(msg_hdr
)) {
462 * Get a buffer that will hold the message
464 buff
= UM_ALLOC(msg_hdr
.sh_len
);
466 atmarp_mem_err("atmarp_scsp_read: msg_hdr.sh_len");
467 UM_COPY(&msg_hdr
, buff
, sizeof(msg_hdr
));
470 * Read the rest of the message, if there is more than
473 len
= msg_hdr
.sh_len
- sizeof(msg_hdr
);
475 len
= read(aip
->ai_scsp_sock
, buff
+ sizeof(msg_hdr
),
480 } else if (len
!= msg_hdr
.sh_len
- sizeof(msg_hdr
)) {
487 * Handle the message based on its type
489 smp
= (Scsp_if_msg
*)buff
;
490 switch(smp
->si_type
) {
492 if (smp
->si_rc
!= SCSP_RSP_OK
) {
498 rc
= atmarp_scsp_cache(aip
, smp
);
500 case SCSP_SOLICIT_IND
:
501 rc
= atmarp_scsp_solicit(aip
, smp
);
503 case SCSP_UPDATE_IND
:
504 rc
= atmarp_scsp_update_in(aip
, smp
);
506 case SCSP_UPDATE_RSP
:
508 * Ignore Update Responses
512 atmarp_log(LOG_ERR
, "Unexpected SCSP message received");
525 * Error on socket to SCSP--close the socket and set the state
526 * so that we know to retry when the cache timer fires.
528 atmarp_scsp_close(aip
);
535 * Send a message to SCSP
539 * aip pointer to ATMARP interface to send message on
540 * buff pointer to message buffer
541 * len length of message
545 * errno reason for failure
549 atmarp_scsp_out(Atmarp_intf
*aip
, char *buff
, int len
)
554 * Send the message to SCSP
556 rc
= write(aip
->ai_scsp_sock
, buff
, len
);
561 * Error on write--close the socket to SCSP, clean up and
562 * set the state so that we know to retry when the cache
565 atmarp_scsp_close(aip
);
568 * Set the return code
581 * Set up a socket and connect to SCSP
584 * aip pointer to interface block
587 * 0 success, ai_scsp_sock is set
588 * errno reason for failure
593 atmarp_scsp_connect(Atmarp_intf
*aip
)
599 static struct sockaddr local_addr
= {
600 #if (defined(BSD) && (BSD >= 199103))
601 sizeof(struct sockaddr
), /* sa_len */
603 AF_UNIX
, /* sa_family */
604 ATMARP_SOCK_PREFIX
/* sa_data */
606 static struct sockaddr scsp_addr
= {
607 #if (defined(BSD) && (BSD >= 199103))
608 sizeof(struct sockaddr
), /* sa_len */
610 AF_UNIX
, /* sa_family */
611 SCSPD_SOCK_NAME
/* sa_data */
615 * Construct a name for the socket
617 strncpy(local_addr
.sa_data
, ATMARP_SOCK_PREFIX
,
618 sizeof(local_addr
.sa_data
));
619 strncat(local_addr
.sa_data
, aip
->ai_intf
, sizeof(local_addr
.sa_data
));
620 sn
= strdup(local_addr
.sa_data
);
622 atmarp_mem_err("atmarp_scsp_connect: strdup");
625 * Clean up any old socket
628 if (rc
< 0 && errno
!= ENOENT
)
632 * Open a socket to SCSP
634 sd
= socket(PF_UNIX
, SOCK_STREAM
, 0);
639 if (sd
> atmarp_max_socket
) {
640 atmarp_max_socket
= sd
;
644 * Set non-blocking I/O
647 rc
= fcntl(sd
, F_SETFL
, FNBIO
+ FNDELAY
);
649 rc
= fcntl(sd
, F_SETFL
, O_NONBLOCK
);
653 goto scsp_connect_fail
;
657 * Bind the local socket address
659 rc
= bind(sd
, &local_addr
, sizeof(local_addr
));
662 goto scsp_connect_fail
;
668 rc
= connect(sd
, &scsp_addr
, sizeof(scsp_addr
));
671 goto scsp_connect_fail
;
675 * Save socket information in interface control block
677 aip
->ai_scsp_sock
= sd
;
678 aip
->ai_scsp_sockname
= sn
;
679 aip
->ai_state
= AI_STATE_UP
;
682 * Send configuration information to SCSP
684 UM_ZERO(&cfg_msg
, sizeof(cfg_msg
));
685 cfg_msg
.si_type
= SCSP_CFG_REQ
;
686 cfg_msg
.si_proto
= SCSP_PROTO_ATMARP
;
687 strcpy(cfg_msg
.si_cfg
.atmarp_netif
, aip
->ai_intf
);
688 len
=sizeof(Scsp_if_msg_hdr
) + strlen(aip
->ai_intf
) + 1;
689 cfg_msg
.si_len
= len
;
690 rc
= atmarp_scsp_out(aip
, (char *)&cfg_msg
, len
);
699 aip
->ai_scsp_sock
= -1;
701 aip
->ai_scsp_sockname
= NULL
;
702 aip
->ai_state
= AI_STATE_NULL
;
708 * Close a socket connection to SCSP
711 * aip pointer to interface block for connection to be closed
719 atmarp_scsp_close(Atmarp_intf
*aip
)
722 * Close and unlink the SCSP socket
724 close(aip
->ai_scsp_sock
);
725 aip
->ai_scsp_sock
= -1;
726 unlink(aip
->ai_scsp_sockname
);
727 UM_FREE(aip
->ai_scsp_sockname
);
728 aip
->ai_scsp_sockname
= NULL
;
730 aip
->ai_state
= AI_STATE_NULL
;
737 * Disconnect an interface from SCSP
740 * aip pointer to interface block for connection to be closed
743 * 0 success, ai_scsp_sock is set
744 * errno reason for failure
749 atmarp_scsp_disconnect(Atmarp_intf
*aip
)
755 * Close and unlink the SCSP socket
757 atmarp_scsp_close(aip
);
760 * Free the ATMARP cache associated with the interface
762 for (i
= 0; i
< ATMARP_HASHSIZ
; i
++) {
763 for (aap
= aip
->ai_arptbl
[i
]; aap
; aap
= aap
->aa_next
) {
766 aip
->ai_arptbl
[i
] = NULL
;