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