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