Initial import from FreeBSD RELENG_4:
[dragonfly.git] / usr.sbin / atm / scspd / scsp_msg.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_msg.c,v 1.3 1999/08/28 01:15:33 peter Exp $
27  *
28  */
29
30
31 /*
32  * Server Cache Synchronization Protocol (SCSP) Support
33  * ----------------------------------------------------
34  *
35  * SCSP message-handling routines
36  *
37  */
38
39 #include <sys/types.h>
40 #include <sys/param.h>
41 #include <sys/socket.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
59 #include "scsp_msg.h"
60 #include "scsp_if.h"
61 #include "scsp_var.h"
62
63 #ifndef lint
64 __RCSID("@(#) $FreeBSD: src/usr.sbin/atm/scspd/scsp_msg.c,v 1.3 1999/08/28 01:15:33 peter Exp $");
65 #endif
66
67
68 /*
69  * Copy CSAS records into a CA record
70  *
71  * Arguments:
72  *      dcsp    pointer to DCS block for DCS
73  *      cap     pointer to CA record for CSASs
74  *
75  *
76  * Returns:
77  *      none
78  *
79  */
80 static void
81 scsp_ca_csas_setup(dcsp, cap)
82         Scsp_dcs        *dcsp;
83         Scsp_ca         *cap;
84 {
85         int             csas_len, len, mtu;
86         Scsp_server     *ssp = dcsp->sd_server;
87         Scsp_cse        *csep, *next_csep;
88         Scsp_csa        *csap;
89
90         /*
91          * Loop through pending CSAS records
92          */
93         len = sizeof(struct scsp_nhdr) + sizeof(struct scsp_nmcp) +
94                         ssp->ss_lsid.id_len +
95                         dcsp->sd_dcsid.id_len;
96         csas_len = sizeof(struct scsp_ncsa) +
97                         dcsp->sd_server->ss_id_len +
98                         dcsp->sd_server->ss_ckey_len;
99         mtu = dcsp->sd_server->ss_mtu;
100         for (csep = dcsp->sd_ca_csas;
101                         csep && (len < mtu - csas_len);
102                         csep = next_csep) {
103                 next_csep = csep->sc_next;
104                 csap = scsp_cse2csas(csep);
105                 LINK2TAIL(csap, Scsp_csa, cap->ca_csa_rec, next);
106                 len += csas_len;
107                 UNLINK(csep, Scsp_cse, dcsp->sd_ca_csas, sc_next);
108                 UM_FREE(csep);
109                 cap->ca_mcp.rec_cnt++;
110         }
111 }
112
113
114 /*
115  * Process CSA records from a CSU Request that may be in response to
116  * CSAS records sent in a CSUS
117  *
118  * Arguments:
119  *      dcsp    pointer to DCS control block
120  *      msg     pointer to received message
121  *
122  * Returns:
123  *      none
124  *
125  */
126 void
127 scsp_csus_ack(dcsp, msg)
128         Scsp_dcs        *dcsp;
129         Scsp_msg        *msg;
130 {
131         Scsp_csu_msg    *csusp;
132         Scsp_csa        *csap, *csasp, *next_csasp;
133
134         /*
135          * If this isn't a CSU Request, or there's no outstanding CSUS,
136          * or the outstanding CSUS has already been satisfied, just
137          * return
138          */
139         if (!msg || msg->sc_msg_type != SCSP_CSU_REQ_MSG ||
140                         !dcsp->sd_csus_rexmt_msg ||
141                         !dcsp->sd_csus_rexmt_msg->sc_csu_msg ||
142                         !dcsp->sd_csus_rexmt_msg->sc_csu_msg->csu_csa_rec)
143                 return;
144
145
146         /*
147          * Loop through the CSASs in the CSUS message, checking for
148          * each in the CSA records of the received CSU Request
149          */
150         csusp = dcsp->sd_csus_rexmt_msg->sc_csu_msg;
151         for (csasp = csusp->csu_csa_rec; csasp; csasp = next_csasp) {
152                 next_csasp = csasp->next;
153                 for (csap = msg->sc_csu_msg->csu_csa_rec;
154                                 csap; csap = csap->next) {
155                         /*
156                          * If the records match, unlink and free the
157                          * CSAS from the CSUS
158                          */
159                         if (scsp_cmp_key(&csap->key, &csasp->key) == 0 &&
160                                         scsp_cmp_key(&csap->key, &csasp->key) == 0 &&
161                                         scsp_cmp_id(&csap->oid, &csasp->oid) == 0 &&
162                                         csap->seq >= csasp->seq) {
163                                 UNLINK(csasp, Scsp_csa,
164                                                 csusp->csu_csa_rec,
165                                                 next);
166                                 SCSP_FREE_CSA(csasp);
167                                 dcsp->sd_csus_rexmt_msg->sc_csu_msg->csu_mcp.rec_cnt--;
168                                 break;
169                         }
170                 }
171         }
172
173         if (csusp->csu_csa_rec == (Scsp_csa *)0) {
174                 /*
175                  * All CSASs in the CSUS message have been
176                  * answered.  Stop the timer and free the
177                  * saved message.
178                  */
179                 HARP_CANCEL(&dcsp->sd_csus_rexmt_t);
180                 scsp_free_msg(dcsp->sd_csus_rexmt_msg);
181                 dcsp->sd_csus_rexmt_msg = (Scsp_msg *)0;
182
183                 /*
184                  * If the CRL isn't empty, send another CSUS
185                  */
186                 if (dcsp->sd_crl) {
187                         (void)scsp_send_csus(dcsp);
188                 }
189         }
190 }
191
192
193 /*
194  * Send a CA message
195  *
196  * Arguments:
197  *      dcsp    pointer to DCS block for DCS
198  *
199  * Returns:
200  *      0       message sent OK
201  *      else    errno indicating reason for failure
202  *
203  */
204 int
205 scsp_send_ca(dcsp)
206         Scsp_dcs        *dcsp;
207 {
208         int             rc;
209         Scsp_msg        *ca_msg;
210         Scsp_ca         *cap;
211         Scsp_server     *ssp = dcsp->sd_server;
212
213         /*
214          * Get memory for a CA message
215          */
216         ca_msg = (Scsp_msg *)UM_ALLOC(sizeof(Scsp_msg));
217         if (!ca_msg) {
218                 scsp_mem_err("scsp_send_ca: sizeof(Scsp_msg)");
219         }
220         cap = (Scsp_ca *)UM_ALLOC(sizeof(Scsp_ca));
221         if (!cap) {
222                 scsp_mem_err("scsp_send_ca: sizeof(Scsp_ca)");
223         }
224         UM_ZERO(ca_msg, sizeof(Scsp_msg));
225         UM_ZERO(cap, sizeof(Scsp_ca));
226
227         /*
228          * Fill out constant fields
229          */
230         ca_msg->sc_msg_type = SCSP_CA_MSG;
231         ca_msg->sc_ca = cap;
232         cap->ca_seq = dcsp->sd_ca_seq;
233         cap->ca_mcp.pid = ssp->ss_pid;
234         cap->ca_mcp.sgid = ssp->ss_sgid;
235         cap->ca_mcp.sid = ssp->ss_lsid;
236         cap->ca_mcp.rid = dcsp->sd_dcsid;
237
238         /*
239          * Fill out state-dependent fields
240          */
241         switch(dcsp->sd_ca_state) {
242         case SCSP_CAFSM_NEG:
243                 cap->ca_m = 1;
244                 cap->ca_i = 1;
245                 cap->ca_o = 1;
246                 break;
247         case SCSP_CAFSM_MASTER:
248                 cap->ca_m = 1;
249                 cap->ca_i = 0;
250                 scsp_ca_csas_setup(dcsp, cap);
251                 cap->ca_o = dcsp->sd_ca_csas != (Scsp_cse *)0;
252                 break;
253         case SCSP_CAFSM_SLAVE:
254                 cap->ca_m = 0;
255                 cap->ca_i = 0;
256                 scsp_ca_csas_setup(dcsp, cap);
257                 cap->ca_o = dcsp->sd_ca_csas != (Scsp_cse *)0;
258                 break;
259         default:
260                 scsp_log(LOG_ERR, "Invalid state in scsp_send_ca");
261                 abort();
262         }
263
264         /*
265          * Send the CA message and save a pointer to it in case
266          * it needs to be retransmitted
267          */
268         rc = scsp_send_msg(dcsp, ca_msg);
269         if (rc == 0) {
270                 dcsp->sd_ca_rexmt_msg = ca_msg;
271         } else {
272                 scsp_free_msg(ca_msg);
273         }
274
275         return(rc);
276 }
277
278
279 /*
280  * Send a CSU Solicit message
281  *
282  * Arguments:
283  *      dcsp    pointer to DCS block for DCS
284  *
285  * Returns:
286  *      0       message sent OK
287  *      else    errno indicating reason for failure
288  *
289  */
290 int
291 scsp_send_csus(dcsp)
292         Scsp_dcs        *dcsp;
293 {
294         int             csas_len, len, mtu, rc;
295         Scsp_msg        *csus_msg;
296         Scsp_csu_msg    *csusp;
297         Scsp_csa        *csasp, *next_csasp;
298         Scsp_server     *ssp = dcsp->sd_server;
299
300         /*
301          * If we have a mesage saved for retransmission, use it.
302          * If not, get memory for a new one.
303          */
304         if (dcsp->sd_csus_rexmt_msg) {
305                 csus_msg = dcsp->sd_csus_rexmt_msg;
306                 csusp = csus_msg->sc_csu_msg;
307         } else {
308                 /*
309                  * Get memory for a CSUS message
310                  */
311                 csus_msg = (Scsp_msg *)UM_ALLOC(sizeof(Scsp_msg));
312                 if (!csus_msg) {
313                         scsp_mem_err("scsp_send_csus: sizeof(Scsp_msg)");
314                 }
315                 csusp = (Scsp_csu_msg *)UM_ALLOC(sizeof(Scsp_csu_msg));
316                 if (!csusp) {
317                         scsp_mem_err("scsp_send_csus: sizeof(Scsp_csu_msg)");
318                 }
319                 UM_ZERO(csus_msg, sizeof(Scsp_msg));
320                 UM_ZERO(csusp, sizeof(Scsp_csu_msg));
321
322                 /*
323                  * Fill out constant fields
324                  */
325                 csus_msg->sc_msg_type = SCSP_CSUS_MSG;
326                 csus_msg->sc_csu_msg = csusp;
327                 csusp->csu_mcp.pid = ssp->ss_pid;
328                 csusp->csu_mcp.sgid = ssp->ss_sgid;
329                 csusp->csu_mcp.sid = ssp->ss_lsid;
330                 csusp->csu_mcp.rid = dcsp->sd_dcsid;
331         }
332
333         /*
334          * Move CSAS records from CRL into message
335          */
336         mtu = dcsp->sd_server->ss_mtu;
337         csas_len = sizeof(struct scsp_ncsa) + ssp->ss_id_len +
338                         ssp->ss_ckey_len;
339         len = sizeof(struct scsp_nhdr) + sizeof(struct scsp_nmcp) +
340                         2 * ssp->ss_id_len +
341                         csas_len * (csusp->csu_mcp.rec_cnt + 1);
342         for (csasp = dcsp->sd_crl;
343                         csasp && ((len + csas_len) < mtu);
344                         csasp = next_csasp, len += csas_len) {
345                 next_csasp = csasp->next;
346                 csusp->csu_mcp.rec_cnt++;
347                 UNLINK(csasp, Scsp_csa, dcsp->sd_crl, next);
348                 LINK2TAIL(csasp, Scsp_csa, csusp->csu_csa_rec, next);
349                 csasp->hops = 1;
350         }
351
352         /*
353          * Send the CSUS message and save a pointer to it in case
354          * it needs to be retransmitted
355          */
356         rc = scsp_send_msg(dcsp, csus_msg);
357         if (rc == 0) {
358                 /*
359                  * Success--Save a pointer to the message and
360                  * start the CSUS retransmit timer
361                  */
362                 dcsp->sd_csus_rexmt_msg = csus_msg;
363                 HARP_TIMER(&dcsp->sd_csus_rexmt_t,
364                                 dcsp->sd_csus_rexmt_int,
365                                 scsp_csus_retran_timeout);
366         } else {
367                 /*
368                  * Error--free the CSUS message
369                  */
370                 scsp_free_msg(csus_msg);
371         }
372
373         return(rc);
374 }
375
376
377 /*
378  * Send a CSU Request message
379  *
380  * Arguments:
381  *      dcsp    pointer to DCS block for DCS
382  *      csap    pointer to CSAs to include
383  *
384  * Returns:
385  *      0       message sent OK
386  *      else    errno indicating reason for failure
387  *
388  */
389 int
390 scsp_send_csu_req(dcsp, csap)
391         Scsp_dcs        *dcsp;
392         Scsp_csa        *csap;
393 {
394         int             rc;
395         Scsp_server     *ssp = dcsp->sd_server;
396         Scsp_csa        *cnt_csap;
397         Scsp_msg        *csu_msg;
398         Scsp_csu_msg    *csup;
399         Scsp_csu_rexmt  *rxp;
400
401         /*
402          * Return if CSA list is empty
403          */
404         if (!csap)
405                 return(0);
406
407         /*
408          * Get memory for a CSU Req message
409          */
410         csu_msg = (Scsp_msg *)UM_ALLOC(sizeof(Scsp_msg));
411         if (!csu_msg) {
412                 scsp_mem_err("scsp_send_csu_req: sizeof(Scsp_msg)");
413         }
414         csup = (Scsp_csu_msg *)UM_ALLOC(sizeof(Scsp_csu_msg));
415         if (!csup) {
416                 scsp_mem_err("scsp_send_csu_req: sizeof(Scsp_csu_msg)");
417         }
418         UM_ZERO(csu_msg, sizeof(Scsp_msg));
419         UM_ZERO(csup, sizeof(Scsp_csu_msg));
420
421         /*
422          * Get memory for a CSU Req retransmission queue entry
423          */
424         rxp = (Scsp_csu_rexmt *)UM_ALLOC(sizeof(Scsp_csu_rexmt));
425         if (!rxp) {
426                 scsp_mem_err("scsp_send_csu_req: sizeof(Scsp_csu_rexmt)");
427         }
428         UM_ZERO(rxp, sizeof(Scsp_csu_rexmt));
429
430         /*
431          * Fill out constant fields
432          */
433         csu_msg->sc_msg_type = SCSP_CSU_REQ_MSG;
434         csu_msg->sc_csu_msg = csup;
435         csup->csu_mcp.pid = ssp->ss_pid;
436         csup->csu_mcp.sgid = ssp->ss_sgid;
437         csup->csu_mcp.sid = ssp->ss_lsid;
438         csup->csu_mcp.rid = dcsp->sd_dcsid;
439
440         /*
441          * Put the CSA list into the message
442          */
443         csup->csu_csa_rec = csap;
444         for (cnt_csap = csap; cnt_csap; cnt_csap = cnt_csap->next) {
445                 csup->csu_mcp.rec_cnt++;
446         }
447
448         /*
449          * Send the CSU Request
450          */
451         rc = scsp_send_msg(dcsp, csu_msg);
452         if (rc) {
453                 scsp_free_msg(csu_msg);
454                 return(rc);
455         }
456         UM_FREE(csu_msg);
457         UM_FREE(csup);
458
459         /*
460          * Save the CSA entries on the CSU Request retransmission
461          * queue and start the retransmission timer
462          */
463         rxp->sr_dcs = dcsp;
464         rxp->sr_csa = csap;
465         HARP_TIMER(&rxp->sr_t, dcsp->sd_csu_rexmt_int,
466                         scsp_csu_req_retran_timeout);
467         LINK2TAIL(rxp, Scsp_csu_rexmt, dcsp->sd_csu_rexmt, sr_next);
468
469         return(0);
470 }
471
472
473 /*
474  * Send a CSU Reply message
475  *
476  * Arguments:
477  *      dcsp    pointer to DCS block for DCS
478  *      csap    pointer to CSAs to include
479  *
480  * Returns:
481  *      0       message sent OK
482  *      errno   reason for failure
483  *
484  */
485 int
486 scsp_send_csu_reply(dcsp, csap)
487         Scsp_dcs        *dcsp;
488         Scsp_csa        *csap;
489 {
490         int             rc;
491         Scsp_server     *ssp = dcsp->sd_server;
492         Scsp_csa        *csap1;
493         Scsp_msg        *csu_msg;
494         Scsp_csu_msg    *csup;
495
496         /*
497          * Return if CSA list is empty
498          */
499         if (!csap)
500                 return(0);
501
502         /*
503          * Get memory for a CSU Reply message
504          */
505         csu_msg = (Scsp_msg *)UM_ALLOC(sizeof(Scsp_msg));
506         if (!csu_msg) {
507                 scsp_mem_err("scsp_send_csu_reply: sizeof(Scsp_msg)");
508         }
509         csup = (Scsp_csu_msg *)UM_ALLOC(sizeof(Scsp_csu_msg));
510         if (!csup) {
511                 scsp_mem_err("scsp_send_csu_reply: sizeof(Scsp_csu_msg)");
512         }
513         UM_ZERO(csu_msg, sizeof(Scsp_msg));
514         UM_ZERO(csup, sizeof(Scsp_csu_msg));
515
516         /*
517          * Fill out constant fields
518          */
519         csu_msg->sc_msg_type = SCSP_CSU_REPLY_MSG;
520         csu_msg->sc_csu_msg = csup;
521         csup->csu_mcp.pid = ssp->ss_pid;
522         csup->csu_mcp.sgid = ssp->ss_sgid;
523         csup->csu_mcp.sid = ssp->ss_lsid;
524         csup->csu_mcp.rid = dcsp->sd_dcsid;
525
526         /*
527          * Put the CSA list into the message.  Convert the CSAs into
528          * CSASs by freeing the protocol-specific portion.
529          */
530         csup->csu_csa_rec = csap;
531         for (csap1 = csap; csap1; csap1 = csap1->next) {
532                 switch(dcsp->sd_server->ss_pid) {
533                 /*
534                  * We currently only support ATMARP
535                  */
536                 case SCSP_PROTO_ATMARP:
537                         if (csap1->atmarp_data) {
538                                 UM_FREE(csap1->atmarp_data);
539                                 csap1->atmarp_data =
540                                                 (Scsp_atmarp_csa *)0;
541                         }
542                         break;
543                 }
544                 csup->csu_mcp.rec_cnt++;
545         }
546
547         /*
548          * Send the CSU Reply
549          */
550         rc = scsp_send_msg(dcsp, csu_msg);
551         scsp_free_msg(csu_msg);
552
553         return(rc);
554 }
555
556
557 /*
558  * Send a Hello message
559  *
560  * Arguments:
561  *      dcsp    pointer to DCS control block
562  *
563  * Returns:
564  *      0       success
565  *      errno   error encountered
566  *
567  */
568 int
569 scsp_send_hello(dcsp)
570         Scsp_dcs        *dcsp;
571 {
572         int             rc;
573         Scsp_msg        *hello;
574         Scsp_hello      *hp;
575
576         /*
577          * Get memory for a Hello message
578          */
579         hello = (Scsp_msg *)UM_ALLOC(sizeof(Scsp_msg));
580         if (!hello) {
581                 scsp_mem_err("scsp_send_hello: sizeof(Scsp_msg)");
582         }
583         UM_ZERO(hello, sizeof(Scsp_msg));
584         hp = (Scsp_hello *)UM_ALLOC(sizeof(Scsp_hello));
585         if (!hp) {
586                 scsp_mem_err("scsp_send_hello: sizeof(Scsp_hello)");
587         }
588         UM_ZERO(hp, sizeof(Scsp_hello));
589
590         /*
591          * Set up the Hello message
592          */
593         hello->sc_msg_type = SCSP_HELLO_MSG;
594         hello->sc_hello = hp;
595         hp->hello_int = SCSP_HELLO_Interval;
596         hp->dead_factor = SCSP_HELLO_DF;
597         hp->family_id = dcsp->sd_server->ss_fid;
598         hp->hello_mcp.pid = dcsp->sd_server->ss_pid;
599         hp->hello_mcp.sgid = dcsp->sd_server->ss_sgid;
600         hp->hello_mcp.flags = 0;
601         hp->hello_mcp.rec_cnt = 0;
602         hp->hello_mcp.sid = dcsp->sd_server->ss_lsid;
603         hp->hello_mcp.rid = dcsp->sd_dcsid;
604
605         /*
606          * Send and free the message
607          */
608         rc = scsp_send_msg(dcsp, hello);
609         scsp_free_msg(hello);
610
611         return(rc);
612 }