kernel tree reorganization stage 1: Major cvs repository work (not logged as
[dragonfly.git] / sys / netproto / atm / spans / spans_subr.c
CommitLineData
984263bc
MD
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 $
d2438d69 27 * @(#) $DragonFly: src/sys/netproto/atm/spans/spans_subr.c,v 1.4 2003/08/07 21:54:34 dillon Exp $
984263bc
MD
28 */
29
30/*
31 * SPANS Signalling Manager
32 * ---------------------------
33 *
34 * SPANS-related subroutines.
35 *
36 */
37
d2438d69 38#include <netproto/atm/kern_include.h>
984263bc
MD
39
40#include "spans_xdr.h"
1f2de5d4 41#include "spans_var.h"
984263bc 42
984263bc
MD
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 */
63int
64spans_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 */
258int
259spans_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 */
351int
352spans_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 */
427void
428spans_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}