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