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