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