Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / netproto / atm / spans / spans_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/sys/netatm/spans/spans_msg.c,v 1.5 1999/08/28 00:48:50 peter Exp $
27  *
28  */
29
30 /*
31  * SPANS Signalling Manager
32  * ---------------------------
33  *
34  * SPANS signalling message processing.
35  *
36  */
37
38 #include <netatm/kern_include.h>
39
40 #include <rpc/rpc.h>
41 #include "spans_xdr.h"
42 #include <netatm/spans/spans_var.h>
43
44 #ifndef lint
45 __RCSID("@(#) $FreeBSD: src/sys/netatm/spans/spans_msg.c,v 1.5 1999/08/28 00:48:50 peter Exp $");
46 #endif
47
48 /*
49  * External functions
50  */
51 void            xdrmbuf_init __P((XDR *, KBuffer *, enum xdr_op));
52
53 /*
54  * Local functions
55  */
56 static void     spans_host_link __P((struct spans *, long));
57 static void     spans_status_ind __P((struct spans *, spans_msg *));
58 static void     spans_status_rsp __P((struct spans *, spans_msg *));
59 static void     spans_open_req __P((struct spans *, spans_msg *));
60 static void     spans_open_rsp __P((struct spans *, spans_msg *));
61 static void     spans_close_req __P((struct spans *, spans_msg *));
62 static void     spans_close_rsp __P((struct spans *, spans_msg *));
63 static void     spans_multi_req __P((struct spans *, spans_msg *));
64 static void     spans_add_req __P((struct spans *, spans_msg *));
65 static void     spans_join_req __P((struct spans *, spans_msg *));
66 static void     spans_leave_req __P((struct spans *, spans_msg *));
67 static void     spans_vcir_ind __P((struct spans *, spans_msg *));
68 static void     spans_query_req __P((struct spans *, spans_msg *));
69
70
71 /*
72  * Called to set status when a status message comes in from a host
73  * connected back-to-back with us.  Check the epoch and, if it has
74  * changed, set the appropriate state and save updated state
75  * information.
76  *
77  * Arguments:
78  *      spp             pointer to SPANS protocol instance block
79  *      host_epoch      epoch of host at far end of link
80  *
81  * Returns:
82  *      0       message sent OK
83  *      errno   error encountered
84  *
85  */
86 static void
87 spans_host_link(spp, host_epoch)
88         struct spans    *spp;
89         long    host_epoch;
90 {
91         struct atm_pif  *pip = spp->sp_pif;
92
93         /*
94          * There's a host at the other end of the link.  If its
95          * epoch has changed, clean up our state and save the
96          * new information.
97          */
98         if (spp->sp_s_epoch != host_epoch) {
99                 spp->sp_s_epoch = host_epoch;
100                 spans_switch_reset(spp, SPANS_UNI_UP);
101                 spp->sp_addr.address_format = T_ATM_SPANS_ADDR;
102                 spp->sp_addr.address_length = sizeof(spans_addr);
103                 KM_COPY(&pip->pif_macaddr.ma_data[2],
104                                 &spp->sp_addr.address[4],
105                                 4);
106                 log(LOG_INFO,
107                 "spans: using SPANS address of %s on interface %s%d\n",
108                         spans_addr_print((spans_addr *)spp->sp_addr.address),
109                         pip->pif_name,
110                         pip->pif_unit);
111         }
112 }
113
114 /*
115  * Send a SPANS signalling message
116  *
117  * Called to send a SPANS message.  This routine gets a buffer, performs
118  * XDR processing, and hands the message to the AAL for transmission.
119  *
120  * Arguments:
121  *      spp     pointer to SPANS protocol instance block
122  *      msg     pointer to status message
123  *
124  * Returns:
125  *      0       message sent OK
126  *      errno   error encountered
127  *
128  */
129 int
130 spans_send_msg(spp, msg)
131         struct spans    *spp;
132         spans_msg       *msg;
133 {
134         int             err = 0;
135         KBuffer         *m;
136         XDR             xdrs;
137
138 #ifdef NOTDEF
139         ATM_DEBUG2("spans_send_msg: msg=%p, type=%d\n", msg,
140                         msg->sm_type);
141         if (msg->sm_type != SPANS_STAT_REQ &&
142                         msg->sm_type != SPANS_STAT_IND &&
143                         msg->sm_type != SPANS_STAT_RSP) {
144                 printf("spans_send_msg: sending ");
145                 spans_print_msg(msg);
146         }
147 #endif
148
149         /*
150          * If the signalling channel has been closed, don't do anything
151          */
152         if (!spp->sp_conn)
153                 return(ECONNABORTED);
154
155         /*
156          * Get a buffer
157          */
158         KB_ALLOCPKT(m, sizeof(spans_msg), KB_F_NOWAIT, KB_T_DATA);
159         if (m == NULL) {
160                 /* No buffer available */
161                 return(ENOBUFS);
162         }
163
164         /*
165          * Convert message to network order
166          */
167         KB_LEN(m) = KB_BFRLEN(m);
168         xdrmbuf_init(&xdrs, m, XDR_ENCODE);
169         if (!xdr_spans_msg(&xdrs, msg)) {
170                 log(LOG_ERR, "spans_send_msg: XDR encode failed\n");
171                 KB_LEN(m) = XDR_GETPOS(&xdrs);
172                 spans_dump_buffer(m);
173                 KB_FREEALL(m);
174                 return(EIO);
175         }
176         KB_LEN(m) = XDR_GETPOS(&xdrs);
177
178         /*
179          * Send the message
180          */
181         err = atm_cm_cpcs_data(spp->sp_conn, m);
182         if (err)
183                 KB_FREEALL(m);
184
185         return(err);
186 }
187
188
189 /*
190  * Send an open request
191  *
192  * Build and send an open request.
193  *
194  * Arguments:
195  *      spp     pointer to SPANS protocol instance block
196  *      svp     pointer to VCCB for which the request is being sent
197  *
198  * Returns:
199  *      none
200  *
201  */
202 int
203 spans_send_open_req(spp, svp)
204         struct  spans           *spp;
205         struct  spans_vccb      *svp;
206 {
207         spans_msg       *req;
208         int             err = 0;
209
210         ATM_DEBUG1("spans_send_open_req: svp=%p\n", svp);
211
212         /*
213          * Get memory for a request message
214          */
215         req = (spans_msg *)atm_allocate(&spans_msgpool);
216         if (req == NULL) {
217                 err = ENOBUFS;
218                 goto done;
219         }
220
221         /*
222          * Fill in the request
223          */
224         req->sm_vers = SPANS_VERS_1_0;
225         req->sm_type = SPANS_OPEN_REQ;
226         req->sm_open_req.opreq_conn = svp->sv_conn;
227         req->sm_open_req.opreq_aal = svp->sv_spans_aal;
228         req->sm_open_req.opreq_desrsrc = svp->sv_spans_qos;
229         req->sm_open_req.opreq_minrsrc.rsc_peak = 0;
230         req->sm_open_req.opreq_minrsrc.rsc_mean = 0;
231         req->sm_open_req.opreq_minrsrc.rsc_burst = 0;
232         req->sm_open_req.opreq_vpvc.vpf_valid = FALSE;
233
234         /*
235          * Send the request
236          */
237         err = spans_send_msg(spp, req);
238         atm_free(req);
239
240 done:
241         return(err);
242 }
243
244
245 /*
246  * Send an open response
247  *
248  * Build and send a response to an open request or open indication.
249  *
250  * Arguments:
251  *      spp     pointer to SPANS protocol instance block
252  *      svp     pointer to VCCB for which the response is being sent
253  *      result  result code to include in the response
254  *
255  * Returns:
256  *      none
257  *
258  */
259 int
260 spans_send_open_rsp(spp, svp, result)
261         struct  spans           *spp;
262         struct  spans_vccb      *svp;
263         spans_result            result;
264 {
265         spans_msg       *rsp;
266         int             rc;
267
268         ATM_DEBUG2("spans_send_open_rsp: svp=%p, result=%d\n", svp,
269                         result);
270
271         /*
272          * Get memory for a response message
273          */
274         rsp = (spans_msg *)atm_allocate(&spans_msgpool);
275         if (rsp == NULL)
276                 return(ENOBUFS);
277
278         /*
279          * Fill in the response
280          */
281         rsp->sm_vers = SPANS_VERS_1_0;
282         rsp->sm_type = SPANS_OPEN_RSP;
283         rsp->sm_open_rsp.oprsp_conn = svp->sv_conn;
284         rsp->sm_open_rsp.oprsp_result = result;
285         rsp->sm_open_rsp.oprsp_rsrc = svp->sv_spans_qos;
286         rsp->sm_open_rsp.oprsp_vpvc =
287                         SPANS_PACK_VPIVCI(svp->sv_vpi, svp->sv_vci);
288
289         /*
290          * Send the response
291          */
292         rc = spans_send_msg(spp, rsp);
293         atm_free(rsp);
294
295         return(rc);
296 }
297
298
299 /*
300  * Send a close request
301  *
302  * Called to send a close request.
303  *
304  * Arguments:
305  *      spp     pointer to SPANS protocol instance block
306  *      svp     pointer to VCCB for which the close is being sent
307  *
308  * Returns:
309  *      none
310  *
311  */
312 int
313 spans_send_close_req(spp, svp)
314         struct spans            *spp;
315         struct  spans_vccb      *svp;
316 {
317         spans_msg       *req;
318         int             err = 0;
319
320         ATM_DEBUG1("spans_send_close_req: svp=%p\n", svp);
321
322         /*
323          * Get memory for a close request
324          */
325         req = (spans_msg *)atm_allocate(&spans_msgpool);
326         if (req == NULL) {
327                 err = ENOBUFS;
328                 goto done;
329         }
330
331         /*
332          * Fill in the request
333          */
334         req->sm_vers = SPANS_VERS_1_0;
335         if (svp->sv_type & VCC_OUT) {
336                 req->sm_type = SPANS_CLOSE_REQ;
337         } else if (svp->sv_type & VCC_IN) {
338                 req->sm_type = SPANS_RCLOSE_REQ;
339         } else {
340                 err = EINVAL;
341                 ATM_DEBUG1(
342                 "spans_send_close_req: invalid VCCB type 0x%x\n",
343                                 svp->sv_type);
344                 goto done;
345         }
346         req->sm_close_req.clreq_conn = svp->sv_conn;
347
348         /*
349          * Send the close request
350          */
351         err = spans_send_msg(spp, req);
352
353 done:
354         if (req)
355                 atm_free(req);
356
357         return(err);
358 }
359
360
361
362 /*
363  * Process a status indication or status request
364  *
365  * Called when a status indication or status request is received.
366  * Processing will be based on the current SPANS state.
367  *
368  * Arguments:
369  *      spp     pointer to SPANS protocol instance block
370  *      msg     pointer to the status message
371  *
372  * Returns:
373  *      none
374  *
375  */
376 static void
377 spans_status_ind(spp, msg)
378         struct  spans   *spp;
379         spans_msg       *msg;
380 {
381         spans_msg       *rsp_msg;
382         struct atm_pif  *pip = spp->sp_pif;
383
384         /*
385          * Reset the probe count.
386          */
387         spp->sp_probe_ct = 0;
388
389         switch (spp->sp_state) {
390         case SPANS_PROBE:
391                 /*
392                  * Interface just came up, update signalling state
393                  */
394                 spp->sp_state = SPANS_ACTIVE;
395                 break;
396
397         case SPANS_ACTIVE:
398                 break;
399
400         default:
401                 log(LOG_ERR, "spans: received status msg in state %d\n",
402                                 spp->sp_state);
403         }
404
405         /*
406          * Process the message
407          */
408         switch (msg->sm_type) {
409
410         case SPANS_STAT_REQ:
411                 /*
412                  * Handle a request from a host at the other end of
413                  * the link.
414                  */
415                 spans_host_link(spp, msg->sm_stat_req.streq_es_epoch);
416                 break;
417
418         case SPANS_STAT_IND:
419
420                 /*
421                  * There's a switch at the other end of the link.  If
422                  * its epoch has changed, reset the SPANS state and save
423                  * the new information.
424                  */
425                 if (spp->sp_s_epoch !=
426                                 msg->sm_stat_ind.stind_sw_epoch) {
427                         spans_switch_reset(spp, SPANS_UNI_UP);
428                         spp->sp_s_epoch =
429                                 msg->sm_stat_ind.stind_sw_epoch;
430                         spp->sp_addr.address_format = T_ATM_SPANS_ADDR;
431                         spp->sp_addr.address_length =
432                                         sizeof(spans_addr);
433                         spans_addr_copy(&msg->sm_stat_ind.stind_es_addr,
434                                 spp->sp_addr.address);
435                         log(LOG_INFO,
436                 "spans: received SPANS address %s from switch for interface %s%d\n",
437                                         spans_addr_print((spans_addr *)spp->sp_addr.address),
438                                         pip->pif_name,
439                                         pip->pif_unit);
440                 }
441                 break;
442
443         default:
444                 ATM_DEBUG1("spans_status_ind: Invalid message type %d\n",
445                                 msg->sm_type);
446                 return;
447         }
448
449         /*
450          * Respond to the status request or indication with a
451          * status response
452          */
453         rsp_msg = (spans_msg *)atm_allocate(&spans_msgpool);
454         if (rsp_msg == NULL)
455                 return;
456         rsp_msg->sm_vers = SPANS_VERS_1_0;
457         rsp_msg->sm_type = SPANS_STAT_RSP;
458         rsp_msg->sm_stat_rsp.strsp_es_epoch = spp->sp_h_epoch;
459         spans_addr_copy(spp->sp_addr.address,
460                         &rsp_msg->sm_stat_rsp.strsp_es_addr);
461         spans_send_msg(spp, rsp_msg);
462         atm_free(rsp_msg);
463 }
464
465
466
467 /*
468  * Process a status response
469  *
470  * Called when a status response is received.
471  * Processing will be based on the current SPANS state.
472  *
473  * Arguments:
474  *      spp     pointer to SPANS protocol instance block
475  *      msg     pointer to the status response message
476  *
477  * Returns:
478  *      none
479  *
480  */
481 static void
482 spans_status_rsp(spp, msg)
483         struct  spans   *spp;
484         spans_msg       *msg;
485 {
486
487         /*
488          * Reset the probe count.
489          */
490         spp->sp_probe_ct = 0;
491
492         switch (spp->sp_state) {
493         case SPANS_PROBE:
494                 /*
495                  * Interface just came up, update signalling state
496                  */
497                 spp->sp_state = SPANS_ACTIVE;
498                 break;
499
500         case SPANS_ACTIVE:
501                 break;
502
503         default:
504                 log(LOG_ERR, "spans: received status msg in state %d\n",
505                                 spp->sp_state);
506         }
507
508         /*
509          * Process the message
510          */
511         spans_host_link(spp, msg->sm_stat_req.streq_es_epoch);
512 }
513
514
515 /*
516  * Process an open indication or open request
517  *
518  * Called when an open indication or open request is received.
519  * Processing will be based on the state of the requested connection.
520  *
521  * Arguments:
522  *      spp     pointer to SPANS protocol instance block
523  *      msg     pointer to the open message
524  *
525  * Returns:
526  *      none
527  *
528  */
529 static void
530 spans_open_req(spp, msg)
531         struct spans    *spp;
532         spans_msg       *msg;
533 {
534         spans_result            result = SPANS_OK;
535         spans_msg               *rsp_msg;
536         struct spans_vccb       *svp = NULL;
537         struct atm_pif          *pip;
538         spans_vpvc              vpvc;
539         int                     err = 0, vpi, vci;
540         Aal_t                   aal;
541         Atm_attributes          call_attrs;
542
543         ATM_DEBUG2("spans_open_req: spp=%p, msg=%p\n", spp, msg);
544
545         /*
546          * See if the connection is new
547          */
548         if ((svp = spans_find_conn(spp, &msg->sm_open_req.opreq_conn)) != NULL) {
549                 /*
550                  * We already have a VCCB that matches the connection in
551                  * the request
552                  */
553                 vpi = SPANS_EXTRACT_VPI(msg->sm_open_req.opreq_vpvc.vpf_vpvc);
554                 vci = SPANS_EXTRACT_VCI(msg->sm_open_req.opreq_vpvc.vpf_vpvc);
555                 if (msg->sm_open_req.opreq_aal == svp->sv_spans_aal &&
556                                 (!msg->sm_open_req.opreq_vpvc.vpf_valid ||
557                                         (vpi == svp->sv_vpi &&
558                                         vci == svp->sv_vci))) {
559                         /*
560                          * VCCB already exists, process depending on
561                          * state
562                          */
563                         switch (svp->sv_sstate) {
564                         case SPANS_VC_R_POPEN:
565                                 /* I'm still thinking about it */
566                                 return;
567                         case SPANS_VC_OPEN:
568                                 /* Retransmit the open_rsp */
569                                 break;
570                         case SPANS_VC_POPEN:
571                         case SPANS_VC_CLOSE:
572                         case SPANS_VC_ABORT:
573                                 ATM_DEBUG0("spans_open_req: bad VCCB state\n");
574                                 result = SPANS_FAIL;
575                                 break;
576                         }
577                 } else {
578                         /*
579                          * VCCB is for same connection, but other
580                          * parameters don't match
581                          */
582                         ATM_DEBUG0("spans_open_req: VCCB confusion\n");
583                         result = SPANS_FAIL;
584                 }
585                 svp = NULL;
586                 goto response;
587         }
588
589         /*
590          * Verify that the request is for our ATM addres
591          */
592         if (spans_addr_cmp(spp->sp_addr.address,
593                         &msg->sm_open_req.opreq_conn.con_dst)) {
594                 ATM_DEBUG0("spans_open_req: bad destination\n");
595                 result = SPANS_BADDEST;
596                 goto response;
597         }
598
599         /*
600          * See if we recognize the specified AAL
601          */
602         if (!spans_get_local_aal(msg->sm_open_req.opreq_aal, &aal)) {
603                 ATM_DEBUG0("spans_open_req: bad AAL\n");
604                 result = SPANS_FAIL;
605                 goto response;
606         }
607
608         /*
609          * Should verify that we can handle requested connection QOS
610          */
611
612         /*
613          * Select a VPI/VCI for the new connection
614          */
615         if (msg->sm_open_req.opreq_vpvc.vpf_valid) {
616                 /*
617                  * Requestor asked for a certain VPI/VCI.  Make sure we
618                  * aren't already using the pair that was asked for.
619                  */
620                 vpi = SPANS_EXTRACT_VPI(msg->sm_open_req.opreq_vpvc.vpf_vpvc);
621                 vci = SPANS_EXTRACT_VCI(msg->sm_open_req.opreq_vpvc.vpf_vpvc);
622                 if (spans_find_vpvc(spp, vci, vpi, VCC_IN)) {
623                         ATM_DEBUG0("spans_open_req: VPI, VCI busy\n");
624                         result = SPANS_NOVPVC;
625                         goto response;
626                 }
627                 vpvc = msg->sm_open_req.opreq_vpvc.vpf_vpvc;
628         } else {
629                 /*
630                  * Allocate a VPI/VCI for this end of the VCC
631                  */
632                 vpvc = spans_alloc_vpvc(spp);
633                 if (vpvc == 0) {
634                         ATM_DEBUG0("spans_open_req: no VPI, VCI available\n");
635                         result = SPANS_NOVPVC;
636                         goto response;
637                 }
638         }
639
640         /*
641          * Get a new VCCB for the connection
642          */
643         svp = (struct spans_vccb *)atm_allocate(&spans_vcpool);
644         if (svp == NULL) {
645                 ATM_DEBUG0("spans_open_req: VCCB pool empty\n");
646                 result = SPANS_NORSC;
647                 goto response;
648         }
649
650         /*
651          * Find the physical interface structure
652          */
653         pip = spp->sp_pif;
654
655         /*
656          * Fill in the VCCB fields that we can at this point
657          */
658         svp->sv_type = VCC_SVC | VCC_IN;
659         svp->sv_proto = ATM_SIG_SPANS;
660         svp->sv_sstate = SPANS_VC_R_POPEN;
661         svp->sv_ustate = VCCU_POPEN;
662         svp->sv_pif = pip;
663         svp->sv_nif = pip->pif_nif;
664         svp->sv_conn = msg->sm_open_req.opreq_conn;
665         svp->sv_spans_qos = msg->sm_open_req.opreq_desrsrc;
666         svp->sv_spans_aal = msg->sm_open_req.opreq_aal;
667         svp->sv_tstamp = time_second;
668
669         svp->sv_vpi = SPANS_EXTRACT_VPI(vpvc);
670         svp->sv_vci = SPANS_EXTRACT_VCI(vpvc);
671
672         /*
673          * Put the VCCB on the SPANS queue
674          */
675         ENQUEUE(svp, struct spans_vccb, sv_sigelem, spp->sp_vccq);
676
677         /*
678          * Set up the ATM attributes block
679          */
680         KM_ZERO(&call_attrs, sizeof(call_attrs));
681         call_attrs.nif = svp->sv_nif;
682         call_attrs.api = CMAPI_CPCS;
683
684         call_attrs.aal.tag = T_ATM_PRESENT;
685         call_attrs.aal.type = aal;
686         switch(aal) {
687         case ATM_AAL3_4:
688                 call_attrs.aal.v.aal4.forward_max_SDU_size =
689                                 ATM_NIF_MTU;
690                 call_attrs.aal.v.aal4.backward_max_SDU_size =
691                                 ATM_NIF_MTU;
692                 call_attrs.aal.v.aal4.SSCS_type =
693                                 T_ATM_NULL;
694                 call_attrs.aal.v.aal4.mid_low = 0;
695                 call_attrs.aal.v.aal4.mid_high = 1023;
696                 break;
697         case ATM_AAL5:
698                 call_attrs.aal.v.aal5.forward_max_SDU_size =
699                                 ATM_NIF_MTU;
700                 call_attrs.aal.v.aal5.backward_max_SDU_size =
701                                 ATM_NIF_MTU;
702                 call_attrs.aal.v.aal5.SSCS_type =
703                                 T_ATM_NULL;
704                 break;
705         }
706
707         call_attrs.traffic.tag = T_ATM_PRESENT;
708         call_attrs.traffic.v.forward.PCR_high_priority = T_ATM_ABSENT;
709         call_attrs.traffic.v.forward.PCR_all_traffic = 
710                         msg->sm_open_req.opreq_desrsrc.rsc_peak *
711                         1000 / 53;
712         call_attrs.traffic.v.forward.SCR_high_priority = T_ATM_ABSENT;
713         call_attrs.traffic.v.forward.SCR_all_traffic = T_ATM_ABSENT;
714         call_attrs.traffic.v.forward.MBS_high_priority = T_ATM_ABSENT;
715         call_attrs.traffic.v.forward.MBS_all_traffic = T_ATM_ABSENT;
716         call_attrs.traffic.v.forward.tagging = T_NO;
717         call_attrs.traffic.v.backward.PCR_high_priority = T_ATM_ABSENT;
718         call_attrs.traffic.v.backward.PCR_all_traffic = 
719                         call_attrs.traffic.v.forward.PCR_all_traffic;
720         call_attrs.traffic.v.backward.SCR_high_priority = T_ATM_ABSENT;
721         call_attrs.traffic.v.backward.SCR_all_traffic = T_ATM_ABSENT;
722         call_attrs.traffic.v.backward.MBS_high_priority = T_ATM_ABSENT;
723         call_attrs.traffic.v.backward.MBS_all_traffic = T_ATM_ABSENT;
724         call_attrs.traffic.v.backward.tagging = T_NO;
725         call_attrs.traffic.v.best_effort = T_YES;
726
727         call_attrs.bearer.tag = T_ATM_PRESENT;
728         call_attrs.bearer.v.bearer_class = T_ATM_CLASS_X;
729         call_attrs.bearer.v.traffic_type = T_ATM_NULL;
730         call_attrs.bearer.v.timing_requirements = T_ATM_NULL;
731         call_attrs.bearer.v.clipping_susceptibility = T_NO;
732         call_attrs.bearer.v.connection_configuration = T_ATM_1_TO_1;
733
734
735         call_attrs.bhli.tag = T_ATM_ABSENT;
736         call_attrs.blli.tag_l2 = T_ATM_ABSENT;
737         call_attrs.blli.tag_l3 = T_ATM_ABSENT;
738         call_attrs.llc.tag = T_ATM_ABSENT;
739
740         call_attrs.called.tag = T_ATM_PRESENT;
741         spans_addr_copy(&msg->sm_open_req.opreq_conn.con_dst,
742                 call_attrs.called.addr.address);
743         call_attrs.called.addr.address_format = T_ATM_SPANS_ADDR;
744         call_attrs.called.addr.address_length = sizeof(spans_addr);
745         call_attrs.called.subaddr.address_format = T_ATM_ABSENT;
746         call_attrs.called.subaddr.address_length = 0;
747
748         call_attrs.calling.tag = T_ATM_PRESENT;
749         spans_addr_copy(&msg->sm_open_req.opreq_conn.con_src,
750                 call_attrs.calling.addr.address);
751         call_attrs.calling.addr.address_format = T_ATM_SPANS_ADDR;
752         call_attrs.calling.addr.address_length = sizeof(spans_addr);
753         call_attrs.calling.subaddr.address_format = T_ATM_ABSENT;
754         call_attrs.calling.subaddr.address_length = 0;
755
756         call_attrs.qos.tag = T_ATM_PRESENT;
757         call_attrs.qos.v.coding_standard = T_ATM_NETWORK_CODING;
758         call_attrs.qos.v.forward.qos_class = T_ATM_QOS_CLASS_0;
759         call_attrs.qos.v.backward.qos_class = T_ATM_QOS_CLASS_0;
760
761         call_attrs.transit.tag = T_ATM_ABSENT;
762         call_attrs.cause.tag = T_ATM_ABSENT;
763
764         /*
765          * Notify the connection manager that it has a new channel
766          */
767         err = atm_cm_incoming((struct vccb *)svp, &call_attrs);
768         if (err) {
769                 ATM_DEBUG0("spans_open_req: atm_cm_incoming returned error\n");
770                 result = SPANS_FAIL;
771                 goto response;
772         }
773
774         /*
775          * Wait for the connection recipient to issue an accept
776          */
777         return;
778
779 response:
780         /*
781          * Clean up the VCCB and the atm_conn block if we got them
782          */
783         if (svp) {
784                 DEQUEUE(svp, struct spans_vccb, sv_sigelem,
785                                 spp->sp_vccq);
786                 atm_free(svp);
787         }
788
789         /*
790          * Some problem was detected with the request.  Send a SPANS
791          * message rejecting the connection.
792          */
793         rsp_msg = (spans_msg *) atm_allocate(&spans_msgpool);
794         if (rsp_msg == NULL)
795                 return;
796
797         /*
798          * Fill out the response
799          */
800         rsp_msg->sm_vers = SPANS_VERS_1_0;
801         rsp_msg->sm_type = SPANS_OPEN_RSP;
802         rsp_msg->sm_open_rsp.oprsp_conn = msg->sm_open_req.opreq_conn;
803         rsp_msg->sm_open_rsp.oprsp_result = result;
804         rsp_msg->sm_open_rsp.oprsp_vpvc = 0;
805
806         /*
807          * Send the Open Response
808          */
809         spans_send_msg(spp, rsp_msg);
810         atm_free(rsp_msg);
811 }
812
813
814 /*
815  * Process an open response or open confirmation
816  *
817  * Called when an open response or open confirmation is received.
818  * Processing will be based on the state of the requested connection and
819  * the status returned.
820  *
821  * Arguments:
822  *      spp     pointer to SPANS protocol instance block
823  *      msg     pointer to the open response or confirmation message
824  *
825  * Returns:
826  *      none
827  *
828  */
829 static void
830 spans_open_rsp(spp, msg)
831         struct spans    *spp;
832         spans_msg       *msg;
833 {
834         struct spans_vccb       *svp;
835
836         ATM_DEBUG2("spans_open_rsp: spp=%p, msg=%p\n", spp, msg);
837
838         /*
839          * Locate the VCCB for the connection
840          */
841         svp = spans_find_conn(spp, &msg->sm_open_rsp.oprsp_conn);
842         if (svp == NULL)
843                 return;
844
845         /*
846          * Check the connection state
847          */
848         if ((svp->sv_sstate != SPANS_VC_POPEN &&
849                         svp->sv_sstate != SPANS_VC_R_POPEN) ||
850                         svp->sv_ustate != VCCU_POPEN) {
851                 ATM_DEBUG2(
852         "spans_open_rsp: invalid VCCB state, sstate=%d, ustate=%d\n",
853                                 svp->sv_sstate, svp->sv_ustate);
854                 return;
855         }
856
857         /*
858          * Cancel the retransmission timer
859          */
860         SPANS_VC_CANCEL((struct vccb *) svp);
861
862         /*
863          * Check the result
864          */
865         switch (msg->sm_open_rsp.oprsp_result) {
866
867         case SPANS_OK:
868                 /*
869                  * Save the assigned VPI and VCI
870                  */
871                 svp->sv_vpi = SPANS_EXTRACT_VPI(msg->sm_open_rsp.oprsp_vpvc);
872                 svp->sv_vci = SPANS_EXTRACT_VCI(msg->sm_open_rsp.oprsp_vpvc);
873
874                 /*
875                  * Update the VCC state and notify the VCC owner
876                  */
877                 svp->sv_sstate = SPANS_VC_OPEN;
878                 svp->sv_ustate = VCCU_OPEN;
879                 svp->sv_tstamp = time_second;
880                 atm_cm_connected(svp->sv_connvc);
881                 break;
882
883         case SPANS_FAIL:
884         case SPANS_NOVPVC:
885         case SPANS_NORSC:
886         case SPANS_BADDEST:
887                 /*
888                  * Close out the VCCB and notify the user
889                  */
890                 svp->sv_sstate = SPANS_VC_FREE;
891                 svp->sv_ustate = VCCU_CLOSED;
892                 svp->sv_connvc->cvc_attr.cause.tag = T_ATM_PRESENT;
893                 svp->sv_connvc->cvc_attr.cause.v.coding_standard =
894                                 T_ATM_ITU_CODING;
895                 svp->sv_connvc->cvc_attr.cause.v.location =
896                                 T_ATM_LOC_USER;
897                 svp->sv_connvc->cvc_attr.cause.v.cause_value =
898                                 T_ATM_CAUSE_CALL_REJECTED;
899                 KM_ZERO(svp->sv_connvc->cvc_attr.cause.v.diagnostics,
900                                 sizeof(svp->sv_connvc->cvc_attr.cause.v.diagnostics));
901                 atm_cm_cleared(svp->sv_connvc);
902                 break;
903
904         default:
905                 log(LOG_ERR, "spans: unknown result %d in open rsp\n",
906                                 msg->sm_open_rsp.oprsp_result);
907                 break;
908         }
909 }
910
911
912 /*
913  * Process a close request from the network
914  *
915  * Called when a close request, close indication, rclose request, or
916  * rclose indication is received.  Processing will be based on the
917  * state of the connection.
918  *
919  * Arguments:
920  *      spp     pointer to SPANS protocol instance block
921  *      msg     pointer to the close request message
922  *
923  * Returns:
924  *      none
925  *
926  */
927 static void
928 spans_close_req(spp, msg)
929         struct spans    *spp;
930         spans_msg       *msg;
931 {
932         struct spans_vccb       *svp;
933         spans_result            result;
934         spans_msg               *rsp_msg;
935         u_char                  outstate;
936         Atm_connvc              *cvp;
937
938         ATM_DEBUG2("spans_close_req: spp=%p, msg=%p\n", spp, msg);
939
940         /*
941          * Locate the VCCB for the connection
942          */
943         svp = spans_find_conn(spp, &msg->sm_close_req.clreq_conn);
944         if (svp == NULL) {
945                 result = SPANS_BADDEST;
946                 goto response;
947         }
948
949         /*
950          * Check the connection type
951          */
952         if (!(svp->sv_type & VCC_SVC)) {
953                 result = SPANS_FAIL;
954                 goto response;
955         }
956
957         /*
958          * Check the connection state
959          */
960         switch (svp->sv_sstate) {
961         case SPANS_VC_OPEN:
962         case SPANS_VC_R_POPEN:
963         case SPANS_VC_POPEN:
964                 /*
965                  * VCC is open or opening--continue
966                  */
967                 break;
968         case SPANS_VC_CLOSE:
969         case SPANS_VC_FREE:
970         case SPANS_VC_ABORT:
971                 /*
972                  * We're already closing--give a response, since this
973                  * is probably a retransmission
974                  */
975                 result = SPANS_OK;
976                 goto response;
977         case SPANS_VC_NULL:
978                 result = SPANS_FAIL;
979                 goto response;
980         }
981
982         /*
983          * Cancel the retransmission timer
984          */
985         SPANS_VC_CANCEL((struct vccb *) svp);
986
987         /*
988          * Close out the VCCB and notify the user
989          */
990         outstate = svp->sv_sstate;
991         svp->sv_ustate = VCCU_CLOSED;
992         svp->sv_sstate = SPANS_VC_FREE;
993         cvp = svp->sv_connvc;
994         switch (outstate) {
995         case SPANS_VC_R_POPEN:
996                 spans_free((struct vccb *)svp);
997                 /* FALLTHRU */
998
999         case SPANS_VC_POPEN:
1000         case SPANS_VC_OPEN:
1001                 cvp->cvc_attr.cause.tag = T_ATM_PRESENT;
1002                 cvp->cvc_attr.cause.v.coding_standard =
1003                                 T_ATM_ITU_CODING;
1004                 cvp->cvc_attr.cause.v.location = T_ATM_LOC_USER;
1005                 cvp->cvc_attr.cause.v.cause_value =
1006                                 T_ATM_CAUSE_NORMAL_CALL_CLEARING;
1007                 KM_ZERO(cvp->cvc_attr.cause.v.diagnostics,
1008                                 sizeof(cvp->cvc_attr.cause.v.diagnostics));
1009                 atm_cm_cleared(svp->sv_connvc);
1010                 break;
1011         }
1012
1013         result = SPANS_OK;
1014
1015 response:
1016         /*
1017          * Respond to the SPANS_CLOSE_IND with a SPANS_CLOSE_RSP
1018          */
1019         rsp_msg = (spans_msg *)atm_allocate(&spans_msgpool);
1020         if (rsp_msg == NULL)
1021                 return;
1022         rsp_msg->sm_vers = SPANS_VERS_1_0;
1023         if (msg->sm_type == SPANS_RCLOSE_REQ ||
1024                         msg->sm_type == SPANS_RCLOSE_IND) {
1025                 rsp_msg->sm_type = SPANS_RCLOSE_RSP;
1026         } else {
1027                 rsp_msg->sm_type = SPANS_CLOSE_RSP;
1028         }
1029         rsp_msg->sm_close_rsp.clrsp_conn = msg->sm_close_req.clreq_conn;
1030         rsp_msg->sm_close_rsp.clrsp_result = result;
1031         spans_send_msg(spp, rsp_msg);
1032         atm_free(rsp_msg);
1033 }
1034
1035
1036 /*
1037  * Process a close response or close confirmation
1038  *
1039  * Called when an close response or close confirmation is received.
1040  * Processing will be based on the state of the requested connection and
1041  * the returned status.
1042  *
1043  * Arguments:
1044  *      spp     pointer to SPANS protocol instance block
1045  *      msg     pointer to the close response or confirmation message
1046  *
1047  * Returns:
1048  *      none
1049  *
1050  */
1051 static void
1052 spans_close_rsp(spp, msg)
1053         struct spans    *spp;
1054         spans_msg       *msg;
1055 {
1056         struct spans_vccb       *svp;
1057
1058         ATM_DEBUG2("spans_close_rsp: spp=%p, msg=%p\n", spp, msg);
1059
1060         /*
1061          * Locate the VCCB for the connection
1062          */
1063         svp = spans_find_conn(spp, &msg->sm_close_rsp.clrsp_conn);
1064         if (svp == NULL) {
1065                 return;
1066         }
1067
1068         /*
1069          * Check the VCCB state
1070          */
1071         if (svp->sv_sstate != SPANS_VC_CLOSE) {
1072                 return;
1073         }
1074
1075         /*
1076          * Cancel the retransmission timer
1077          */
1078         SPANS_VC_CANCEL((struct vccb *) svp);
1079
1080         /*
1081          * Check the response from the remote end
1082          */
1083         switch (msg->sm_close_rsp.clrsp_result) {
1084
1085         case SPANS_OK:
1086                 /*
1087                  * Mark the VCCB as closed and notify the owner
1088                  */
1089                 svp->sv_sstate = SPANS_VC_FREE;
1090                 svp->sv_connvc->cvc_attr.cause.tag = T_ATM_PRESENT;
1091                 svp->sv_connvc->cvc_attr.cause.v.coding_standard =
1092                                 T_ATM_ITU_CODING;
1093                 svp->sv_connvc->cvc_attr.cause.v.location =
1094                                 T_ATM_LOC_USER;
1095                 svp->sv_connvc->cvc_attr.cause.v.cause_value =
1096                                 T_ATM_CAUSE_NORMAL_CALL_CLEARING;
1097                 KM_ZERO(svp->sv_connvc->cvc_attr.cause.v.diagnostics,
1098                                 sizeof(svp->sv_connvc->cvc_attr.cause.v.diagnostics));
1099                 atm_cm_cleared(svp->sv_connvc);
1100                 break;
1101
1102         case SPANS_NOVPVC:
1103         case SPANS_BADDEST:
1104         case SPANS_FAIL:
1105         case SPANS_NORSC:
1106                 /*
1107                  * Mark the VCCB as closed and notify the owner
1108                  */
1109                 svp->sv_sstate = SPANS_VC_FREE;
1110                 svp->sv_connvc->cvc_attr.cause.tag = T_ATM_PRESENT;
1111                 svp->sv_connvc->cvc_attr.cause.v.coding_standard =
1112                                 T_ATM_ITU_CODING;
1113                 svp->sv_connvc->cvc_attr.cause.v.location =
1114                                 T_ATM_LOC_USER;
1115                 svp->sv_connvc->cvc_attr.cause.v.cause_value =
1116                                 T_ATM_CAUSE_UNSPECIFIED_NORMAL;
1117                 KM_ZERO(svp->sv_connvc->cvc_attr.cause.v.diagnostics,
1118                                 sizeof(svp->sv_connvc->cvc_attr.cause.v.diagnostics));
1119                 atm_cm_cleared(svp->sv_connvc);
1120                 break;
1121
1122         default:
1123                 log(LOG_ERR, "spans: unknown result %d in close rsp\n",
1124                                 msg->sm_close_rsp.clrsp_result);
1125                 break;
1126         }
1127 }
1128
1129
1130 /*
1131  * Process a multi request or multi indication
1132  *
1133  * Called when a multi response or multi confirmation is received.  We
1134  * don't support multicast channels, so we just reject the request.
1135  *
1136  * Arguments:
1137  *      spp     pointer to SPANS protocol instance block
1138  *      msg     pointer to the multi request or indication message
1139  *
1140  * Returns:
1141  *      none
1142  *
1143  */
1144 static void
1145 spans_multi_req(spp, msg)
1146         struct spans    *spp;
1147         spans_msg       *msg;
1148 {
1149         spans_msg       *rsp_msg;
1150
1151         /*
1152          * Get memory for a SPANS_MULTI_RSP message.
1153          */
1154         rsp_msg = (spans_msg *) atm_allocate(&spans_msgpool);
1155         if (rsp_msg == NULL)
1156                 return;
1157
1158         /*
1159          * Fill out the response.
1160          */
1161         rsp_msg->sm_vers = SPANS_VERS_1_0;
1162         rsp_msg->sm_type = SPANS_MULTI_RSP;
1163         rsp_msg->sm_multi_rsp.mursp_conn = msg->sm_multi_req.mureq_conn;
1164         rsp_msg->sm_multi_rsp.mursp_result = SPANS_FAIL;
1165         rsp_msg->sm_multi_rsp.mursp_rsrc = msg->sm_multi_req.mureq_desrsrc;
1166         rsp_msg->sm_multi_rsp.mursp_vpvc = 0;
1167
1168         /*
1169          * Send the response and free the message.
1170          */
1171         (void) spans_send_msg(spp, rsp_msg);
1172         atm_free(rsp_msg);
1173 }
1174
1175
1176 /*
1177  * Process an add request or add indication
1178  *
1179  * Called when an add response or add confirmation is received.  We
1180  * don't support multicast channels, so we just reject the request.
1181  *
1182  * Arguments:
1183  *      spp     pointer to SPANS protocol instance block
1184  *      msg     pointer to the add request or indication message
1185  *
1186  * Returns:
1187  *      none
1188  *
1189  */
1190 static void
1191 spans_add_req(spp, msg)
1192         struct spans    *spp;
1193         spans_msg       *msg;
1194 {
1195         spans_msg       *rsp_msg;
1196
1197         /*
1198          * Get memory for a SPANS_ADD_RSP message.
1199          */
1200         rsp_msg = (spans_msg *) atm_allocate(&spans_msgpool);
1201         if (rsp_msg == NULL)
1202                 return;
1203
1204         /*
1205          * Fill out the response.
1206          */
1207         rsp_msg->sm_vers = SPANS_VERS_1_0;
1208         rsp_msg->sm_type = SPANS_ADD_RSP;
1209         rsp_msg->sm_add_rsp.adrsp_conn = msg->sm_add_req.adreq_desconn;
1210         rsp_msg->sm_add_rsp.adrsp_result = SPANS_FAIL;
1211         rsp_msg->sm_add_rsp.adrsp_rsrc.rsc_peak = 0;
1212         rsp_msg->sm_add_rsp.adrsp_rsrc.rsc_mean = 0;
1213         rsp_msg->sm_add_rsp.adrsp_rsrc.rsc_burst = 0;
1214
1215         /*
1216          * Send the response and free the message.
1217          */
1218         (void) spans_send_msg(spp, rsp_msg);
1219         atm_free(rsp_msg);
1220 }
1221
1222
1223 /*
1224  * Process a join request
1225  *
1226  * Called when an join request is received.  We don't support group
1227  * addresses, so we just reject the request.
1228  *
1229  * Arguments:
1230  *      spp     pointer to SPANS protocol instance block
1231  *      msg     pointer to the join request message
1232  *
1233  * Returns:
1234  *      none
1235  *
1236  */
1237 static void
1238 spans_join_req(spp, msg)
1239         struct spans    *spp;
1240         spans_msg       *msg;
1241 {
1242         spans_msg       *rsp_msg;
1243
1244         /*
1245          * Get memory for a SPANS_JOIN_CNF message.
1246          */
1247         rsp_msg = (spans_msg *) atm_allocate(&spans_msgpool);
1248         if (rsp_msg == NULL)
1249                 return;
1250
1251         /*
1252          * Fill out the response.
1253          */
1254         rsp_msg->sm_vers = SPANS_VERS_1_0;
1255         rsp_msg->sm_type = SPANS_JOIN_CNF;
1256         spans_addr_copy(&msg->sm_join_req.jnreq_addr,
1257                         &rsp_msg->sm_join_cnf.jncnf_addr);
1258         rsp_msg->sm_join_cnf.jncnf_result = SPANS_FAIL;
1259
1260         /*
1261          * Send the response and free the message.
1262          */
1263         (void) spans_send_msg(spp, rsp_msg);
1264         atm_free(rsp_msg);
1265 }
1266
1267
1268 /*
1269  * Process a leave request
1270  *
1271  * Called when an leave request is received.  We don't support group
1272  * addresses, so we just reject the request.
1273  *
1274  * Arguments:
1275  *      spp     pointer to SPANS protocol instance block
1276  *      msg     pointer to the leave request message
1277  *
1278  * Returns:
1279  *      none
1280  *
1281  */
1282 static void
1283 spans_leave_req(spp, msg)
1284         struct spans    *spp;
1285         spans_msg       *msg;
1286 {
1287         spans_msg       *rsp_msg;
1288
1289         /*
1290          * Get memory for a SPANS_LEAVE_CNF message.
1291          */
1292         rsp_msg = (spans_msg *) atm_allocate(&spans_msgpool);
1293         if (rsp_msg == NULL)
1294                 return;
1295
1296         /*
1297          * Fill out the response.
1298          */
1299         rsp_msg->sm_vers = SPANS_VERS_1_0;
1300         rsp_msg->sm_type = SPANS_LEAVE_CNF;
1301         spans_addr_copy(&msg->sm_leave_req.lvreq_addr,
1302                         &rsp_msg->sm_leave_cnf.lvcnf_addr);
1303         rsp_msg->sm_leave_cnf.lvcnf_result = SPANS_FAIL;
1304
1305         /*
1306          * Send the response and free the message.
1307          */
1308         (void) spans_send_msg(spp, rsp_msg);
1309         atm_free(rsp_msg);
1310 }
1311
1312
1313 /*
1314  * Process a VCI range indication
1315  *
1316  * Called when a VCI range indication is received.  Adjust the VCI
1317  * bounds if they have changed.
1318  *
1319  * Arguments:
1320  *      spp     pointer to SPANS protocol instance block
1321  *      msg     pointer to the VCI range indication message
1322  *
1323  * Returns:
1324  *      none
1325  *
1326  */
1327 static void
1328 spans_vcir_ind(spp, msg)
1329         struct spans    *spp;
1330         spans_msg       *msg;
1331 {
1332         /*
1333          * Adjust the limits if they have changed
1334          */
1335         if (msg->sm_vcir_ind.vrind_min != spp->sp_min_vci) {
1336                 spp->sp_min_vci =
1337                                 (msg->sm_vcir_ind.vrind_min <
1338                                 SPANS_MIN_VCI ?
1339                                 SPANS_MIN_VCI :
1340                                 msg->sm_vcir_ind.vrind_min);
1341         }
1342         if (msg->sm_vcir_ind.vrind_max != spp->sp_max_vci) {
1343                 spp->sp_max_vci =
1344                                 (msg->sm_vcir_ind.vrind_max >
1345                                 SPANS_MAX_VCI ?
1346                                 SPANS_MAX_VCI :
1347                                 msg->sm_vcir_ind.vrind_max);
1348         }
1349 }
1350
1351
1352 /*
1353  * Process a query request
1354  *
1355  * Called when a query request is received.  Respond with the
1356  * appropriate query response.
1357  *
1358  * Arguments:
1359  *      spp     pointer to SPANS protocol instance block
1360  *      msg     pointer to the VCI range indication message
1361  *
1362  * Returns:
1363  *      none
1364  *
1365  */
1366 static void
1367 spans_query_req(spp, msg)
1368         struct spans    *spp;
1369         spans_msg       *msg;
1370 {
1371         struct spans_vccb       *svp = NULL;
1372         spans_msg               *rsp_msg;
1373
1374         ATM_DEBUG1("spans_query_req: msg=%p\n", msg);
1375
1376         /*
1377          * Ignore an end-to-end query
1378          */
1379         if (msg->sm_query_req.qyreq_type == SPANS_QUERY_END_TO_END) {
1380                 return;
1381         }
1382
1383         /*
1384          * Get memory for a SPANS_QUERY_RSP message.
1385          */
1386         rsp_msg = (spans_msg *) atm_allocate(&spans_msgpool);
1387         if (rsp_msg == NULL)
1388                 return;
1389
1390         /*
1391          * Fill out the response.
1392          */
1393         rsp_msg->sm_vers = SPANS_VERS_1_0;
1394         rsp_msg->sm_type = SPANS_QUERY_RSP;
1395         rsp_msg->sm_query_rsp.qyrsp_conn = msg->sm_query_req.qyreq_conn;
1396         rsp_msg->sm_query_rsp.qyrsp_type = msg->sm_query_req.qyreq_type;
1397         rsp_msg->sm_query_rsp.qyrsp_data = 0;
1398
1399         /*
1400          * Get the state of the requested connection
1401          */
1402         svp = spans_find_conn(spp, &msg->sm_query_req.qyreq_conn);
1403         if (svp) {
1404                 switch(svp->sv_sstate) {
1405                 case SPANS_VC_NULL:
1406                 case SPANS_VC_FREE:
1407                         rsp_msg->sm_query_rsp.qyrsp_state =
1408                                 SPANS_CONN_CLOSED;
1409                         break;
1410                 case SPANS_VC_OPEN:
1411                         rsp_msg->sm_query_rsp.qyrsp_state =
1412                                 SPANS_CONN_OPEN;
1413                         break;
1414                 case SPANS_VC_POPEN:
1415                 case SPANS_VC_R_POPEN:
1416                         rsp_msg->sm_query_rsp.qyrsp_state =
1417                                 SPANS_CONN_OPEN_PEND;
1418                         break;
1419                 case SPANS_VC_CLOSE:
1420                 case SPANS_VC_ABORT:
1421                         rsp_msg->sm_query_rsp.qyrsp_state =
1422                                 SPANS_CONN_CLOSE_PEND;
1423                         break;
1424                 case SPANS_VC_ACTIVE:
1425                 case SPANS_VC_ACT_DOWN:
1426                         /*
1427                          * VCCB is for a PVC (shouldn't happen)
1428                          */
1429                         atm_free(rsp_msg);
1430                         return;
1431                 }
1432         } else {
1433                 /*
1434                  * No VCCB found--connection doesn't exist
1435                  */
1436                 rsp_msg->sm_query_rsp.qyrsp_state = SPANS_CONN_CLOSED;
1437         }
1438
1439         /*
1440          * Send the response and free the message.
1441          */
1442         (void) spans_send_msg(spp, rsp_msg);
1443         atm_free(rsp_msg);
1444 }
1445
1446
1447 /*
1448  * Process a SPANS signalling message
1449  *
1450  * Called when a SPANS message is received.  The message is converted
1451  * into internal format with XDR and decoded by calling the appropriate
1452  * mesage handling routine.  Unrecognized and unexpected messages are
1453  * logged.
1454  *
1455  * Arguments:
1456  *      spp     pointer to SPANS protocol instance block
1457  *      m       pointer to a buffer chain containing the SPANS message
1458  *
1459  * Returns:
1460  *      none
1461  *
1462  */
1463 void
1464 spans_rcv_msg(spp, m)
1465         struct spans    *spp;
1466         KBuffer         *m;
1467 {
1468         XDR             xdrs;
1469         spans_msg       *msg;
1470
1471         /*
1472          * Get storage for the message
1473          */
1474         msg = (spans_msg *)atm_allocate(&spans_msgpool);
1475         if (msg == NULL) {
1476                 return;
1477         }
1478
1479         /*
1480          * Convert the message from network order to internal format
1481          */
1482         xdrmbuf_init(&xdrs, m, XDR_DECODE);
1483         if (!xdr_spans_msg(&xdrs, msg)) {
1484                 log(LOG_ERR, "spans_rcv_msg: XDR decode failed\n");
1485                 spans_dump_buffer(m);
1486                 goto done;
1487         }
1488
1489 #ifdef NOTDEF
1490         /*
1491          * Debug--print some information about the message
1492          */
1493         if (msg->sm_type != SPANS_STAT_REQ &&
1494                         msg->sm_type != SPANS_STAT_IND &&
1495                         msg->sm_type != SPANS_STAT_RSP) {
1496                 printf("spans_rcv_msg: got ");
1497                 spans_print_msg(msg);
1498         }
1499 #endif
1500
1501         /*
1502          * Verify the message sm_vers
1503          */
1504         if (msg->sm_vers != SPANS_VERS_1_0) {
1505                 log(LOG_ERR, "spans: invalid message version 0x%x\n",
1506                                 msg->sm_vers);
1507         }
1508
1509         /*
1510          * Ignore the message if SPANS isn't up yet
1511          */
1512         if (spp->sp_state != SPANS_ACTIVE &&
1513                         (spp->sp_state != SPANS_PROBE ||
1514                         (msg->sm_type != SPANS_STAT_REQ &&
1515                         msg->sm_type != SPANS_STAT_RSP &&
1516                         msg->sm_type != SPANS_STAT_IND))) {
1517                 goto done;
1518         }
1519
1520         /*
1521          * Process the message based on its type
1522          */
1523         switch(msg->sm_type) {
1524         case SPANS_STAT_REQ:
1525                 spans_status_ind(spp, msg);
1526                 break;
1527         case SPANS_STAT_IND:
1528                 spans_status_ind(spp, msg);
1529                 break;
1530         case SPANS_STAT_RSP:
1531                 spans_status_rsp(spp, msg);
1532                 break;
1533         case SPANS_OPEN_REQ:
1534                 spans_open_req(spp, msg);
1535                 break;
1536         case SPANS_OPEN_IND:
1537                 spans_open_req(spp, msg);
1538                 break;
1539         case SPANS_OPEN_RSP:
1540                 spans_open_rsp(spp, msg);
1541                 break;
1542         case SPANS_OPEN_CNF:
1543                 spans_open_rsp(spp, msg);
1544                 break;
1545         case SPANS_CLOSE_REQ:
1546                 spans_close_req(spp, msg);
1547                 break;
1548         case SPANS_CLOSE_IND:
1549                 spans_close_req(spp, msg);
1550                 break;
1551         case SPANS_CLOSE_RSP:
1552                 spans_close_rsp(spp, msg);
1553                 break;
1554         case SPANS_CLOSE_CNF:
1555                 spans_close_rsp(spp, msg);
1556                 break;
1557         case SPANS_RCLOSE_REQ:
1558                 spans_close_req(spp, msg);
1559                 break;
1560         case SPANS_RCLOSE_IND:
1561                 spans_close_req(spp, msg);
1562                 break;
1563         case SPANS_RCLOSE_RSP:
1564                 spans_close_rsp(spp, msg);
1565                 break;
1566         case SPANS_RCLOSE_CNF:
1567                 spans_close_rsp(spp, msg);
1568                 break;
1569         case SPANS_MULTI_REQ:
1570                 spans_multi_req(spp, msg);
1571                 break;
1572         case SPANS_MULTI_IND:
1573                 spans_multi_req(spp, msg);
1574                 break;
1575         case SPANS_MULTI_RSP:
1576                 log(LOG_ERR,
1577                         "spans: unexpected message (multi_rsp)\n");
1578                 break;
1579         case SPANS_MULTI_CNF:
1580                 log(LOG_ERR,
1581                         "spans: unexpected message (multi_conf)\n");
1582                 break;
1583         case SPANS_ADD_REQ:
1584                 spans_add_req(spp, msg);
1585                 break;
1586         case SPANS_ADD_IND:
1587                 spans_add_req(spp, msg);
1588                 break;
1589         case SPANS_ADD_RSP:
1590                 log(LOG_ERR,
1591                         "spans: unexpected message (add_rsp)\n");
1592                 break;
1593         case SPANS_ADD_CNF:
1594                 log(LOG_ERR, "spans: unexpected message (add_conf)\n");
1595                 break;
1596         case SPANS_JOIN_REQ:
1597                 spans_join_req(spp, msg);
1598                 break;
1599         case SPANS_JOIN_CNF:
1600                 log(LOG_ERR, "spans: unexpected message (join_conf)\n");
1601                 break;
1602         case SPANS_LEAVE_REQ:
1603                 spans_leave_req(spp, msg);
1604                 break;
1605         case SPANS_LEAVE_CNF:
1606                 log(LOG_ERR,
1607                         "spans: unexpected message (leave_conf)\n");
1608                 break;
1609         case SPANS_VCIR_IND:
1610                 spans_vcir_ind(spp, msg);
1611                 break;
1612         case SPANS_QUERY_REQ:
1613                 spans_query_req(spp, msg);
1614                 break;
1615         case SPANS_QUERY_RSP:
1616                 log(LOG_ERR,
1617                         "spans: unexpected message (query_rsp)\n");
1618                 break;
1619         default:
1620                 log(LOG_ERR, "spans: unknown SPANS message type %d\n",
1621                                 msg->sm_type);
1622         }
1623
1624 done:
1625         /*
1626          * Free the incoming message (both buffer and internal format) if
1627          * necessary.
1628          */
1629         if (msg)
1630                 atm_free(msg);
1631         if (m)
1632                 KB_FREEALL(m);
1633 }