Merge branch 'vendor/FLEX'
[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  */
28
29 /*
30  * Server Cache Synchronization Protocol (SCSP) Support
31  * ----------------------------------------------------
32  *
33  * Output packet processing
34  *
35  */
36
37 #include <sys/types.h>
38 #include <sys/param.h>
39 #include <sys/socket.h>
40 #include <net/ethernet.h>
41 #include <net/if.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
51 #include <errno.h>
52 #include <libatm.h>
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <string.h>
56 #include <syslog.h>
57 #include <unistd.h>
58
59 #include "scsp_msg.h"
60 #include "scsp_if.h"
61 #include "scsp_var.h"
62
63 /*
64  * Put a long integer into the output buffer
65  *
66  * This routine is provided for cases where long ints may not be
67  * word-aligned in the output buffer.
68  *
69  * Arguments:
70  *      l       long integer
71  *      cp      pointer to output buffer
72  *
73  * Returns:
74  *      None
75  *
76  */
77 static void
78 put_long(u_long l, u_char *cp)
79 {
80         u_long  nl;
81
82         /*
83          * Convert to network order and copy to output buffer
84          */
85         nl = htonl(l);
86         UM_COPY(&nl, cp, sizeof(u_long));
87 }
88
89
90 /*
91  * Format a Sender or Receiver ID
92  *
93  * Arguments:
94  *      idp     ponter to ID structure
95  *      buff    pointer to ID
96  *
97  * Returns:
98  *      0       input was invalid
99  *      else    length of ID processed
100  *
101  */
102 static int
103 scsp_format_id(Scsp_id *idp, char *buff)
104 {
105         /*
106          * Copy the ID
107          */
108         UM_COPY(idp->id, buff, idp->id_len);
109
110         /*
111          * Return the ID length
112          */
113         return(idp->id_len);
114 }
115
116
117 /*
118  * Format the Mandatory Common Part of an SCSP input packet
119  *
120  * Arguments:
121  *      mcp     pointer to MCP
122  *      buff    pointer to mandatory common part
123  *
124  * Returns:
125  *      0       input was invalid
126  *      else    length of MCP in message
127  *
128  */
129 static int
130 scsp_format_mcp(Scsp_mcp *mcp, char *buff)
131 {
132         int                     len;
133         char                    *odp;
134         struct scsp_nmcp        *smp;
135
136         /*
137          * Set the protocol ID
138          */
139         smp = (struct scsp_nmcp *)buff;
140         smp->sm_pid = htons(mcp->pid);
141
142         /*
143          * Set the server group ID
144          */
145         smp->sm_sgid = htons(mcp->sgid);
146
147         /*
148          * Set the flags
149          */
150         smp->sm_flags = htons(mcp->flags);
151
152         /*
153          * Set the sender ID and length
154          */
155         smp->sm_sid_len = mcp->sid.id_len;
156         odp = buff + sizeof(struct scsp_nmcp);
157         len = scsp_format_id(&mcp->sid, odp);
158         if (len == 0) {
159                 goto mcp_invalid;
160          }
161
162         /*
163          * Set the receiver ID and length
164          */
165         smp->sm_rid_len = mcp->rid.id_len;
166         odp += mcp->sid.id_len;
167         len = scsp_format_id(&mcp->rid, odp);
168         if (len == 0) {
169                 goto mcp_invalid;
170          }
171
172         /*
173          * Set the record count
174          */
175         smp->sm_rec_cnt = htons(mcp->rec_cnt);
176
177         /*
178          * Return the length of data we processed
179          */
180         return(sizeof(struct scsp_nmcp) + mcp->sid.id_len +
181                         mcp->rid.id_len);
182
183 mcp_invalid:
184         return(0);
185 }
186
187
188 /*
189  * Format an Extension
190  *
191  * Arguments:
192  *      exp     pointer to extension in internal format
193  *      buff    pointer to output buffer
194  *      blen    space available in buffer
195  *
196  * Returns:
197  *      0       input was invalid
198  *      else    length of extension processed
199  *
200  */
201 static int
202 scsp_format_ext(Scsp_ext *exp, char *buff, int blen)
203 {
204         struct scsp_next        *sep;
205
206         /*
207          * Make sure there's room in the buffer
208          */
209         if (blen < (sizeof(struct scsp_next) + exp->len))
210                 return(0);
211
212         /*
213          * Set the type
214          */
215         sep = (struct scsp_next *)buff;
216         sep->se_type = htons(exp->type);
217
218         /*
219          * Set the length
220          */
221         sep->se_len = htons(exp->len);
222
223         /*
224          * Set the value
225          */
226         if (exp->len > 0) {
227                 buff += sizeof(struct scsp_next);
228                 UM_COPY((caddr_t)exp + sizeof(Scsp_ext),
229                                 buff,
230                                 exp->len);
231         }
232
233         /*
234          * Return the number of bytes processed
235          */
236         return(sizeof(struct scsp_next) + exp->len);
237 }
238
239
240 /*
241  * Format the ATMARP part of a CSA record
242  *
243  * Arguments:
244  *      acsp    pointer to ATMARP protocol-specific CSA record
245  *      buff    pointer to output buffer
246  *
247  * Returns:
248  *      0       input was invalid
249  *      else    length of record processed
250  *
251  */
252 static int
253 scsp_format_atmarp(Scsp_atmarp_csa *acsp, char *buff)
254 {
255         char                    *cp;
256         int                     len, pkt_len;
257         struct scsp_atmarp_ncsa *sanp;
258
259         /*
260          * Figure out how long PDU is going to be
261          */
262         pkt_len = sizeof(struct scsp_atmarp_ncsa);
263         switch (acsp->sa_sha.address_format) {
264         case T_ATM_ENDSYS_ADDR:
265                 pkt_len += acsp->sa_sha.address_length;
266                 break;
267
268         case T_ATM_E164_ADDR:
269                 pkt_len += acsp->sa_sha.address_length;
270                 if (acsp->sa_ssa.address_format == T_ATM_ENDSYS_ADDR)
271                         pkt_len += acsp->sa_ssa.address_length;
272                 break;
273         }
274
275         switch (acsp->sa_tha.address_format) {
276         case T_ATM_ENDSYS_ADDR:
277                 pkt_len += acsp->sa_tha.address_length;
278                 break;
279
280         case T_ATM_E164_ADDR:
281                 pkt_len += acsp->sa_tha.address_length;
282                 if (acsp->sa_tha.address_format == T_ATM_ENDSYS_ADDR)
283                         pkt_len += acsp->sa_tha.address_length;
284                 break;
285         }
286
287         if (acsp->sa_spa.s_addr != 0)
288                 pkt_len += sizeof(struct in_addr);
289
290         if (acsp->sa_tpa.s_addr != 0)
291                 pkt_len += sizeof(struct in_addr);
292
293         /*
294          * Set up pointers
295          */
296         sanp = (struct scsp_atmarp_ncsa *)buff;
297         cp = (char *)sanp + sizeof(struct scsp_atmarp_ncsa);
298
299         /*
300          * Build fields
301          */
302         sanp->sa_hrd = htons(ARP_ATMFORUM);
303         sanp->sa_pro = htons(ETHERTYPE_IP);
304
305         /* sa_sha */
306         len = acsp->sa_sha.address_length;
307         switch (acsp->sa_sha.address_format) {
308         case T_ATM_ENDSYS_ADDR:
309                 sanp->sa_shtl = ARP_TL_NSAPA | (len & ARP_TL_LMASK);
310
311                 /* sa_sha */
312                 UM_COPY(acsp->sa_sha.address, cp, len);
313                 cp += len;
314
315                 sanp->sa_sstl = 0;
316                 break;
317
318         case T_ATM_E164_ADDR:
319                 sanp->sa_shtl = ARP_TL_E164 | (len & ARP_TL_LMASK);
320
321                 /* sa_sha */
322                 UM_COPY(acsp->sa_sha.address, cp, len);
323                 cp += len;
324
325                 if (acsp->sa_ssa.address_format == T_ATM_ENDSYS_ADDR) {
326                         len = acsp->sa_ssa.address_length;
327                         sanp->sa_sstl = ARP_TL_NSAPA |
328                                         (len & ARP_TL_LMASK);
329
330                         /* sa_ssa */
331                         UM_COPY(acsp->sa_ssa.address, cp, len);
332                         cp += len;
333                 } else
334                         sanp->sa_sstl = 0;
335                 break;
336
337         default:
338                 sanp->sa_shtl = 0;
339                 sanp->sa_sstl = 0;
340         }
341
342         /* sa_state */
343         sanp->sa_state = acsp->sa_state;
344         sanp->sa_fill1 = 0;
345
346         /* sa_spa */
347         if (acsp->sa_spa.s_addr != 0) {
348                 sanp->sa_spln = sizeof(struct in_addr);
349                 UM_COPY(&acsp->sa_spa, cp, sizeof(struct in_addr));
350                 cp += sizeof(struct in_addr);
351         }
352
353         /* sa_tha */
354         len = acsp->sa_tha.address_length;
355         switch (acsp->sa_tha.address_format) {
356         case T_ATM_ENDSYS_ADDR:
357                 sanp->sa_thtl = ARP_TL_NSAPA | (len & ARP_TL_LMASK);
358
359                 /* sa_tha */
360                 UM_COPY(acsp->sa_tha.address, cp, len);
361                 cp += len;
362
363                 sanp->sa_tstl = 0;
364                 break;
365
366         case T_ATM_E164_ADDR:
367                 sanp->sa_thtl = ARP_TL_E164 | (len & ARP_TL_LMASK);
368
369                 /* sa_tha */
370                 UM_COPY(acsp->sa_tha.address, cp, len);
371                 cp += len;
372
373                 if (acsp->sa_tsa.address_format == T_ATM_ENDSYS_ADDR) {
374                         len = acsp->sa_tha.address_length;
375                         sanp->sa_tstl = ARP_TL_NSAPA |
376                                         (len & ARP_TL_LMASK);
377
378                         /* sa_tsa */
379                         UM_COPY(acsp->sa_tsa.address, cp, len);
380                         cp += len;
381                 } else
382                         sanp->sa_tstl = 0;
383                 break;
384
385         default:
386                 sanp->sa_thtl = 0;
387                 sanp->sa_tstl = 0;
388         }
389
390         /* sa_tpa */
391         if (acsp->sa_tpa.s_addr != 0) {
392                 sanp->sa_tpln = sizeof(struct in_addr);
393                 UM_COPY(&acsp->sa_tpa, cp, sizeof(struct in_addr));
394         }
395
396         return(pkt_len);
397 }
398
399
400 /*
401  * Format a Cache State Advertisement or Cache State Advertisement
402  * Summary record
403  *
404  * Arguments:
405  *      csapp   pointer to CSA or CSAS
406  *      buff    pointer to output buffer
407  *
408  * Returns:
409  *      0       input was invalid
410  *      else    length of record processed
411  *
412  */
413 static int
414 scsp_format_csa(Scsp_csa *csap, char *buff)
415 {
416         int                     len = 0;
417         char                    *odp;
418         struct scsp_ncsa        *scp;
419
420         /*
421          * Set the hop count
422          */
423         scp = (struct scsp_ncsa *)buff;
424         scp->scs_hop_cnt = htons(csap->hops);
425
426         /*
427          * Set the null flag
428          */
429         if (csap->null) {
430                 scp->scs_nfill = htons(SCSP_CSAS_NULL);
431         }
432
433         /*
434          * Set the sequence number
435          */
436         put_long(csap->seq, (u_char *)&scp->scs_seq);
437
438         /*
439          * Set the cache key
440          */
441         scp->scs_ck_len = csap->key.key_len;
442         odp = buff + sizeof(struct scsp_ncsa);
443         UM_COPY(csap->key.key, odp, scp->scs_ck_len);
444
445         /*
446          * Set the originator ID
447          */
448         odp += scp->scs_ck_len;
449         scp->scs_oid_len = scsp_format_id(&csap->oid, odp);
450
451         /*
452          * Set the protocol-specific data, if present.  At the
453          * moment, we only handle data for ATMARP.
454          */
455         if (csap->atmarp_data) {
456                 odp += scp->scs_oid_len;
457                 len = scsp_format_atmarp(csap->atmarp_data, odp);
458         }
459
460         /*
461          * Set the record length
462          */
463         scp->scs_len = htons(sizeof(struct scsp_ncsa) +
464                         scp->scs_ck_len + scp->scs_oid_len +
465                         len);
466
467         /*
468          * Return the length of data we processed
469          */
470         return(ntohs(scp->scs_len));
471 }
472
473
474 /*
475  * Format a Cache Alignment message
476  *
477  * Arguments:
478  *      cap     pointer to CA message
479  *      buff    pointer to output buffer
480  *      blen    space available in buffer
481  *
482  * Returns:
483  *      0       input was invalid
484  *      else    length of CA message processed
485  *
486  */
487 static int
488 scsp_format_ca(Scsp_ca *cap, char *buff, int blen)
489 {
490         int             i, len, proc_len;
491         struct scsp_nca *scap;
492         Scsp_csa        *csap;
493
494         /*
495          * Set the sequence number
496          */
497         scap = (struct scsp_nca *)buff;
498         put_long(cap->ca_seq, (u_char *)&scap->sca_seq);
499         proc_len = sizeof(scap->sca_seq);
500         buff += sizeof(scap->sca_seq);
501
502         /*
503          * Set the flags
504          */
505         cap->ca_mcp.flags = 0;
506         if (cap->ca_m)
507                 cap->ca_mcp.flags |= SCSP_CA_M;
508         if (cap->ca_i)
509                 cap->ca_mcp.flags |= SCSP_CA_I;
510         if (cap->ca_o)
511                 cap->ca_mcp.flags |= SCSP_CA_O;
512
513         /*
514          * Format the mandatory common part of the message
515          */
516         len = scsp_format_mcp(&cap->ca_mcp, buff);
517         if (len == 0)
518                 goto ca_invalid;
519         buff += len;
520         proc_len += len;
521
522         /*
523          * Put any CSAS records into the message
524          */
525         for (i = 0, csap = cap->ca_csa_rec; i < cap->ca_mcp.rec_cnt;
526                         i++, csap = csap->next) {
527                 len = scsp_format_csa(csap, buff);
528                 buff += len;
529                 proc_len += len;
530                 if (proc_len > blen) {
531                         scsp_log(LOG_CRIT, "scsp_format_ca: buffer overflow");
532                         abort();
533                 }
534         }
535
536         /*
537          * Return the length of processed data
538          */
539         return(proc_len);
540
541 ca_invalid:
542         return(0);
543 }
544
545
546 /*
547  * Format a Cache State Update Request, Cache State Update Reply, or
548  * Cache State Update Solicit message.  These all have the same format,
549  * a Mandatory Common Part followed by a number of CSA or CSAS records.
550  *
551  * Arguments:
552  *      csup    pointer to location to put pointer to CSU Req message
553  *      buff    pointer to output buffer
554  *      blen    space available in buffer
555  *
556  * Returns:
557  *      0       input was invalid
558  *      else    length of CSU Req message processed
559  *
560  */
561 static int
562 scsp_format_csu(Scsp_csu_msg *csup, char *buff, int blen)
563 {
564         int                     i, len, proc_len;
565         Scsp_csa                *csap;
566
567         /*
568          * Format the mandatory common part of the message
569          */
570         len = scsp_format_mcp(&csup->csu_mcp, buff);
571         if (len == 0)
572                 goto csu_invalid;
573         buff += len;
574         proc_len = len;
575
576         /*
577          * Put the CSAS records into the message
578          */
579         for (i = 0, csap = csup->csu_csa_rec;
580                         i < csup->csu_mcp.rec_cnt && csap;
581                         i++, csap = csap->next) {
582                 len = scsp_format_csa(csap, buff);
583                 buff += len;
584                 proc_len += len;
585                 if (proc_len > blen) {
586                         scsp_log(LOG_CRIT, "scsp_format_csu: buffer overflow");
587                         abort();
588                 }
589         }
590
591         /*
592          * Return the length of processed data
593          */
594         return(proc_len);
595
596 csu_invalid:
597         return(0);
598 }
599
600
601 /*
602  * Format a Hello message
603  *
604  * Arguments:
605  *      hpp     pointer to Hello message
606  *      buff    pointer to output buffer
607  *      blen    space available in buffer
608  *
609  * Returns:
610  *      0       input was invalid
611  *      else    length of Hello message processed
612  *
613  */
614 static int
615 scsp_format_hello(Scsp_hello *hp, char *buff, int blen)
616 {
617         int                     len, proc_len;
618         struct scsp_nhello      *shp;
619         Scsp_id                 *ridp;
620
621         /*
622          * Set the hello interval
623          */
624         shp = (struct scsp_nhello *)buff;
625         shp->sch_hi = htons(hp->hello_int);
626
627         /*
628          * Set the dead factor
629          */
630         shp->sch_df = htons(hp->dead_factor);
631
632         /*
633          * Set the family ID
634          */
635         shp->sch_fid = htons(hp->family_id);
636
637         /*
638          * Process the mandatory common part of the message
639          */
640         proc_len = sizeof(struct scsp_nhello) -
641                         sizeof(struct scsp_nmcp);
642         buff += proc_len;
643         len = scsp_format_mcp(&hp->hello_mcp, buff);
644         if (len == 0)
645                 goto hello_invalid;
646         proc_len += len;
647         buff += len;
648
649         /*
650          * Add any additional receiver ID records to the message
651          */
652         for (ridp = hp->hello_mcp.rid.next; ridp;
653                         ridp = ridp->next) {
654                 len = scsp_format_id(ridp, buff);
655                 if (len == 0) {
656                         goto hello_invalid;
657                 }
658                 proc_len += len;
659                 buff += len;
660         }
661
662         /*
663          * Return the length of the Hello message body
664          */
665         if (proc_len > blen) {
666                 scsp_log(LOG_CRIT, "scsp_format_hello: buffer overflow");
667                 abort();
668         }
669         return(proc_len);
670
671 hello_invalid:
672         return(0);
673 }
674
675
676 /*
677  * Format an SCSP output packet
678  *
679  * Arguments:
680  *      dcsp    pointer to DCS for which message is being prepared
681  *      msg     pointer to input packet
682  *      bpp     pointer to location to put pointer to formatted packet
683  *
684  * Returns:
685  *      0       input packet was invalid
686  *      else    length of formatted packet
687  *
688  */
689 int
690 scsp_format_msg(Scsp_dcs *dcsp, Scsp_msg *msg, char **bpp)
691 {
692         char                    *buff = NULL, *e_buff = NULL;
693         int                     buff_len, e_buff_len;
694         int                     e_len, len, plen;
695         struct scsp_nhdr        *shp;
696         Scsp_ext                *exp;
697
698         /*
699          * Allocate a buffer for the message
700          */
701         buff_len = dcsp->sd_server->ss_mtu;
702         buff = (char *)UM_ALLOC(buff_len);
703         if (!buff) {
704                 scsp_mem_err("scsp_format_msg: dcsp->sd_server->ss_mtu");
705         }
706         UM_ZERO(buff, buff_len);
707         *bpp = buff;
708
709         /*
710          * Encode the fixed header
711          *
712          * Set the version
713          */
714         shp = (struct scsp_nhdr *)buff;
715         shp->sh_ver = SCSP_VER_1;
716
717         /*
718          * Set the message type
719          */
720         shp->sh_type = msg->sc_msg_type;
721
722         /*
723          * Point past the fixed header
724          */
725         len = sizeof(struct scsp_nhdr);
726         buff_len -= len;
727
728         /*
729          * Encode any extensions into a temporary buffer
730          */
731         e_len = 0;
732         if (msg->sc_ext) {
733                 /*
734                  * Get a buffer for the extensions
735                  */
736                 e_buff_len = 1024;
737                 e_buff = (char *)UM_ALLOC(e_buff_len);
738                 if (!buff) {
739                         scsp_mem_err("scsp_format_msg: e_buff_len");
740                 }
741                 UM_ZERO(e_buff, e_buff_len);
742
743                 /*
744                  * Encode the extensions
745                  */
746                 for (exp = msg->sc_ext = 0; exp; exp = exp->next) {
747                         plen = scsp_format_ext(exp, e_buff + e_len,
748                                         e_buff_len - e_len);
749                         if (plen == 0) {
750                                 goto ignore;
751                         }
752                         e_len += plen;
753                 }
754
755                 /*
756                  * Free the buffer if we didn't use it
757                  */
758                 if (!e_len) {
759                         UM_FREE(e_buff);
760                         e_buff = NULL;
761                 }
762         }
763         buff_len -= e_len;
764
765         /*
766          * Encode the body of the message, depending on the type
767          */
768         switch(msg->sc_msg_type) {
769         case SCSP_CA_MSG:
770                 plen = scsp_format_ca(msg->sc_ca, buff + len, buff_len);
771                 break;
772         case SCSP_CSU_REQ_MSG:
773         case SCSP_CSU_REPLY_MSG:
774         case SCSP_CSUS_MSG:
775                 plen = scsp_format_csu(msg->sc_csu_msg, buff + len,
776                                 buff_len);
777                 break;
778         case SCSP_HELLO_MSG:
779                 plen = scsp_format_hello(msg->sc_hello, buff + len,
780                                 buff_len);
781                 break;
782         default:
783                 goto ignore;
784         }
785         if (plen == 0) {
786                 goto ignore;
787         }
788         len += plen;
789
790         /*
791          * Copy the extensions to the end of the message
792          */
793         if (e_len) {
794                 shp->sh_ext_off = htons(len);
795                 UM_COPY(e_buff, buff + len, e_len);
796                 UM_FREE(e_buff);
797         }
798
799         /*
800          * Set the length
801          */
802         shp->sh_len = htons(len);
803
804         /*
805          * Compute the message checksum
806          */
807         shp->sh_checksum = htons(ip_checksum(buff, len));
808
809         /*
810          * Return the length of the buffer
811          */
812         return(len);
813
814 ignore:
815         if (buff)
816                 UM_FREE(buff);
817         if (e_buff)
818                 UM_FREE(e_buff);
819         *bpp = NULL;
820         return(0);
821 }
822
823
824 /*
825  * Send an SCSP message
826  *
827  * Arguments:
828  *      dcsp    pointer to DCS control block
829  *      msg     pointer to message to send
830  *
831  * Returns:
832  *      0       success
833  *      errno   error encountered
834  *
835  */
836 int
837 scsp_send_msg(Scsp_dcs *dcsp, Scsp_msg *msg)
838 {
839         int     len, rc;
840         char    *buff;
841
842         /*
843          * Make sure we have a socket open
844          */
845         if (dcsp->sd_sock == -1) {
846                 return(EBADF);
847         }
848
849         /*
850          * Trace the message
851          */
852         if (((scsp_trace_mode & SCSP_TRACE_HELLO_MSG) &&
853                         msg->sc_msg_type == SCSP_HELLO_MSG) ||
854                         ((scsp_trace_mode & SCSP_TRACE_CA_MSG) &&
855                         msg->sc_msg_type != SCSP_HELLO_MSG)) {
856                 scsp_trace_msg(dcsp, msg, 0);
857                 scsp_trace("\n");
858         }
859
860         /*
861          * Put the message into network format
862          */
863         len = scsp_format_msg(dcsp, msg, &buff);
864         if (len == 0) {
865                 scsp_log(LOG_ERR, "scsp_send_msg: message conversion failed\n");
866                 abort();
867         }
868
869         /*
870          * Write the message to the DCS
871          */
872         rc = write(dcsp->sd_sock, (void *)buff, len);
873         UM_FREE(buff);
874         if (rc == len || (rc == -1 && errno == EINPROGRESS)) {
875                 rc = 0;
876         } else {
877                 /*
878                  * There was an error on the write--close the VCC
879                  */
880                 close(dcsp->sd_sock);
881                 dcsp->sd_sock = -1;
882
883                 /*
884                  * Inform the Hello FSM
885                  */
886                 scsp_hfsm(dcsp, SCSP_HFSM_VC_CLOSED, NULL);
887
888                 /*
889                  * Set the return code
890                  */
891                 if (rc == -1)
892                         rc = errno;
893                 else
894                         rc = EINVAL;
895         }
896
897         return(rc);
898 }