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/scspd/scsp_output.c,v 1.3 1999/08/28 01:15:33 peter Exp $
27 * @(#) $DragonFly: src/usr.sbin/atm/scspd/scsp_output.c,v 1.4 2004/12/18 22:48:02 swildner Exp $
31 * Server Cache Synchronization Protocol (SCSP) Support
32 * ----------------------------------------------------
34 * Output packet processing
38 #include <sys/types.h>
39 #include <sys/param.h>
40 #include <sys/socket.h>
41 #include <net/ethernet.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_sys.h>
50 #include <netatm/atm_ioctl.h>
65 * Put a long integer into the output buffer
67 * This routine is provided for cases where long ints may not be
68 * word-aligned in the output buffer.
72 * cp pointer to output buffer
79 put_long(u_long l
, u_char
*cp
)
84 * Convert to network order and copy to output buffer
87 UM_COPY(&nl
, cp
, sizeof(u_long
));
92 * Format a Sender or Receiver ID
95 * idp ponter to ID structure
100 * else length of ID processed
104 scsp_format_id(Scsp_id
*idp
, char *buff
)
109 UM_COPY(idp
->id
, buff
, idp
->id_len
);
112 * Return the ID length
119 * Format the Mandatory Common Part of an SCSP input packet
123 * buff pointer to mandatory common part
126 * 0 input was invalid
127 * else length of MCP in message
131 scsp_format_mcp(Scsp_mcp
*mcp
, char *buff
)
135 struct scsp_nmcp
*smp
;
138 * Set the protocol ID
140 smp
= (struct scsp_nmcp
*)buff
;
141 smp
->sm_pid
= htons(mcp
->pid
);
144 * Set the server group ID
146 smp
->sm_sgid
= htons(mcp
->sgid
);
151 smp
->sm_flags
= htons(mcp
->flags
);
154 * Set the sender ID and length
156 smp
->sm_sid_len
= mcp
->sid
.id_len
;
157 odp
= buff
+ sizeof(struct scsp_nmcp
);
158 len
= scsp_format_id(&mcp
->sid
, odp
);
164 * Set the receiver ID and length
166 smp
->sm_rid_len
= mcp
->rid
.id_len
;
167 odp
+= mcp
->sid
.id_len
;
168 len
= scsp_format_id(&mcp
->rid
, odp
);
174 * Set the record count
176 smp
->sm_rec_cnt
= htons(mcp
->rec_cnt
);
179 * Return the length of data we processed
181 return(sizeof(struct scsp_nmcp
) + mcp
->sid
.id_len
+
190 * Format an Extension
193 * exp pointer to extension in internal format
194 * buff pointer to output buffer
195 * blen space available in buffer
198 * 0 input was invalid
199 * else length of extension processed
203 scsp_format_ext(Scsp_ext
*exp
, char *buff
, int blen
)
205 struct scsp_next
*sep
;
208 * Make sure there's room in the buffer
210 if (blen
< (sizeof(struct scsp_next
) + exp
->len
))
216 sep
= (struct scsp_next
*)buff
;
217 sep
->se_type
= htons(exp
->type
);
222 sep
->se_len
= htons(exp
->len
);
228 buff
+= sizeof(struct scsp_next
);
229 UM_COPY((caddr_t
)exp
+ sizeof(Scsp_ext
),
235 * Return the number of bytes processed
237 return(sizeof(struct scsp_next
) + exp
->len
);
242 * Format the ATMARP part of a CSA record
245 * acsp pointer to ATMARP protocol-specific CSA record
246 * buff pointer to output buffer
249 * 0 input was invalid
250 * else length of record processed
254 scsp_format_atmarp(Scsp_atmarp_csa
*acsp
, char *buff
)
258 struct scsp_atmarp_ncsa
*sanp
;
261 * Figure out how long PDU is going to be
263 pkt_len
= sizeof(struct scsp_atmarp_ncsa
);
264 switch (acsp
->sa_sha
.address_format
) {
265 case T_ATM_ENDSYS_ADDR
:
266 pkt_len
+= acsp
->sa_sha
.address_length
;
269 case T_ATM_E164_ADDR
:
270 pkt_len
+= acsp
->sa_sha
.address_length
;
271 if (acsp
->sa_ssa
.address_format
== T_ATM_ENDSYS_ADDR
)
272 pkt_len
+= acsp
->sa_ssa
.address_length
;
276 switch (acsp
->sa_tha
.address_format
) {
277 case T_ATM_ENDSYS_ADDR
:
278 pkt_len
+= acsp
->sa_tha
.address_length
;
281 case T_ATM_E164_ADDR
:
282 pkt_len
+= acsp
->sa_tha
.address_length
;
283 if (acsp
->sa_tha
.address_format
== T_ATM_ENDSYS_ADDR
)
284 pkt_len
+= acsp
->sa_tha
.address_length
;
288 if (acsp
->sa_spa
.s_addr
!= 0)
289 pkt_len
+= sizeof(struct in_addr
);
291 if (acsp
->sa_tpa
.s_addr
!= 0)
292 pkt_len
+= sizeof(struct in_addr
);
297 sanp
= (struct scsp_atmarp_ncsa
*)buff
;
298 cp
= (char *)sanp
+ sizeof(struct scsp_atmarp_ncsa
);
303 sanp
->sa_hrd
= htons(ARP_ATMFORUM
);
304 sanp
->sa_pro
= htons(ETHERTYPE_IP
);
307 len
= acsp
->sa_sha
.address_length
;
308 switch (acsp
->sa_sha
.address_format
) {
309 case T_ATM_ENDSYS_ADDR
:
310 sanp
->sa_shtl
= ARP_TL_NSAPA
| (len
& ARP_TL_LMASK
);
313 UM_COPY(acsp
->sa_sha
.address
, cp
, len
);
319 case T_ATM_E164_ADDR
:
320 sanp
->sa_shtl
= ARP_TL_E164
| (len
& ARP_TL_LMASK
);
323 UM_COPY(acsp
->sa_sha
.address
, cp
, len
);
326 if (acsp
->sa_ssa
.address_format
== T_ATM_ENDSYS_ADDR
) {
327 len
= acsp
->sa_ssa
.address_length
;
328 sanp
->sa_sstl
= ARP_TL_NSAPA
|
329 (len
& ARP_TL_LMASK
);
332 UM_COPY(acsp
->sa_ssa
.address
, cp
, len
);
344 sanp
->sa_state
= acsp
->sa_state
;
348 if (acsp
->sa_spa
.s_addr
!= 0) {
349 sanp
->sa_spln
= sizeof(struct in_addr
);
350 UM_COPY(&acsp
->sa_spa
, cp
, sizeof(struct in_addr
));
351 cp
+= sizeof(struct in_addr
);
355 len
= acsp
->sa_tha
.address_length
;
356 switch (acsp
->sa_tha
.address_format
) {
357 case T_ATM_ENDSYS_ADDR
:
358 sanp
->sa_thtl
= ARP_TL_NSAPA
| (len
& ARP_TL_LMASK
);
361 UM_COPY(acsp
->sa_tha
.address
, cp
, len
);
367 case T_ATM_E164_ADDR
:
368 sanp
->sa_thtl
= ARP_TL_E164
| (len
& ARP_TL_LMASK
);
371 UM_COPY(acsp
->sa_tha
.address
, cp
, len
);
374 if (acsp
->sa_tsa
.address_format
== T_ATM_ENDSYS_ADDR
) {
375 len
= acsp
->sa_tha
.address_length
;
376 sanp
->sa_tstl
= ARP_TL_NSAPA
|
377 (len
& ARP_TL_LMASK
);
380 UM_COPY(acsp
->sa_tsa
.address
, cp
, len
);
392 if (acsp
->sa_tpa
.s_addr
!= 0) {
393 sanp
->sa_tpln
= sizeof(struct in_addr
);
394 UM_COPY(&acsp
->sa_tpa
, cp
, sizeof(struct in_addr
));
402 * Format a Cache State Advertisement or Cache State Advertisement
406 * csapp pointer to CSA or CSAS
407 * buff pointer to output buffer
410 * 0 input was invalid
411 * else length of record processed
415 scsp_format_csa(Scsp_csa
*csap
, char *buff
)
419 struct scsp_ncsa
*scp
;
424 scp
= (struct scsp_ncsa
*)buff
;
425 scp
->scs_hop_cnt
= htons(csap
->hops
);
431 scp
->scs_nfill
= htons(SCSP_CSAS_NULL
);
435 * Set the sequence number
437 put_long(csap
->seq
, (u_char
*)&scp
->scs_seq
);
442 scp
->scs_ck_len
= csap
->key
.key_len
;
443 odp
= buff
+ sizeof(struct scsp_ncsa
);
444 UM_COPY(csap
->key
.key
, odp
, scp
->scs_ck_len
);
447 * Set the originator ID
449 odp
+= scp
->scs_ck_len
;
450 scp
->scs_oid_len
= scsp_format_id(&csap
->oid
, odp
);
453 * Set the protocol-specific data, if present. At the
454 * moment, we only handle data for ATMARP.
456 if (csap
->atmarp_data
) {
457 odp
+= scp
->scs_oid_len
;
458 len
= scsp_format_atmarp(csap
->atmarp_data
, odp
);
462 * Set the record length
464 scp
->scs_len
= htons(sizeof(struct scsp_ncsa
) +
465 scp
->scs_ck_len
+ scp
->scs_oid_len
+
469 * Return the length of data we processed
471 return(ntohs(scp
->scs_len
));
476 * Format a Cache Alignment message
479 * cap pointer to CA message
480 * buff pointer to output buffer
481 * blen space available in buffer
484 * 0 input was invalid
485 * else length of CA message processed
489 scsp_format_ca(Scsp_ca
*cap
, char *buff
, int blen
)
491 int i
, len
, proc_len
;
492 struct scsp_nca
*scap
;
496 * Set the sequence number
498 scap
= (struct scsp_nca
*)buff
;
499 put_long(cap
->ca_seq
, (u_char
*)&scap
->sca_seq
);
500 proc_len
= sizeof(scap
->sca_seq
);
501 buff
+= sizeof(scap
->sca_seq
);
506 cap
->ca_mcp
.flags
= 0;
508 cap
->ca_mcp
.flags
|= SCSP_CA_M
;
510 cap
->ca_mcp
.flags
|= SCSP_CA_I
;
512 cap
->ca_mcp
.flags
|= SCSP_CA_O
;
515 * Format the mandatory common part of the message
517 len
= scsp_format_mcp(&cap
->ca_mcp
, buff
);
524 * Put any CSAS records into the message
526 for (i
= 0, csap
= cap
->ca_csa_rec
; i
< cap
->ca_mcp
.rec_cnt
;
527 i
++, csap
= csap
->next
) {
528 len
= scsp_format_csa(csap
, buff
);
531 if (proc_len
> blen
) {
532 scsp_log(LOG_CRIT
, "scsp_format_ca: buffer overflow");
538 * Return the length of processed data
548 * Format a Cache State Update Request, Cache State Update Reply, or
549 * Cache State Update Solicit message. These all have the same format,
550 * a Mandatory Common Part followed by a number of CSA or CSAS records.
553 * csup pointer to location to put pointer to CSU Req message
554 * buff pointer to output buffer
555 * blen space available in buffer
558 * 0 input was invalid
559 * else length of CSU Req message processed
563 scsp_format_csu(Scsp_csu_msg
*csup
, char *buff
, int blen
)
565 int i
, len
, proc_len
;
566 struct scsp_ncsu_msg
*scsup
;
570 * Format the mandatory common part of the message
572 scsup
= (struct scsp_ncsu_msg
*)buff
;
573 len
= scsp_format_mcp(&csup
->csu_mcp
, buff
);
580 * Put the CSAS records into the message
582 for (i
= 0, csap
= csup
->csu_csa_rec
;
583 i
< csup
->csu_mcp
.rec_cnt
&& csap
;
584 i
++, csap
= csap
->next
) {
585 len
= scsp_format_csa(csap
, buff
);
588 if (proc_len
> blen
) {
589 scsp_log(LOG_CRIT
, "scsp_format_csu: buffer overflow");
595 * Return the length of processed data
605 * Format a Hello message
608 * hpp pointer to Hello message
609 * buff pointer to output buffer
610 * blen space available in buffer
613 * 0 input was invalid
614 * else length of Hello message processed
618 scsp_format_hello(Scsp_hello
*hp
, char *buff
, int blen
)
621 struct scsp_nhello
*shp
;
625 * Set the hello interval
627 shp
= (struct scsp_nhello
*)buff
;
628 shp
->sch_hi
= htons(hp
->hello_int
);
631 * Set the dead factor
633 shp
->sch_df
= htons(hp
->dead_factor
);
638 shp
->sch_fid
= htons(hp
->family_id
);
641 * Process the mandatory common part of the message
643 proc_len
= sizeof(struct scsp_nhello
) -
644 sizeof(struct scsp_nmcp
);
646 len
= scsp_format_mcp(&hp
->hello_mcp
, buff
);
653 * Add any additional receiver ID records to the message
655 for (ridp
= hp
->hello_mcp
.rid
.next
; ridp
;
657 len
= scsp_format_id(ridp
, buff
);
666 * Return the length of the Hello message body
668 if (proc_len
> blen
) {
669 scsp_log(LOG_CRIT
, "scsp_format_hello: buffer overflow");
680 * Format an SCSP output packet
683 * dcsp pointer to DCS for which message is being prepared
684 * msg pointer to input packet
685 * bpp pointer to location to put pointer to formatted packet
688 * 0 input packet was invalid
689 * else length of formatted packet
693 scsp_format_msg(Scsp_dcs
*dcsp
, Scsp_msg
*msg
, char **bpp
)
695 char *buff
= NULL
, *e_buff
= NULL
;
696 int buff_len
, e_buff_len
;
697 int e_len
, len
, plen
;
698 struct scsp_nhdr
*shp
;
702 * Allocate a buffer for the message
704 buff_len
= dcsp
->sd_server
->ss_mtu
;
705 buff
= (char *)UM_ALLOC(buff_len
);
707 scsp_mem_err("scsp_format_msg: dcsp->sd_server->ss_mtu");
709 UM_ZERO(buff
, buff_len
);
713 * Encode the fixed header
717 shp
= (struct scsp_nhdr
*)buff
;
718 shp
->sh_ver
= SCSP_VER_1
;
721 * Set the message type
723 shp
->sh_type
= msg
->sc_msg_type
;
726 * Point past the fixed header
728 len
= sizeof(struct scsp_nhdr
);
732 * Encode any extensions into a temporary buffer
737 * Get a buffer for the extensions
740 e_buff
= (char *)UM_ALLOC(e_buff_len
);
742 scsp_mem_err("scsp_format_msg: e_buff_len");
744 UM_ZERO(e_buff
, e_buff_len
);
747 * Encode the extensions
749 for (exp
= msg
->sc_ext
= 0; exp
; exp
= exp
->next
) {
750 plen
= scsp_format_ext(exp
, e_buff
+ e_len
,
759 * Free the buffer if we didn't use it
769 * Encode the body of the message, depending on the type
771 switch(msg
->sc_msg_type
) {
773 plen
= scsp_format_ca(msg
->sc_ca
, buff
+ len
, buff_len
);
775 case SCSP_CSU_REQ_MSG
:
776 case SCSP_CSU_REPLY_MSG
:
778 plen
= scsp_format_csu(msg
->sc_csu_msg
, buff
+ len
,
782 plen
= scsp_format_hello(msg
->sc_hello
, buff
+ len
,
794 * Copy the extensions to the end of the message
797 shp
->sh_ext_off
= htons(len
);
798 UM_COPY(e_buff
, buff
+ len
, e_len
);
805 shp
->sh_len
= htons(len
);
808 * Compute the message checksum
810 shp
->sh_checksum
= htons(ip_checksum(buff
, len
));
813 * Return the length of the buffer
828 * Send an SCSP message
831 * dcsp pointer to DCS control block
832 * msg pointer to message to send
836 * errno error encountered
840 scsp_send_msg(Scsp_dcs
*dcsp
, Scsp_msg
*msg
)
846 * Make sure we have a socket open
848 if (dcsp
->sd_sock
== -1) {
855 if (((scsp_trace_mode
& SCSP_TRACE_HELLO_MSG
) &&
856 msg
->sc_msg_type
== SCSP_HELLO_MSG
) ||
857 ((scsp_trace_mode
& SCSP_TRACE_CA_MSG
) &&
858 msg
->sc_msg_type
!= SCSP_HELLO_MSG
)) {
859 scsp_trace_msg(dcsp
, msg
, 0);
864 * Put the message into network format
866 len
= scsp_format_msg(dcsp
, msg
, &buff
);
868 scsp_log(LOG_ERR
, "scsp_send_msg: message conversion failed\n");
873 * Write the message to the DCS
875 rc
= write(dcsp
->sd_sock
, (void *)buff
, len
);
877 if (rc
== len
|| (rc
== -1 && errno
== EINPROGRESS
)) {
881 * There was an error on the write--close the VCC
883 close(dcsp
->sd_sock
);
887 * Inform the Hello FSM
889 scsp_hfsm(dcsp
, SCSP_HFSM_VC_CLOSED
, NULL
);
892 * Set the return code