added -y/--side-by-side option
[dfdiff.git] / usr.sbin / atm / scspd / scsp_output.c
blobd764b1552eb0eadf8ddd6f8d3591f88522213c0b
1 /*
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>
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_sys.h>
50 #include <netatm/atm_ioctl.h>
52 #include <errno.h>
53 #include <libatm.h>
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <string.h>
57 #include <syslog.h>
58 #include <unistd.h>
60 #include "scsp_msg.h"
61 #include "scsp_if.h"
62 #include "scsp_var.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.
70 * Arguments:
71 * l long integer
72 * cp pointer to output buffer
74 * Returns:
75 * None
78 static void
79 put_long(u_long l, u_char *cp)
81 u_long nl;
84 * Convert to network order and copy to output buffer
86 nl = htonl(l);
87 UM_COPY(&nl, cp, sizeof(u_long));
92 * Format a Sender or Receiver ID
94 * Arguments:
95 * idp ponter to ID structure
96 * buff pointer to ID
98 * Returns:
99 * 0 input was invalid
100 * else length of ID processed
103 static int
104 scsp_format_id(Scsp_id *idp, char *buff)
107 * Copy the ID
109 UM_COPY(idp->id, buff, idp->id_len);
112 * Return the ID length
114 return(idp->id_len);
119 * Format the Mandatory Common Part of an SCSP input packet
121 * Arguments:
122 * mcp pointer to MCP
123 * buff pointer to mandatory common part
125 * Returns:
126 * 0 input was invalid
127 * else length of MCP in message
130 static int
131 scsp_format_mcp(Scsp_mcp *mcp, char *buff)
133 int len;
134 char *odp;
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);
149 * Set the flags
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);
159 if (len == 0) {
160 goto mcp_invalid;
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);
169 if (len == 0) {
170 goto mcp_invalid;
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 +
182 mcp->rid.id_len);
184 mcp_invalid:
185 return(0);
190 * Format an Extension
192 * Arguments:
193 * exp pointer to extension in internal format
194 * buff pointer to output buffer
195 * blen space available in buffer
197 * Returns:
198 * 0 input was invalid
199 * else length of extension processed
202 static int
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))
211 return(0);
214 * Set the type
216 sep = (struct scsp_next *)buff;
217 sep->se_type = htons(exp->type);
220 * Set the length
222 sep->se_len = htons(exp->len);
225 * Set the value
227 if (exp->len > 0) {
228 buff += sizeof(struct scsp_next);
229 UM_COPY((caddr_t)exp + sizeof(Scsp_ext),
230 buff,
231 exp->len);
235 * Return the number of bytes processed
237 return(sizeof(struct scsp_next) + exp->len);
242 * Format the ATMARP part of a CSA record
244 * Arguments:
245 * acsp pointer to ATMARP protocol-specific CSA record
246 * buff pointer to output buffer
248 * Returns:
249 * 0 input was invalid
250 * else length of record processed
253 static int
254 scsp_format_atmarp(Scsp_atmarp_csa *acsp, char *buff)
256 char *cp;
257 int len, pkt_len;
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;
267 break;
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;
273 break;
276 switch (acsp->sa_tha.address_format) {
277 case T_ATM_ENDSYS_ADDR:
278 pkt_len += acsp->sa_tha.address_length;
279 break;
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;
285 break;
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);
295 * Set up pointers
297 sanp = (struct scsp_atmarp_ncsa *)buff;
298 cp = (char *)sanp + sizeof(struct scsp_atmarp_ncsa);
301 * Build fields
303 sanp->sa_hrd = htons(ARP_ATMFORUM);
304 sanp->sa_pro = htons(ETHERTYPE_IP);
306 /* sa_sha */
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);
312 /* sa_sha */
313 UM_COPY(acsp->sa_sha.address, cp, len);
314 cp += len;
316 sanp->sa_sstl = 0;
317 break;
319 case T_ATM_E164_ADDR:
320 sanp->sa_shtl = ARP_TL_E164 | (len & ARP_TL_LMASK);
322 /* sa_sha */
323 UM_COPY(acsp->sa_sha.address, cp, len);
324 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);
331 /* sa_ssa */
332 UM_COPY(acsp->sa_ssa.address, cp, len);
333 cp += len;
334 } else
335 sanp->sa_sstl = 0;
336 break;
338 default:
339 sanp->sa_shtl = 0;
340 sanp->sa_sstl = 0;
343 /* sa_state */
344 sanp->sa_state = acsp->sa_state;
345 sanp->sa_fill1 = 0;
347 /* sa_spa */
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);
354 /* sa_tha */
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);
360 /* sa_tha */
361 UM_COPY(acsp->sa_tha.address, cp, len);
362 cp += len;
364 sanp->sa_tstl = 0;
365 break;
367 case T_ATM_E164_ADDR:
368 sanp->sa_thtl = ARP_TL_E164 | (len & ARP_TL_LMASK);
370 /* sa_tha */
371 UM_COPY(acsp->sa_tha.address, cp, len);
372 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);
379 /* sa_tsa */
380 UM_COPY(acsp->sa_tsa.address, cp, len);
381 cp += len;
382 } else
383 sanp->sa_tstl = 0;
384 break;
386 default:
387 sanp->sa_thtl = 0;
388 sanp->sa_tstl = 0;
391 /* sa_tpa */
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));
397 return(pkt_len);
402 * Format a Cache State Advertisement or Cache State Advertisement
403 * Summary record
405 * Arguments:
406 * csapp pointer to CSA or CSAS
407 * buff pointer to output buffer
409 * Returns:
410 * 0 input was invalid
411 * else length of record processed
414 static int
415 scsp_format_csa(Scsp_csa *csap, char *buff)
417 int len = 0;
418 char *odp;
419 struct scsp_ncsa *scp;
422 * Set the hop count
424 scp = (struct scsp_ncsa *)buff;
425 scp->scs_hop_cnt = htons(csap->hops);
428 * Set the null flag
430 if (csap->null) {
431 scp->scs_nfill = htons(SCSP_CSAS_NULL);
435 * Set the sequence number
437 put_long(csap->seq, (u_char *)&scp->scs_seq);
440 * Set the cache key
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 +
466 len);
469 * Return the length of data we processed
471 return(ntohs(scp->scs_len));
476 * Format a Cache Alignment message
478 * Arguments:
479 * cap pointer to CA message
480 * buff pointer to output buffer
481 * blen space available in buffer
483 * Returns:
484 * 0 input was invalid
485 * else length of CA message processed
488 static int
489 scsp_format_ca(Scsp_ca *cap, char *buff, int blen)
491 int i, len, proc_len;
492 struct scsp_nca *scap;
493 Scsp_csa *csap;
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);
504 * Set the flags
506 cap->ca_mcp.flags = 0;
507 if (cap->ca_m)
508 cap->ca_mcp.flags |= SCSP_CA_M;
509 if (cap->ca_i)
510 cap->ca_mcp.flags |= SCSP_CA_I;
511 if (cap->ca_o)
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);
518 if (len == 0)
519 goto ca_invalid;
520 buff += len;
521 proc_len += len;
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);
529 buff += len;
530 proc_len += len;
531 if (proc_len > blen) {
532 scsp_log(LOG_CRIT, "scsp_format_ca: buffer overflow");
533 abort();
538 * Return the length of processed data
540 return(proc_len);
542 ca_invalid:
543 return(0);
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.
552 * Arguments:
553 * csup pointer to location to put pointer to CSU Req message
554 * buff pointer to output buffer
555 * blen space available in buffer
557 * Returns:
558 * 0 input was invalid
559 * else length of CSU Req message processed
562 static int
563 scsp_format_csu(Scsp_csu_msg *csup, char *buff, int blen)
565 int i, len, proc_len;
566 struct scsp_ncsu_msg *scsup;
567 Scsp_csa *csap;
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);
574 if (len == 0)
575 goto csu_invalid;
576 buff += len;
577 proc_len = len;
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);
586 buff += len;
587 proc_len += len;
588 if (proc_len > blen) {
589 scsp_log(LOG_CRIT, "scsp_format_csu: buffer overflow");
590 abort();
595 * Return the length of processed data
597 return(proc_len);
599 csu_invalid:
600 return(0);
605 * Format a Hello message
607 * Arguments:
608 * hpp pointer to Hello message
609 * buff pointer to output buffer
610 * blen space available in buffer
612 * Returns:
613 * 0 input was invalid
614 * else length of Hello message processed
617 static int
618 scsp_format_hello(Scsp_hello *hp, char *buff, int blen)
620 int len, proc_len;
621 struct scsp_nhello *shp;
622 Scsp_id *ridp;
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);
636 * Set the family ID
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);
645 buff += proc_len;
646 len = scsp_format_mcp(&hp->hello_mcp, buff);
647 if (len == 0)
648 goto hello_invalid;
649 proc_len += len;
650 buff += len;
653 * Add any additional receiver ID records to the message
655 for (ridp = hp->hello_mcp.rid.next; ridp;
656 ridp = ridp->next) {
657 len = scsp_format_id(ridp, buff);
658 if (len == 0) {
659 goto hello_invalid;
661 proc_len += len;
662 buff += len;
666 * Return the length of the Hello message body
668 if (proc_len > blen) {
669 scsp_log(LOG_CRIT, "scsp_format_hello: buffer overflow");
670 abort();
672 return(proc_len);
674 hello_invalid:
675 return(0);
680 * Format an SCSP output packet
682 * Arguments:
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
687 * Returns:
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 = (char *)0, *e_buff = (char *)0;
696 int buff_len, e_buff_len;
697 int e_len, len, plen;
698 struct scsp_nhdr *shp;
699 Scsp_ext *exp;
702 * Allocate a buffer for the message
704 buff_len = dcsp->sd_server->ss_mtu;
705 buff = (char *)UM_ALLOC(buff_len);
706 if (!buff) {
707 scsp_mem_err("scsp_format_msg: dcsp->sd_server->ss_mtu");
709 UM_ZERO(buff, buff_len);
710 *bpp = buff;
713 * Encode the fixed header
715 * Set the version
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);
729 buff_len -= len;
732 * Encode any extensions into a temporary buffer
734 e_len = 0;
735 if (msg->sc_ext) {
737 * Get a buffer for the extensions
739 e_buff_len = 1024;
740 e_buff = (char *)UM_ALLOC(e_buff_len);
741 if (!buff) {
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,
751 e_buff_len - e_len);
752 if (plen == 0) {
753 goto ignore;
755 e_len += plen;
759 * Free the buffer if we didn't use it
761 if (!e_len) {
762 UM_FREE(e_buff);
763 e_buff = (char *)0;
766 buff_len -= e_len;
769 * Encode the body of the message, depending on the type
771 switch(msg->sc_msg_type) {
772 case SCSP_CA_MSG:
773 plen = scsp_format_ca(msg->sc_ca, buff + len, buff_len);
774 break;
775 case SCSP_CSU_REQ_MSG:
776 case SCSP_CSU_REPLY_MSG:
777 case SCSP_CSUS_MSG:
778 plen = scsp_format_csu(msg->sc_csu_msg, buff + len,
779 buff_len);
780 break;
781 case SCSP_HELLO_MSG:
782 plen = scsp_format_hello(msg->sc_hello, buff + len,
783 buff_len);
784 break;
785 default:
786 goto ignore;
788 if (plen == 0) {
789 goto ignore;
791 len += plen;
794 * Copy the extensions to the end of the message
796 if (e_len) {
797 shp->sh_ext_off = htons(len);
798 UM_COPY(e_buff, buff + len, e_len);
799 UM_FREE(e_buff);
803 * Set the length
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
815 return(len);
817 ignore:
818 if (buff)
819 UM_FREE(buff);
820 if (e_buff)
821 UM_FREE(e_buff);
822 *bpp = (char *)0;
823 return(0);
828 * Send an SCSP message
830 * Arguments:
831 * dcsp pointer to DCS control block
832 * msg pointer to message to send
834 * Returns:
835 * 0 success
836 * errno error encountered
840 scsp_send_msg(Scsp_dcs *dcsp, Scsp_msg *msg)
842 int len, rc;
843 char *buff;
846 * Make sure we have a socket open
848 if (dcsp->sd_sock == -1) {
849 return(EBADF);
853 * Trace the message
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);
860 scsp_trace("\n");
864 * Put the message into network format
866 len = scsp_format_msg(dcsp, msg, &buff);
867 if (len == 0) {
868 scsp_log(LOG_ERR, "scsp_send_msg: message conversion failed\n");
869 abort();
873 * Write the message to the DCS
875 rc = write(dcsp->sd_sock, (void *)buff, len);
876 UM_FREE(buff);
877 if (rc == len || (rc == -1 && errno == EINPROGRESS)) {
878 rc = 0;
879 } else {
881 * There was an error on the write--close the VCC
883 close(dcsp->sd_sock);
884 dcsp->sd_sock = -1;
887 * Inform the Hello FSM
889 scsp_hfsm(dcsp, SCSP_HFSM_VC_CLOSED, (Scsp_msg *)0);
892 * Set the return code
894 if (rc == -1)
895 rc = errno;
896 else
897 rc = EINVAL;
900 return(rc);