Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / netproto / atm / spans / spans_proto.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_proto.c,v 1.4 1999/08/28 00:48:51 peter Exp $
27  *
28  */
29
30 /*
31  * SPANS Signalling Manager
32  * ---------------------------
33  *
34  * SPANS protocol processing module.
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_proto.c,v 1.4 1999/08/28 00:48:51 peter Exp $");
45 #endif
46
47 /*
48  * Internal functions
49  */
50 caddr_t spans_getname __P((void *));
51 void    spans_connected __P((void *));
52 void    spans_cleared __P((void *, struct t_atm_cause *));
53 void    spans_cpcs_data __P((void *, KBuffer *));
54
55
56 /*
57  * ATM endpoint for SPANS signalling channel
58  */
59 static Atm_endpoint     spans_endpt = {
60         NULL,                   /* ep_next */
61         ENDPT_SPANS_SIG,        /* ep_id */
62         NULL,                   /* ep_ioctl */
63         spans_getname,          /* ep_getname */
64         spans_connected,        /* ep_connected */
65         spans_cleared,          /* ep_cleared */
66         NULL,                   /* ep_incoming */
67         NULL,                   /* ep_addparty */
68         NULL,                   /* ep_dropparty */
69         NULL,                   /* ep_cpcs_ctl */
70         spans_cpcs_data,        /* ep_cpcs_data */
71         NULL,                   /* ep_saal_ctl */
72         NULL,                   /* ep_saal_data */
73         NULL,                   /* ep_sscop_ctl */
74         NULL                    /* ep_sscop_data */
75 };
76
77
78 /*
79  * ATM connection attributes for UNI signalling channel
80  */
81 static Atm_attributes   spans_attr = {
82         NULL,                           /* nif */
83         CMAPI_CPCS,                     /* api */
84         0,                              /* api_init */
85         0,                              /* headin */
86         0,                              /* headout */
87         {                               /* aal */
88                 T_ATM_PRESENT,          /* aal.tag */
89                 ATM_AAL3_4              /* aal.aal_type */
90         },
91         {                               /* traffic */
92                 T_ATM_PRESENT,          /* traffic.tag */
93                 {                       /* traffic.v */
94                         {               /* traffic.v.forward */
95                                 T_ATM_ABSENT,   /* PCR_high */
96                                 0,              /* PCR_all */
97                                 T_ATM_ABSENT,   /* SCR_high */
98                                 T_ATM_ABSENT,   /* SCR_all */
99                                 T_ATM_ABSENT,   /* MBS_high */
100                                 T_ATM_ABSENT,   /* MBS_all */
101                                 T_NO,           /* tagging */
102                         },
103                         {               /* traffic.v.backward */
104                                 T_ATM_ABSENT,   /* PCR_high */
105                                 0,              /* PCR_all */
106                                 T_ATM_ABSENT,   /* SCR_high */
107                                 T_ATM_ABSENT,   /* SCR_all */
108                                 T_ATM_ABSENT,   /* MBS_high */
109                                 T_ATM_ABSENT,   /* MBS_all */
110                                 T_NO,           /* tagging */
111                         },
112                         T_YES,          /* best_effort */
113                 }
114         },
115         {                               /* bearer */
116                 T_ATM_PRESENT,          /* bearer.tag */
117                 {                       /* bearer.v */
118                         T_ATM_CLASS_X,          /* class */
119                         T_ATM_NULL,             /* traffic_type */
120                         T_ATM_NO_END_TO_END,    /* timing_req */
121                         T_NO,                   /* clipping */
122                         T_ATM_1_TO_1,           /* conn_conf */
123                 }
124         },
125         {                               /* bhli */
126                 T_ATM_ABSENT,           /* bhli.tag */
127         },
128         {                               /* blli */
129                 T_ATM_ABSENT,           /* blli.tag_l2 */
130                 T_ATM_ABSENT,           /* blli.tag_l3 */
131         },
132         {                               /* llc */
133                 T_ATM_ABSENT,           /* llc.tag */
134         },
135         {                               /* called */
136                 T_ATM_PRESENT,          /* called.tag */
137         },
138         {                               /* calling */
139                 T_ATM_ABSENT,           /* calling.tag */
140         },
141         {                               /* qos */
142                 T_ATM_PRESENT,          /* qos.tag */
143                 {                       /* qos.v */
144                         T_ATM_NETWORK_CODING,   /* coding_standard */
145                         {                       /* qos.v.forward */
146                                 T_ATM_QOS_CLASS_0,      /* class */
147                         },
148                         {                       /* qos.v.backward */
149                                 T_ATM_QOS_CLASS_0,      /* class */
150                         }
151                 }
152         },
153         {                               /* transit */
154                 T_ATM_ABSENT,           /* transit.tag */
155         },
156         {                               /* cause */
157                 T_ATM_ABSENT,           /* cause.tag */
158         }
159 };
160
161
162 /*
163  * SPANS cause structre
164  */
165 struct t_atm_cause spans_cause = {
166         T_ATM_ITU_CODING,               /* coding_standard */
167         T_ATM_LOC_USER,                 /* location */
168         T_ATM_CAUSE_UNSPECIFIED_NORMAL, /* cause_value */
169         { 0, 0, 0, 0 }                  /* diagnostics */
170 };
171
172
173 /*
174  * Process a SPANS timeout
175  *
176  * Called when a previously scheduled spans control block timer expires.
177  * Processing will based on the current SPANS state.
178  *
179  * Called at splnet.
180  *
181  * Arguments:
182  *      tip     pointer to spans timer control block
183  *
184  * Returns:
185  *      none
186  *
187  */
188 void
189 spans_timer(tip)
190         struct atm_time *tip;
191 {
192         struct spans    *spp;
193         spans_msg       *msg;
194         Atm_addr_pvc    *pvcp;
195         int             err;
196
197         /*
198          * Back-off to SPANS control block
199          */
200         spp = (struct spans *)
201                 ((caddr_t)tip - (int)(&((struct spans *)0)->sp_time));
202
203         ATM_DEBUG2("spans_timer: spp=%p,state=%d\n",
204                         spp, spp->sp_state);
205
206         /*
207          * Process timeout based on protocol state
208          */
209         switch (spp->sp_state) {
210
211         case SPANS_INIT:
212
213                 /*
214                  * Open signalling channel
215                  */
216                 spans_attr.nif = spp->sp_pif->pif_nif;
217
218                 spans_attr.aal.v.aal4.forward_max_SDU_size =
219                                 ATM_NIF_MTU;
220                 spans_attr.aal.v.aal4.backward_max_SDU_size =
221                                 ATM_NIF_MTU;
222                 spans_attr.aal.v.aal4.SSCS_type =
223                                 T_ATM_SSCS_SSCOP_UNREL;
224                 spans_attr.aal.v.aal4.mid_low = 0;
225                 spans_attr.aal.v.aal4.mid_high = 0;
226
227                 spans_attr.called.tag = T_ATM_PRESENT;
228                 spans_attr.called.addr.address_format = T_ATM_PVC_ADDR;
229                 spans_attr.called.addr.address_length =
230                         sizeof(Atm_addr_pvc);
231                 pvcp = (Atm_addr_pvc *)spans_attr.called.addr.address;
232                 ATM_PVC_SET_VPI(pvcp, SPANS_SIG_VPI);
233                 ATM_PVC_SET_VCI(pvcp, SPANS_SIG_VCI);
234                 spans_attr.called.subaddr.address_format = T_ATM_ABSENT;
235                 spans_attr.called.subaddr.address_length = 0;
236
237                 spans_attr.traffic.v.forward.PCR_all_traffic =
238                                 spp->sp_pif->pif_pcr;
239                 spans_attr.traffic.v.backward.PCR_all_traffic =
240                                 spp->sp_pif->pif_pcr;
241
242                 err = atm_cm_connect(&spans_endpt, spp, &spans_attr,
243                                 &spp->sp_conn);
244                 if (err) {
245                         log(LOG_CRIT, "spans: signalling channel setup failed\n");
246                         return;
247                 }
248
249                 /*
250                  * Signalling channel open, start probing
251                  */
252                 spp->sp_state = SPANS_PROBE;
253
254                 /* FALLTHRU */
255
256         case SPANS_PROBE:
257         case SPANS_ACTIVE:
258
259                 /*
260                  * Send out SPANS_STAT_REQ message
261                  */
262                 msg = (spans_msg *)atm_allocate(&spans_msgpool);
263                 if (msg == NULL) {
264                         /* Retry later if no memory */
265                         SPANS_TIMER(spp, SPANS_PROBE_ERR_WAIT);
266                         break;
267                 }
268                 msg->sm_vers = SPANS_VERS_1_0;
269                 msg->sm_type = SPANS_STAT_REQ;
270                 msg->sm_stat_req.streq_es_epoch = spp->sp_h_epoch;
271                 if (spans_send_msg(spp, msg)) {
272                         /* Retry later if send fails */
273                         SPANS_TIMER(spp, SPANS_PROBE_ERR_WAIT);
274                         atm_free(msg);
275                         break;
276                 }
277                 atm_free(msg);
278                 spp->sp_probe_ct++;
279
280                 /*
281                  * Check whether we're getting an answer to our probes
282                  */
283                 if (spp->sp_state == SPANS_ACTIVE &&
284                                 spp->sp_probe_ct > SPANS_PROBE_THRESH) {
285                         /*
286                          * Interface is down, notify VCC owners
287                          */
288                         spans_switch_reset(spp, SPANS_UNI_DOWN);
289
290                         /*
291                          * Set new state and increment host epoch so
292                          * switch knows we reset everyting.
293                          */
294                         spp->sp_state = SPANS_PROBE;
295                         spp->sp_h_epoch++;
296                         spp->sp_s_epoch = 0;
297                 }
298
299                 /*
300                  * Keep sending status requests
301                  */
302                 SPANS_TIMER(spp, SPANS_PROBE_INTERVAL);
303
304                 break;
305
306         case SPANS_DETACH:
307                 /*
308                  * Try to terminate the SPANS signalling PVC
309                  */
310                 err = atm_cm_release(spp->sp_conn, &spans_cause);
311                 if (err) {
312                         log(LOG_ERR, "spans: can't close signalling channel\n");
313                 }
314                 break;
315
316         default:
317                 log(LOG_ERR, "spans: timer state: spp=%p, state=%d\n",
318                         spp, spp->sp_state);
319         }
320 }
321
322
323 /*
324  * Process a SPANS VCC timeout
325  *
326  * Called when a previously scheduled SPANS VCCB timer expires.
327  * Processing will based on the current VCC state.
328  *
329  * Called at splnet.
330  *
331  * Arguments:
332  *      tip     pointer to vccb timer control block
333  *
334  * Returns:
335  *      none
336  *
337  */
338 void
339 spans_vctimer(tip)
340         struct atm_time *tip;
341 {
342         int                     err;
343         struct spans            *spp;
344         struct spans_vccb       *svp;
345
346         /*
347          * Get VCCB and SPANS control block addresses
348          */
349         svp = (struct spans_vccb *) ((caddr_t)tip -
350                         (int)(&((struct vccb *)0)->vc_time));
351         spp = (struct spans *)svp->sv_pif->pif_siginst;
352
353         ATM_DEBUG3("spans_vctimer: svp=%p, sstate=%d, ustate=%d\n",
354                         svp, svp->sv_sstate, svp->sv_ustate);
355
356         /*
357          * Process timeout based on protocol state
358          */
359         switch (svp->sv_sstate) {
360
361         case SPANS_VC_ABORT:
362                 /*
363                  * Kill the VCCB and notify the owner
364                  */
365                 err = spans_clear_vcc(spp, svp);
366                 break;
367
368         case SPANS_VC_FREE:
369                 /*
370                  * Free VCCB storage
371                  */
372                 svp->sv_ustate = VCCU_CLOSED;
373                 svp->sv_sstate = SPANS_VC_FREE;
374                 spans_free((struct vccb *)svp);
375                 break;
376
377         case SPANS_VC_POPEN:
378                 /*
379                  * Issued open request, but didn't get response.
380                  */
381                 if (svp->sv_retry < SV_MAX_RETRY) {
382                         /*
383                          * Retransmit the open request
384                          */
385                         err = spans_send_open_req(spp, svp);
386                         svp->sv_retry++;
387                         SPANS_VC_TIMER((struct vccb *) svp, SV_TIMEOUT);
388                 } else {
389                         /*
390                          * Retry limit exceeded--report the open failed
391                          */
392                         svp->sv_ustate = VCCU_CLOSED;
393                         svp->sv_sstate = SPANS_VC_FREE;
394                         svp->sv_connvc->cvc_attr.cause.tag =
395                                         T_ATM_PRESENT;
396                         svp->sv_connvc->cvc_attr.cause.v.coding_standard =
397                                         T_ATM_ITU_CODING;
398                         svp->sv_connvc->cvc_attr.cause.v.location =
399                                         T_ATM_LOC_USER;
400                         svp->sv_connvc->cvc_attr.cause.v.cause_value =
401                                         T_ATM_CAUSE_NO_USER_RESPONDING;
402                         KM_ZERO(svp->sv_connvc->cvc_attr.cause.v.diagnostics,
403                                         sizeof(svp->sv_connvc->cvc_attr.cause.v.diagnostics));
404                         atm_cm_cleared(svp->sv_connvc);
405                 }
406                 break;
407
408         case SPANS_VC_CLOSE:
409                 /*
410                  * Issued close request, but didn't get response.
411                  */
412                 if (svp->sv_retry < SV_MAX_RETRY) {
413                         /*
414                          * Retransmit the close request
415                          */
416                         err = spans_send_close_req(spp, svp);
417                         svp->sv_retry++;
418                         SPANS_VC_TIMER((struct vccb *) svp, SV_TIMEOUT);
419                 } else {
420                         /*
421                          * Retry limit exceeded--just finish the close
422                          */
423                         svp->sv_sstate = SPANS_VC_FREE;
424                         svp->sv_connvc->cvc_attr.cause.tag = T_ATM_PRESENT;
425                         svp->sv_connvc->cvc_attr.cause.v.coding_standard =
426                                         T_ATM_ITU_CODING;
427                         svp->sv_connvc->cvc_attr.cause.v.location =
428                                         T_ATM_LOC_USER;
429                         svp->sv_connvc->cvc_attr.cause.v.cause_value =
430                                         T_ATM_CAUSE_NO_USER_RESPONDING;
431                         KM_ZERO(svp->sv_connvc->cvc_attr.cause.v.diagnostics,
432                                         sizeof(svp->sv_connvc->cvc_attr.cause.v.diagnostics));
433                         atm_cm_cleared(svp->sv_connvc);
434                 }
435                 break;
436
437         case SPANS_VC_ACTIVE:
438         case SPANS_VC_ACT_DOWN:
439                 /*
440                  * Shouldn't happen
441                  */
442                 log(LOG_ERR, "spans_vctimer: unexpected state %d\n",
443                                 svp->sv_sstate);
444                 break;
445
446         default:
447                 log(LOG_ERR, "spans: vctimer state: svp=%p, sstate=%d\n",
448                                 svp, svp->sv_sstate);
449         }
450 }
451
452
453 /*
454  * SPANS name routine
455  *
456  * Arguments:
457  *      tok     SPANS signalling channel token (ignored)
458  *
459  * Returns:
460  *      pointer to a string identifying the SPANS signalling manager
461  *
462  */
463 caddr_t
464 spans_getname(tok)
465         void            *tok;
466 {
467         return("SPANS");
468 }
469
470
471 /*
472  * Process a VCC connection notification
473  *
474  * Should never be called
475  *
476  * Arguments:
477  *      tok     user's connection token (SPANS protocol block)
478  *
479  * Returns:
480  *      none
481  *
482  */
483 void
484 spans_connected(tok)
485         void            *tok;
486 {
487         struct spans            *spp = (struct spans *)tok;
488
489         ATM_DEBUG2("spans_connected: spp=%p,state=%d\n",
490                         spp, spp->sp_state);
491
492         /*
493          * Connected routine shouldn't ever get called for a PVC
494          */
495         log(LOG_ERR, "spans: connected function called, tok=%p\n", spp);
496 }
497
498
499 /*
500  * Process a VCC close notification
501  *
502  * Called when the SPANS signalling channel is closed
503  *
504  * Arguments:
505  *      tok     user's connection token (spans protocol block)
506  *      cp      pointer to cause structure
507  *
508  * Returns:
509  *      none
510  *
511  */
512 void
513 spans_cleared(tok, cp)
514         void                    *tok;
515         struct t_atm_cause      *cp;
516 {
517         struct spans    *spp = (struct spans *)tok;
518
519         /*
520          * VCC has been closed.
521          */
522         log(LOG_ERR, "spans: signalling channel closed\n");
523         SPANS_CANCEL(spp);
524         spp->sp_conn = 0;
525 }
526
527
528 /*
529  * SPANS CPCS data handler
530  *
531  * This is the module which receives data on the SPANS signalling
532  * channel.  Processing is based on the indication received from the
533  * AAL and the protocol state.
534  *
535  * Arguments:
536  *      tok     session token (pointer to spans protocol control block)
537  *      m       pointer to buffer with data
538  *
539  * Returns:
540  *      none
541  *
542  */
543 void
544 spans_cpcs_data(tok, m)
545         void    *tok;
546         KBuffer *m;
547 {
548         struct spans    *spp = tok;
549
550         ATM_DEBUG3("spans_cpcs_data: spp=%p,state=%d,m=%p,\n",
551                         spp, spp->sp_state, m);
552
553         /*
554          * Process data
555          */
556         spans_rcv_msg(spp, m);
557 }