* K&R function cleanup
[dragonfly.git] / usr.sbin / atm / scspd / scsp_output.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_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.3 2003/11/15 20:33:43 eirikn Exp $
28  */
29
30 /*
31  * Server Cache Synchronization Protocol (SCSP) Support
32  * ----------------------------------------------------
33  *
34  * Output packet processing
35  *
36  */
37
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>
51
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>
59
60 #include "scsp_msg.h"
61 #include "scsp_if.h"
62 #include "scsp_var.h"
63
64 /*
65  * Put a long integer into the output buffer
66  *
67  * This routine is provided for cases where long ints may not be
68  * word-aligned in the output buffer.
69  *
70  * Arguments:
71  *      l       long integer
72  *      cp      pointer to output buffer
73  *
74  * Returns:
75  *      None
76  *
77  */
78 static void
79 put_long(u_long l, u_char *cp)
80 {
81         u_long  nl;
82
83         /*
84          * Convert to network order and copy to output buffer
85          */
86         nl = htonl(l);
87         UM_COPY(&nl, cp, sizeof(u_long));
88 }
89
90
91 /*
92  * Format a Sender or Receiver ID
93  *
94  * Arguments:
95  *      idp     ponter to ID structure
96  *      buff    pointer to ID
97  *
98  * Returns:
99  *      0       input was invalid
100  *      else    length of ID processed
101  *
102  */
103 static int
104 scsp_format_id(Scsp_id *idp, char *buff)
105 {
106         /*
107          * Copy the ID
108          */
109         UM_COPY(idp->id, buff, idp->id_len);
110
111         /*
112          * Return the ID length
113          */
114         return(idp->id_len);
115 }
116
117
118 /*
119  * Format the Mandatory Common Part of an SCSP input packet
120  *
121  * Arguments:
122  *      mcp     pointer to MCP
123  *      buff    pointer to mandatory common part
124  *
125  * Returns:
126  *      0       input was invalid
127  *      else    length of MCP in message
128  *
129  */
130 static int
131 scsp_format_mcp(Scsp_mcp *mcp, char *buff)
132 {
133         int                     len;
134         char                    *odp;
135         struct scsp_nmcp        *smp;
136
137         /*
138          * Set the protocol ID
139          */
140         smp = (struct scsp_nmcp *)buff;
141         smp->sm_pid = htons(mcp->pid);
142
143         /*
144          * Set the server group ID
145          */
146         smp->sm_sgid = htons(mcp->sgid);
147
148         /*
149          * Set the flags
150          */
151         smp->sm_flags = htons(mcp->flags);
152
153         /*
154          * Set the sender ID and length
155          */
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;
161          }
162
163         /*
164          * Set the receiver ID and length
165          */
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;
171          }
172
173         /*
174          * Set the record count
175          */
176         smp->sm_rec_cnt = htons(mcp->rec_cnt);
177
178         /*
179          * Return the length of data we processed
180          */
181         return(sizeof(struct scsp_nmcp) + mcp->sid.id_len +
182                         mcp->rid.id_len);
183
184 mcp_invalid:
185         return(0);
186 }
187
188
189 /*
190  * Format an Extension
191  *
192  * Arguments:
193  *      exp     pointer to extension in internal format
194  *      buff    pointer to output buffer
195  *      blen    space available in buffer
196  *
197  * Returns:
198  *      0       input was invalid
199  *      else    length of extension processed
200  *
201  */
202 static int
203 scsp_format_ext(Scsp_ext *exp, char *buff, int blen)
204 {
205         struct scsp_next        *sep;
206
207         /*
208          * Make sure there's room in the buffer
209          */
210         if (blen < (sizeof(struct scsp_next) + exp->len))
211                 return(0);
212
213         /*
214          * Set the type
215          */
216         sep = (struct scsp_next *)buff;
217         sep->se_type = htons(exp->type);
218
219         /*
220          * Set the length
221          */
222         sep->se_len = htons(exp->len);
223
224         /*
225          * Set the value
226          */
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);
232         }
233
234         /*
235          * Return the number of bytes processed
236          */
237         return(sizeof(struct scsp_next) + exp->len);
238 }
239
240
241 /*
242  * Format the ATMARP part of a CSA record
243  *
244  * Arguments:
245  *      acsp    pointer to ATMARP protocol-specific CSA record
246  *      buff    pointer to output buffer
247  *
248  * Returns:
249  *      0       input was invalid
250  *      else    length of record processed
251  *
252  */
253 static int
254 scsp_format_atmarp(Scsp_atmarp_csa *acsp, char *buff)
255 {
256         char                    *cp;
257         int                     len, pkt_len;
258         struct scsp_atmarp_ncsa *sanp;
259
260         /*
261          * Figure out how long PDU is going to be
262          */
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;
268
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;
274         }
275
276         switch (acsp->sa_tha.address_format) {
277         case T_ATM_ENDSYS_ADDR:
278                 pkt_len += acsp->sa_tha.address_length;
279                 break;
280
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;
286         }
287
288         if (acsp->sa_spa.s_addr != 0)
289                 pkt_len += sizeof(struct in_addr);
290
291         if (acsp->sa_tpa.s_addr != 0)
292                 pkt_len += sizeof(struct in_addr);
293
294         /*
295          * Set up pointers
296          */
297         sanp = (struct scsp_atmarp_ncsa *)buff;
298         cp = (char *)sanp + sizeof(struct scsp_atmarp_ncsa);
299
300         /*
301          * Build fields
302          */
303         sanp->sa_hrd = htons(ARP_ATMFORUM);
304         sanp->sa_pro = htons(ETHERTYPE_IP);
305
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);
311
312                 /* sa_sha */
313                 UM_COPY(acsp->sa_sha.address, cp, len);
314                 cp += len;
315
316                 sanp->sa_sstl = 0;
317                 break;
318
319         case T_ATM_E164_ADDR:
320                 sanp->sa_shtl = ARP_TL_E164 | (len & ARP_TL_LMASK);
321
322                 /* sa_sha */
323                 UM_COPY(acsp->sa_sha.address, cp, len);
324                 cp += len;
325
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);
330
331                         /* sa_ssa */
332                         UM_COPY(acsp->sa_ssa.address, cp, len);
333                         cp += len;
334                 } else
335                         sanp->sa_sstl = 0;
336                 break;
337
338         default:
339                 sanp->sa_shtl = 0;
340                 sanp->sa_sstl = 0;
341         }
342
343         /* sa_state */
344         sanp->sa_state = acsp->sa_state;
345         sanp->sa_fill1 = 0;
346
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);
352         }
353
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);
359
360                 /* sa_tha */
361                 UM_COPY(acsp->sa_tha.address, cp, len);
362                 cp += len;
363
364                 sanp->sa_tstl = 0;
365                 break;
366
367         case T_ATM_E164_ADDR:
368                 sanp->sa_thtl = ARP_TL_E164 | (len & ARP_TL_LMASK);
369
370                 /* sa_tha */
371                 UM_COPY(acsp->sa_tha.address, cp, len);
372                 cp += len;
373
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);
378
379                         /* sa_tsa */
380                         UM_COPY(acsp->sa_tsa.address, cp, len);
381                         cp += len;
382                 } else
383                         sanp->sa_tstl = 0;
384                 break;
385
386         default:
387                 sanp->sa_thtl = 0;
388                 sanp->sa_tstl = 0;
389         }
390
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));
395         }
396
397         return(pkt_len);
398 }
399
400
401 /*
402  * Format a Cache State Advertisement or Cache State Advertisement
403  * Summary record
404  *
405  * Arguments:
406  *      csapp   pointer to CSA or CSAS
407  *      buff    pointer to output buffer
408  *
409  * Returns:
410  *      0       input was invalid
411  *      else    length of record processed
412  *
413  */
414 static int
415 scsp_format_csa(Scsp_csa *csap, char *buff)
416 {
417         int                     len = 0;
418         char                    *odp;
419         struct scsp_ncsa        *scp;
420
421         /*
422          * Set the hop count
423          */
424         scp = (struct scsp_ncsa *)buff;
425         scp->scs_hop_cnt = htons(csap->hops);
426
427         /*
428          * Set the null flag
429          */
430         if (csap->null) {
431                 scp->scs_nfill = htons(SCSP_CSAS_NULL);
432         }
433
434         /*
435          * Set the sequence number
436          */
437         put_long(csap->seq, (u_char *)&scp->scs_seq);
438
439         /*
440          * Set the cache key
441          */
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);
445
446         /*
447          * Set the originator ID
448          */
449         odp += scp->scs_ck_len;
450         scp->scs_oid_len = scsp_format_id(&csap->oid, odp);
451
452         /*
453          * Set the protocol-specific data, if present.  At the
454          * moment, we only handle data for ATMARP.
455          */
456         if (csap->atmarp_data) {
457                 odp += scp->scs_oid_len;
458                 len = scsp_format_atmarp(csap->atmarp_data, odp);
459         }
460
461         /*
462          * Set the record length
463          */
464         scp->scs_len = htons(sizeof(struct scsp_ncsa) +
465                         scp->scs_ck_len + scp->scs_oid_len +
466                         len);
467
468         /*
469          * Return the length of data we processed
470          */
471         return(ntohs(scp->scs_len));
472 }
473
474
475 /*
476  * Format a Cache Alignment message
477  *
478  * Arguments:
479  *      cap     pointer to CA message
480  *      buff    pointer to output buffer
481  *      blen    space available in buffer
482  *
483  * Returns:
484  *      0       input was invalid
485  *      else    length of CA message processed
486  *
487  */
488 static int
489 scsp_format_ca(Scsp_ca *cap, char *buff, int blen)
490 {
491         int             i, len, proc_len;
492         struct scsp_nca *scap;
493         Scsp_csa        *csap;
494
495         /*
496          * Set the sequence number
497          */
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);
502
503         /*
504          * Set the flags
505          */
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;
513
514         /*
515          * Format the mandatory common part of the message
516          */
517         len = scsp_format_mcp(&cap->ca_mcp, buff);
518         if (len == 0)
519                 goto ca_invalid;
520         buff += len;
521         proc_len += len;
522
523         /*
524          * Put any CSAS records into the message
525          */
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();
534                 }
535         }
536
537         /*
538          * Return the length of processed data
539          */
540         return(proc_len);
541
542 ca_invalid:
543         return(0);
544 }
545
546
547 /*
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.
551  *
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
556  *
557  * Returns:
558  *      0       input was invalid
559  *      else    length of CSU Req message processed
560  *
561  */
562 static int
563 scsp_format_csu(Scsp_csu_msg *csup, char *buff, int blen)
564 {
565         int                     i, len, proc_len;
566         struct scsp_ncsu_msg    *scsup;
567         Scsp_csa                *csap;
568
569         /*
570          * Format the mandatory common part of the message
571          */
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;
578
579         /*
580          * Put the CSAS records into the message
581          */
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();
591                 }
592         }
593
594         /*
595          * Return the length of processed data
596          */
597         return(proc_len);
598
599 csu_invalid:
600         return(0);
601 }
602
603
604 /*
605  * Format a Hello message
606  *
607  * Arguments:
608  *      hpp     pointer to Hello message
609  *      buff    pointer to output buffer
610  *      blen    space available in buffer
611  *
612  * Returns:
613  *      0       input was invalid
614  *      else    length of Hello message processed
615  *
616  */
617 static int
618 scsp_format_hello(Scsp_hello *hp, char *buff, int blen)
619 {
620         int                     len, proc_len;
621         struct scsp_nhello      *shp;
622         Scsp_id                 *ridp;
623
624         /*
625          * Set the hello interval
626          */
627         shp = (struct scsp_nhello *)buff;
628         shp->sch_hi = htons(hp->hello_int);
629
630         /*
631          * Set the dead factor
632          */
633         shp->sch_df = htons(hp->dead_factor);
634
635         /*
636          * Set the family ID
637          */
638         shp->sch_fid = htons(hp->family_id);
639
640         /*
641          * Process the mandatory common part of the message
642          */
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;
651
652         /*
653          * Add any additional receiver ID records to the message
654          */
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;
660                 }
661                 proc_len += len;
662                 buff += len;
663         }
664
665         /*
666          * Return the length of the Hello message body
667          */
668         if (proc_len > blen) {
669                 scsp_log(LOG_CRIT, "scsp_format_hello: buffer overflow");
670                 abort();
671         }
672         return(proc_len);
673
674 hello_invalid:
675         return(0);
676 }
677
678
679 /*
680  * Format an SCSP output packet
681  *
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
686  *
687  * Returns:
688  *      0       input packet was invalid
689  *      else    length of formatted packet
690  *
691  */
692 int
693 scsp_format_msg(Scsp_dcs *dcsp, Scsp_msg *msg, char **bpp)
694 {
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;
700
701         /*
702          * Allocate a buffer for the message
703          */
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");
708         }
709         UM_ZERO(buff, buff_len);
710         *bpp = buff;
711
712         /*
713          * Encode the fixed header
714          *
715          * Set the version
716          */
717         shp = (struct scsp_nhdr *)buff;
718         shp->sh_ver = SCSP_VER_1;
719
720         /*
721          * Set the message type
722          */
723         shp->sh_type = msg->sc_msg_type;
724
725         /*
726          * Point past the fixed header
727          */
728         len = sizeof(struct scsp_nhdr);
729         buff_len -= len;
730
731         /*
732          * Encode any extensions into a temporary buffer
733          */
734         e_len = 0;
735         if (msg->sc_ext) {
736                 /*
737                  * Get a buffer for the extensions
738                  */
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");
743                 }
744                 UM_ZERO(e_buff, e_buff_len);
745
746                 /*
747                  * Encode the extensions
748                  */
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;
754                         }
755                         e_len += plen;
756                 }
757
758                 /*
759                  * Free the buffer if we didn't use it
760                  */
761                 if (!e_len) {
762                         UM_FREE(e_buff);
763                         e_buff = (char *)0;
764                 }
765         }
766         buff_len -= e_len;
767
768         /*
769          * Encode the body of the message, depending on the type
770          */
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;
787         }
788         if (plen == 0) {
789                 goto ignore;
790         }
791         len += plen;
792
793         /*
794          * Copy the extensions to the end of the message
795          */
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);
800         }
801
802         /*
803          * Set the length
804          */
805         shp->sh_len = htons(len);
806
807         /*
808          * Compute the message checksum
809          */
810         shp->sh_checksum = htons(ip_checksum(buff, len));
811
812         /*
813          * Return the length of the buffer
814          */
815         return(len);
816
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);
824 }
825
826
827 /*
828  * Send an SCSP message
829  *
830  * Arguments:
831  *      dcsp    pointer to DCS control block
832  *      msg     pointer to message to send
833  *
834  * Returns:
835  *      0       success
836  *      errno   error encountered
837  *
838  */
839 int
840 scsp_send_msg(Scsp_dcs *dcsp, Scsp_msg *msg)
841 {
842         int     len, rc;
843         char    *buff;
844
845         /*
846          * Make sure we have a socket open
847          */
848         if (dcsp->sd_sock == -1) {
849                 return(EBADF);
850         }
851
852         /*
853          * Trace the message
854          */
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");
861         }
862
863         /*
864          * Put the message into network format
865          */
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();
870         }
871
872         /*
873          * Write the message to the DCS
874          */
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 {
880                 /*
881                  * There was an error on the write--close the VCC
882                  */
883                 (void)close(dcsp->sd_sock);
884                 dcsp->sd_sock = -1;
885
886                 /*
887                  * Inform the Hello FSM
888                  */
889                 (void)scsp_hfsm(dcsp, SCSP_HFSM_VC_CLOSED,
890                                 (Scsp_msg *)0);
891
892                 /*
893                  * Set the return code
894                  */
895                 if (rc == -1)
896                         rc = errno;
897                 else
898                         rc = EINVAL;
899         }
900
901         return(rc);
902 }