Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / netproto / atm / spans / spans_subr.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_subr.c,v 1.4 1999/08/28 00:48:52 peter Exp $
27  *
28  */
29
30 /*
31  * SPANS Signalling Manager
32  * ---------------------------
33  *
34  * SPANS-related subroutines.
35  *
36  */
37
38 #include <netatm/kern_include.h>
39
40 #include "spans_xdr.h"
41 #include <netatm/spans/spans_var.h>
42
43 #ifndef lint
44 __RCSID("@(#) $FreeBSD: src/sys/netatm/spans/spans_subr.c,v 1.4 1999/08/28 00:48:52 peter Exp $");
45 #endif
46
47
48 /*
49  * Open a SPANS VCC
50  *
51  * Called when a user wants to open a VC.  This function will construct
52  * a VCCB, create the stack requested by the user, and, if we are
53  * opening an SVC, start the SPANS signalling message exchange.  The
54  * user will have to wait for a notify event to be sure the SVC is fully
55  * open.
56  *
57  * Must be called at splnet.
58  *
59  * Arguments:
60  *      spp     pointer to SPANS protocol instance
61  *      acp     pointer to PVC's connection parameters
62  *
63  * Returns:
64  *      0       VCC creation successful
65  *      errno   VCC setup failed - reason indicated
66  *
67  */
68 int
69 spans_open_vcc(spp, cvp)
70         struct spans    *spp;
71         Atm_connvc      *cvp;
72
73 {
74         struct atm_pif          *pip = spp->sp_pif;
75         struct spans_vccb       *svp;
76         Atm_addr_pvc            *pvp;
77         spans_aal               aal;
78         int                     err, pvc, vpi, vci;
79
80         ATM_DEBUG2("spans_open_vcc: spp=%p, cvp=%p\n", spp, cvp);
81
82         /*
83          * Validate user parameters. AAL and encapsulation are
84          * checked by the connection manager.
85          */
86
87         /*
88          * Check called party address(es)
89          */
90         if (cvp->cvc_attr.called.tag != T_ATM_PRESENT ||
91                         cvp->cvc_attr.called.addr.address_format ==
92                                 T_ATM_ABSENT ||
93                         cvp->cvc_attr.called.subaddr.address_format !=
94                                 T_ATM_ABSENT) {
95                 return(EINVAL);
96         }
97         switch (cvp->cvc_attr.called.addr.address_format) {
98         case T_ATM_PVC_ADDR:
99                 /*
100                  * Make sure VPI/VCI is valid
101                  */
102                 pvc = 1;
103                 pvp = (Atm_addr_pvc *)cvp->cvc_attr.called.addr.address;
104                 vpi = ATM_PVC_GET_VPI(pvp);
105                 vci = ATM_PVC_GET_VCI(pvp);
106                 if ((vpi > pip->pif_maxvpi) ||
107                                 (vci == 0) ||
108                                 (vci > pip->pif_maxvci)) {
109                         return(ERANGE);
110                 }
111
112                 /*
113                  * Make sure VPI/VCI is not already in use
114                  */
115                 if (spans_find_vpvc(spp, vpi, vci, 0)) {
116                         return(EADDRINUSE);
117                 }
118                 ATM_DEBUG2("spans_open_vcc: VPI.VCI=%d.%d\n",
119                                 vpi, vci);
120                 break;
121
122         case T_ATM_SPANS_ADDR:
123                 pvc = 0;
124                 vpi = vci = 0;
125
126                 /*
127                  * Check signalling state
128                  */
129                 if (spp->sp_state != SPANS_ACTIVE) {
130                         return(ENETDOWN);
131                 }
132
133                 /*
134                  *Check destination address length
135                  */
136                 if (cvp->cvc_attr.called.addr.address_length !=
137                                 sizeof(spans_addr)) {
138                         return(EINVAL);
139                 }
140                 break;
141
142         default:
143                 return(EINVAL);
144         }
145
146         /*
147          * Check that this is for the same interface SPANS uses
148          */
149         if (!cvp->cvc_attr.nif ||
150                         cvp->cvc_attr.nif->nif_pif != spp->sp_pif) {
151                 return(EINVAL);
152         }
153
154         /*
155          * Check AAL
156          */
157         if (!spans_get_spans_aal(cvp->cvc_attr.aal.type, &aal)) {
158                 return(EINVAL);
159         }
160
161 #ifdef NOTDEF
162         /*
163          * Check encapsulation
164          */
165         /* XXX -- How do we check encapsulation? */
166         if (cvp->ac_encaps != ATM_ENC_NULL) {
167                 return(EINVAL);
168         }
169 #endif
170
171         /*
172          * Allocate control block for VCC
173          */
174         svp = (struct spans_vccb *)atm_allocate(&spans_vcpool);
175         if (svp == NULL) {
176                 return(ENOMEM);
177         }
178
179         /*
180          * Fill in VCCB
181          */
182         if (pvc) {
183                 svp->sv_type = VCC_PVC | VCC_IN | VCC_OUT;
184                 svp->sv_vpi = vpi;
185                 svp->sv_vci = vci;
186                 svp->sv_sstate = (spp->sp_state == SPANS_ACTIVE ?
187                                 SPANS_VC_ACTIVE : SPANS_VC_ACT_DOWN);
188                 svp->sv_ustate = VCCU_OPEN;
189         } else {
190                 svp->sv_type = VCC_SVC | VCC_OUT;
191                 spans_addr_copy(cvp->cvc_attr.called.addr.address,
192                                 &svp->sv_conn.con_dst);
193                 spans_addr_copy(spp->sp_addr.address,
194                                 &svp->sv_conn.con_src);
195                 svp->sv_conn.con_dsap = SPANS_SAP_IP;
196                 svp->sv_conn.con_ssap = spans_ephemeral_sap(spp);
197                 svp->sv_sstate = SPANS_VC_POPEN;
198                 svp->sv_ustate = VCCU_POPEN;
199         }
200         svp->sv_proto = ATM_SIG_SPANS;
201         svp->sv_pif = spp->sp_pif;
202         svp->sv_nif = cvp->cvc_attr.nif;
203         svp->sv_connvc = cvp;
204         svp->sv_spans_aal = aal;
205         svp->sv_tstamp = time_second;
206
207         /*
208          * Put VCCB on SPANS queue
209          */
210         ENQUEUE(svp, struct spans_vccb, sv_sigelem, spp->sp_vccq);
211
212         /*
213          * Link VCCB to VCC connection block
214          */
215         cvp->cvc_vcc = (struct vccb *) svp;
216
217         /*
218          * Start the SPANS message exchange if this is an SVC
219          */
220         if (!pvc) {
221                 svp->sv_retry = 0;
222                 svp->sv_spans_qos.rsc_peak = 1;
223                 svp->sv_spans_qos.rsc_mean = 1;
224                 svp->sv_spans_qos.rsc_burst = 1;
225                 err = spans_send_open_req(spp, svp);
226                 if (err) {
227                         /*
228                          * On error, delete the VCCB
229                          */
230                         DEQUEUE(svp, struct spans_vccb, sv_sigelem,
231                                         spp->sp_vccq);
232                         cvp->cvc_vcc = (struct vccb *)0;
233                         atm_free((caddr_t)svp);
234                         return(err);
235                 } else {
236                         /*
237                          * VCCB is opening--set the retransmit timer
238                          */
239                         SPANS_VC_TIMER((struct vccb *) svp, SV_TIMEOUT);
240                 }
241         }
242
243         return(0);
244 }
245
246
247 /*
248  * Close a SPANS VCC
249  *
250  * Called when a user wants to close a VCC.  This function will clean
251  * up the VCCB and, for an SVC, send a close request.
252  *
253  * Must be called at splnet.
254  *
255  * Arguments:
256  *      spp     pointer to SPANS protocol instance
257  *      svp     pointer to VCCB for the VCC to be closed
258  *
259  * Returns:
260  *      0       VCC is now closed
261  *      errno   error encountered
262  */
263 int
264 spans_close_vcc(spp, svp, force)
265         struct spans            *spp;
266         struct spans_vccb       *svp;
267         int                     force;
268
269 {
270         int             err = 0;
271
272         ATM_DEBUG2("spans_close_vcc: svp=%p, state=%d\n", svp,
273                         svp->sv_sstate);
274
275         /*
276          * Check that this is for the same interface SPANS uses
277          */
278         if (svp->sv_pif != spp->sp_pif) {
279                 return (EINVAL);
280         }
281
282         /*
283          * Kill any possible timer
284          */
285         SPANS_VC_CANCEL((struct vccb *) svp);
286
287         /*
288          * Mark the close time.
289          */
290         svp->sv_tstamp = time_second;
291
292         /*
293          * Process based on the connection type
294          */
295         if (svp->sv_type & VCC_PVC) {
296                 svp->sv_sstate = SPANS_VC_FREE;
297                 svp->sv_ustate = VCCU_CLOSED;
298         } else if (svp->sv_type & VCC_SVC) {
299                 /*
300                  * Update VCCB states
301                  */
302                 svp->sv_ustate = VCCU_CLOSED;
303
304                 /*
305                  * Send the appropriate SPANS close message
306                  */
307                 switch (svp->sv_sstate) {
308                 case SPANS_VC_R_POPEN:
309                         err = spans_send_open_rsp(spp, svp, SPANS_FAIL);
310                         svp->sv_sstate = SPANS_VC_FREE;
311                         break;
312                 case SPANS_VC_OPEN:
313                 case SPANS_VC_POPEN:
314                 case SPANS_VC_ABORT:
315                         svp->sv_retry = 0;
316                         err = spans_send_close_req(spp, svp);
317                         if (force) {
318                                 svp->sv_sstate = SPANS_VC_FREE;
319                         } else {
320                                 svp->sv_sstate = SPANS_VC_CLOSE;
321                                 SPANS_VC_TIMER((struct vccb *) svp,
322                                                 SV_TIMEOUT);
323                         }
324                         break;
325                 case SPANS_VC_CLOSE:
326                         if (force) {
327                                 svp->sv_sstate = SPANS_VC_FREE;
328                         }
329                         break;
330                 }
331         }
332
333         /*
334          * Wait for user to free resources
335          */
336         return(err);
337 }
338
339
340 /*
341  * Clear a SPANS VCC
342  *
343  * Called when the signalling manager wants to close a VCC immediately.
344  * This function will clean up the VCCB and notify the owner.
345  *
346  * Must be called at splnet.
347  *
348  * Arguments:
349  *      spp     pointer to SPANS protocol instance
350  *      svp     pointer to VCCB for the VCC to be closed
351  *
352  * Returns:
353  *      0       VCC is now closed
354  *      errno   error encountered
355  */
356 int
357 spans_clear_vcc(spp, svp)
358         struct spans            *spp;
359         struct spans_vccb       *svp;
360
361 {
362         u_char  outstate;
363
364         ATM_DEBUG2("spans_clear_vcc: svp=%p, state=%d\n", svp,
365                         svp->sv_sstate);
366
367         /*
368          * Check that this is for the same interface SPANS uses
369          */
370         if (svp->sv_pif != spp->sp_pif) {
371                 return (EINVAL);
372         }
373
374         /*
375          * Kill any possible timer
376          */
377         SPANS_VC_CANCEL((struct vccb *) svp);
378
379         /*
380          * Mark the close time
381          */
382         svp->sv_tstamp = time_second;
383
384         /*
385          * Mark the VCCB closed
386          */
387         outstate = svp->sv_sstate;
388         svp->sv_sstate = SPANS_VC_FREE;
389         svp->sv_ustate = VCCU_CLOSED;
390
391         /*
392          * Notify the user if old state indicates.
393          */
394         switch (outstate) {
395         case SPANS_VC_ACTIVE:
396         case SPANS_VC_ACT_DOWN:
397         case SPANS_VC_POPEN:
398         case SPANS_VC_OPEN:
399         case SPANS_VC_CLOSE:
400         case SPANS_VC_ABORT:
401                 /* XXX -- set cause */
402                 atm_cm_cleared(svp->sv_connvc);
403                 break;
404         case SPANS_VC_NULL:
405         case SPANS_VC_R_POPEN:
406         case SPANS_VC_FREE:
407                 break;
408         }
409
410         /*
411          * Wait for user to free resources
412          */
413         return(0);
414 }
415
416
417 /*
418  * Reset the switch state
419  *
420  * Called when the switch or host at the far end of the ATM link has
421  * gone away.  This can be deteched either by a number of SPANS_STAT_REQ
422  * messages going unanswered or by the host epoch changing in a SPANS
423  * SPANS_STAT_IND or SPANS_STAT_REQ message.
424  *
425  * Arguments:
426  *      spp     pointer to SPANS protocol instance
427  *
428  * Returns:
429  *      none
430  *
431  */
432 void
433 spans_switch_reset(spp, cause)
434         struct spans    *spp;
435         int             cause;
436
437 {
438         int             s;
439         struct vccb     *vcp, *vnext;
440
441         ATM_DEBUG2("spans_switch_reset: spp=%p, cause=%d\n",
442                         spp, cause);
443
444         /*
445          * Log the event
446          */
447         log(LOG_INFO, "spans: signalling %s on interface %s%d\n",
448                         (cause == SPANS_UNI_DOWN ? "down" : "up"),
449                         spp->sp_pif->pif_name,
450                         spp->sp_pif->pif_unit);
451
452         /*
453          * Terminate all of our VCCs
454          */
455         s = splnet();
456         for (vcp = Q_HEAD(spp->sp_vccq, struct vccb); vcp;
457                         vcp = vnext) {
458
459                 u_char  outstate;
460
461                 vnext = Q_NEXT(vcp, struct vccb, vc_sigelem);
462
463                 if (vcp->vc_type & VCC_SVC) {
464                         /*
465                          * Close the SVC and notify the owner
466                          */
467                         outstate = vcp->vc_sstate;
468                         SPANS_VC_CANCEL((struct vccb *) vcp);
469                         vcp->vc_ustate = VCCU_CLOSED;
470                         vcp->vc_sstate = SPANS_VC_FREE;
471                         if (outstate == SPANS_VC_OPEN ||
472                                         outstate == SPANS_VC_POPEN) {
473                                 /* XXX -- set cause */
474                                 atm_cm_cleared(vcp->vc_connvc);
475                         }
476                 } else if (vcp->vc_type & VCC_PVC) {
477                         /*
478                          * Note new state
479                          */
480                         switch(cause) {
481                         case SPANS_UNI_DOWN:
482                                 vcp->vc_sstate = SPANS_VC_ACT_DOWN;
483                                 break;
484                         case SPANS_UNI_UP:
485                                 vcp->vc_sstate = SPANS_VC_ACTIVE;
486                                 break;
487                         }
488                 } else {
489                         log(LOG_ERR, "spans: invalid VCC type: vccb=%p, type=%d\n",
490                                         vcp, vcp->vc_type);
491                 }
492         }
493         (void) splx(s);
494 }