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