Beginnings of support for L2CC
[mpls-ldp-portable.git] / ldp / ldp_state_funcs.c
blob2e51255b50b4b3ac78d1f01d62674ad30d651690
2 /*
3 * Copyright (C) James R. Leu 2000
4 * jleu@mindspring.com
6 * This software is covered under the LGPL, for more
7 * info check out http://www.gnu.org/copyleft/lgpl.html
8 */
10 #include <sys/socket.h>
11 #include "ldp_struct.h"
12 #include "ldp_global.h"
13 #include "ldp_session.h"
14 #include "ldp_entity.h"
15 #include "ldp_fec.h"
16 #include "ldp_adj.h"
17 #include "ldp_attr.h"
18 #include "ldp_mesg.h"
19 #include "ldp_hello.h"
20 #include "ldp_init.h"
21 #include "ldp_label_rel_with.h"
22 #include "ldp_label_mapping.h"
23 #include "ldp_label_request.h"
24 #include "ldp_addr.h"
25 #include "ldp_keepalive.h"
26 #include "ldp_label_request.h"
27 #include "ldp_label_mapping.h"
28 #include "ldp_notif.h"
29 #include "ldp_label_abort.h"
30 #include "ldp_inet_addr.h"
32 #include "mpls_assert.h"
33 #include "mpls_tree_impl.h"
34 #include "mpls_trace_impl.h"
35 #include "mpls_socket_impl.h"
37 mpls_return_enum ldp_state_new_adjacency(ldp_global * g, ldp_session * s,
38 ldp_adj * a, ldp_entity * e, uint32_t event, ldp_mesg * msg, mpls_dest * from)
40 mpls_inet_addr traddr, lsraddr, *addr;
41 ldp_adj *local_a = NULL;
42 int labelspace;
43 int hellotime;
44 int request = 0;
45 int target = 0;
46 uint32_t csn = 0;
47 mpls_return_enum retval = MPLS_FAILURE;
49 MPLS_ASSERT(msg && e);
51 LDP_ENTER(g->user_data, "ldp_state_new_adjacency");
53 ldp_mesg_hdr_get_labelspace(msg, &labelspace);
54 ldp_mesg_hdr_get_lsraddr(msg, &lsraddr);
55 ldp_mesg_hello_get_hellotime(msg, &hellotime);
56 ldp_mesg_hello_get_request(msg, &request);
57 ldp_mesg_hello_get_targeted(msg, &target);
58 ldp_mesg_hello_get_csn(msg, &csn);
60 if (ldp_mesg_hello_get_traddr(msg, &traddr) == MPLS_FAILURE) {
61 addr = NULL;
62 } else {
63 addr = &traddr;
66 e->mesg_rx++;
68 if ((local_a = ldp_adj_create(&from->addr, &lsraddr, labelspace,
69 hellotime, addr, csn)) == NULL) {
70 goto ldp_state_new_adjacency_end;
72 ldp_entity_add_adj(e, local_a);
73 _ldp_global_add_adj(g, local_a);
74 if (ldp_hello_process(g, local_a, e, hellotime, csn, addr, target,
75 request) != MPLS_SUCCESS) {
76 /* this can fail if we could not create an active session, or
77 * we're getting errored hellos,
78 * if this fails then undo the e<->a linking (which will delete a) */
79 ldp_entity_del_adj(e, local_a);
80 _ldp_global_del_adj(g, local_a);
81 } else if (ldp_adj_startup(g, local_a, request) != MPLS_SUCCESS) {
82 /* the only way this fail is if a timer could not be created
83 * if this fails then undo the e<->a linking (which will delete a) */
84 ldp_entity_del_adj(e, local_a);
85 _ldp_global_del_adj(g, local_a);
86 } else {
87 /* by this time, we will have a e<->a binding, and some timers,
88 * if we're active, there will also be an active session */
89 retval = MPLS_SUCCESS;
92 ldp_state_new_adjacency_end:
94 LDP_EXIT(g->user_data, "ldp_state_new_adjacency");
95 return retval;
98 mpls_return_enum ldp_state_maintainance(ldp_global * g, ldp_session * s,
99 ldp_adj * a, ldp_entity * e, uint32_t event, ldp_mesg * msg, mpls_dest * from)
101 mpls_inet_addr traddr, *addr;
102 int hellotime;
103 int request = 0;
104 int target = 0;
105 uint32_t csn = 0;
106 mpls_return_enum retval = MPLS_SUCCESS;
108 MPLS_ASSERT(msg && e);
110 LDP_ENTER(g->user_data, "ldp_state_maintainance");
112 if (ldp_mesg_hello_get_hellotime(msg, &hellotime) != MPLS_SUCCESS) {
113 retval = MPLS_FAILURE;
114 goto ldp_state_maintainance_end;
117 ldp_mesg_hello_get_request(msg, &request);
118 ldp_mesg_hello_get_targeted(msg, &target);
119 /* if there isn't a csn in the msg, then csn stays 0 */
120 ldp_mesg_hello_get_csn(msg, &csn);
121 if (ldp_mesg_hello_get_traddr(msg, &traddr) != MPLS_SUCCESS) {
122 addr = NULL;
123 } else {
124 addr = &traddr;
127 if (ldp_hello_process(g, a, e, hellotime, csn, addr, target,
128 request) != MPLS_SUCCESS) {
129 retval = MPLS_FAILURE;
130 goto ldp_state_maintainance_end;
132 retval = ldp_adj_maintain_timer(g, a);
133 e->mesg_rx++;
135 ldp_state_maintainance_end:
137 LDP_EXIT(g->user_data, "ldp_state_maintainance");
139 return retval;
142 mpls_return_enum ldp_state_recv_init(ldp_global * g, ldp_session * s,
143 ldp_adj * a, ldp_entity * e, uint32_t event, ldp_mesg * msg, mpls_dest * from)
145 mpls_inet_addr lsraddr;
146 ldp_adj* ap;
147 int labelspace = 0;
148 mpls_bool match = MPLS_BOOL_FALSE;
150 MPLS_ASSERT(msg && s);
152 LDP_ENTER(g->user_data, "ldp_state_recv_init");
154 /* we haven't tied this session to an adj yet, at a minimum we can
155 * now stop the backoff timer we started while waiting for this
156 * init to arrive */
157 ldp_session_backoff_stop(g, s);
159 ldp_mesg_hdr_get_lsraddr(msg, &lsraddr);
160 ldp_mesg_hdr_get_labelspace(msg, &labelspace);
162 if (s->oper_role != LDP_ACTIVE) {
163 /* sessions being created from the ACTIVE side of an ADJ have already
164 * bound to the session */
165 /* there may be multiple ADJ that are matched! */
166 ap = MPLS_LIST_HEAD(&g->adj);
167 while (ap != NULL) {
168 if ((!mpls_inet_addr_compare(&lsraddr, &ap->remote_lsr_address)) &&
169 labelspace == ap->remote_label_space && !ap->session) {
170 ldp_adj_add_session(ap, s);
171 match = MPLS_BOOL_TRUE;
173 ap = MPLS_LIST_NEXT(&g->adj, ap, _global);
176 if (match == MPLS_BOOL_FALSE) {
177 LDP_PRINT(g->user_data, "ldp_state_recv_init: cannot find adj\n");
178 s->shutdown_notif = LDP_NOTIF_SESSION_REJECTED_NO_HELLO;
179 s->shutdown_fatal = MPLS_BOOL_FALSE;
180 goto ldp_state_recv_init_shutdown;
184 if (ldp_init_process(g, s, msg) == MPLS_FAILURE) {
185 LDP_PRINT(g->user_data, "ldp_state_recv_init: invalid INIT parameters\n");
186 /* session shutdown notif info set inside init_process */
187 goto ldp_state_recv_init_shutdown;
190 s->state = LDP_STATE_OPENREC;
191 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL, LDP_TRACE_FLAG_DEBUG,
192 "ldp_state_recv_init: (%d) changed to OPENREC\n", s->index);
194 if (s->oper_role == LDP_PASSIVE) {
195 if (ldp_init_send(g, s) == MPLS_FAILURE) {
196 LDP_PRINT(g->user_data, "ldp_state_recv_init: unable to send INIT\n");
197 s->shutdown_notif = LDP_NOTIF_INTERNAL_ERROR;
198 s->shutdown_fatal = MPLS_BOOL_TRUE;
199 goto ldp_state_recv_init_shutdown;
202 ldp_keepalive_send(g, s);
204 LDP_EXIT(g->user_data, "ldp_state_recv_init");
205 return MPLS_SUCCESS;
207 ldp_state_recv_init_shutdown:
209 LDP_EXIT(g->user_data, "ldp_state_recv_init-error");
210 return MPLS_FAILURE;
213 mpls_return_enum ldp_state_connect(ldp_global * g, ldp_session * s, ldp_adj * a,
214 ldp_entity * e, uint32_t event, ldp_mesg * msg, mpls_dest * from)
216 mpls_return_enum retval = MPLS_SUCCESS;
218 LDP_ENTER(g->user_data, "ldp_state_connect");
220 mpls_socket_readlist_add(g->socket_handle, s->socket, (void *)s,
221 MPLS_SOCKET_TCP_DATA);
222 s->state = LDP_STATE_INITIALIZED;
223 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL, LDP_TRACE_FLAG_DEBUG,
224 "ldp_state_connect: (%d) changed to INITIALIZED\n", s->index);
226 /* even though as part of creating an active session, the remote_dest
227 * was filled in, it had port 646 specified. 'from' now contains the
228 * real port info that our TCP session is connected to */
229 if (from) {
230 memcpy(&s->remote_dest, from, sizeof(mpls_dest));
233 if (s->oper_role == LDP_ACTIVE) {
234 if (ldp_init_send(g, s) == MPLS_SUCCESS) {
235 s->state = LDP_STATE_OPENSENT;
236 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL, LDP_TRACE_FLAG_DEBUG,
237 "ldp_state_connect: (%d) changed to OPENSENT\n", s->index);
238 } else {
239 s->shutdown_notif = LDP_NOTIF_INTERNAL_ERROR;
240 s->shutdown_fatal = MPLS_BOOL_TRUE;
241 retval = MPLS_FAILURE;
243 } else {
244 /* if this session is passive, we still are not associated with an
245 * adj. That will happen when we receive an init. There are no timers
246 * running yet, so we need to create a timer, to clean this socket
247 * up, if we do not receive a Init mesg, we'll overload the backoff
248 * timer for this purpose */
249 retval = ldp_session_backoff_start(g, s);
252 LDP_EXIT(g->user_data, "ldp_state_connect");
254 return retval;
257 mpls_return_enum ldp_state_finish_init(ldp_global * g, ldp_session * s,
258 ldp_adj * a, ldp_entity * e, uint32_t event, ldp_mesg * msg, mpls_dest * from)
260 mpls_return_enum retval;
261 MPLS_ASSERT(s);
263 LDP_ENTER(g->user_data, "ldp_state_finish_init");
265 retval = ldp_session_startup(g, s);
267 LDP_EXIT(g->user_data, "ldp_state_finish_init");
269 return MPLS_SUCCESS;
272 mpls_return_enum ldp_state_process(ldp_global * g, ldp_session * s, ldp_adj * a,
273 ldp_entity * e, uint32_t event, ldp_mesg * msg, mpls_dest * from)
275 mpls_return_enum retval = MPLS_SUCCESS;
276 ldp_attr *r_attr;
277 mpls_fec fec;
278 int i;
280 MPLS_ASSERT(s && msg);
282 LDP_ENTER(g->user_data, "ldp_state_process");
284 switch (msg->u.generic.flags.flags.msgType) {
285 case MPLS_LBLWITH_MSGTYPE:
287 mplsLdpLbl_W_R_Msg_t *rw = &msg->u.release;
289 for (i = 0; i < rw->fecTlv.numberFecElements; i++) {
290 fec_tlv2mpls_fec(&rw->fecTlv, i, &fec);
291 if (!(r_attr = ldp_attr_create(&fec))) {
292 goto ldp_state_process_error;
295 MPLS_REFCNT_HOLD(r_attr);
297 rel_with2attr(rw, r_attr);
298 retval = ldp_label_withdraw_process(g, s, a, e, r_attr, &fec);
300 MPLS_REFCNT_RELEASE(r_attr, ldp_attr_delete);
301 if (retval != MPLS_SUCCESS)
302 break;
304 break;
306 case MPLS_LBLREL_MSGTYPE:
308 mplsLdpLbl_W_R_Msg_t *rw = &msg->u.release;
310 for (i = 0; i < rw->fecTlv.numberFecElements; i++) {
311 fec_tlv2mpls_fec(&rw->fecTlv, i, &fec);
312 if (!(r_attr = ldp_attr_create(&fec))) {
313 goto ldp_state_process_error;
316 MPLS_REFCNT_HOLD(r_attr);
318 rel_with2attr(rw, r_attr);
319 retval = ldp_label_release_process(g, s, a, e, r_attr, &fec);
321 MPLS_REFCNT_RELEASE(r_attr, ldp_attr_delete);
322 if (retval != MPLS_SUCCESS)
323 break;
325 break;
327 case MPLS_LBLREQ_MSGTYPE:
329 mplsLdpLblReqMsg_t *req = &msg->u.request;
331 MPLS_ASSERT(req->fecTlv.numberFecElements == 1);
333 for (i = 0; i < req->fecTlv.numberFecElements; i++) {
334 fec_tlv2mpls_fec(&req->fecTlv, i, &fec);
335 if (!(r_attr = ldp_attr_create(&fec))) {
336 goto ldp_state_process_error;
339 MPLS_REFCNT_HOLD(r_attr);
341 req2attr(req, r_attr, LDP_ATTR_ALL & ~LDP_ATTR_FEC);
342 retval = ldp_label_request_process(g, s, a, e, r_attr, &fec);
344 MPLS_REFCNT_RELEASE(r_attr, ldp_attr_delete);
345 if (retval != MPLS_SUCCESS)
346 break;
348 break;
350 case MPLS_LBLMAP_MSGTYPE:
352 mplsLdpLblMapMsg_t *map = &msg->u.map;
354 for (i = 0; i < map->fecTlv.numberFecElements; i++) {
355 fec_tlv2mpls_fec(&map->fecTlv, i, &fec);
356 if (!(r_attr = ldp_attr_create(&fec))) {
357 goto ldp_state_process_error;
359 MPLS_REFCNT_HOLD(r_attr);
361 map2attr(map, r_attr, LDP_ATTR_ALL & ~LDP_ATTR_FEC);
362 retval = ldp_label_mapping_process(g, s, a, e, r_attr, &fec);
364 MPLS_REFCNT_RELEASE(r_attr, ldp_attr_delete);
365 if (retval != MPLS_SUCCESS)
366 break;
368 break;
370 case MPLS_LBLABORT_MSGTYPE:
372 mplsLdpLblAbortMsg_t *abrt = &msg->u.abort;
374 for (i = 0; i < abrt->fecTlv.numberFecElements; i++) {
375 fec_tlv2mpls_fec(&abrt->fecTlv, i, &fec);
376 if (!(r_attr = ldp_attr_create(&fec))) {
377 goto ldp_state_process_error;
380 MPLS_REFCNT_HOLD(r_attr);
381 abort2attr(abrt, r_attr, LDP_ATTR_ALL & ~LDP_ATTR_FEC);
382 retval = ldp_label_abort_process(g, s, a, e, r_attr, &fec);
384 MPLS_REFCNT_RELEASE(r_attr, ldp_attr_delete);
385 if (retval != MPLS_SUCCESS)
386 break;
388 break;
390 case MPLS_ADDRWITH_MSGTYPE:
391 case MPLS_ADDR_MSGTYPE:
393 retval = ldp_addr_process(g, s, e, msg);
394 break;
396 default:
398 MPLS_ASSERT(0);
399 break;
403 LDP_EXIT(g->user_data, "ldp_state_process");
405 return retval;
407 ldp_state_process_error:
409 LDP_EXIT(g->user_data, "ldp_state_process");
411 s->shutdown_notif = LDP_NOTIF_INTERNAL_ERROR;
412 s->shutdown_fatal = MPLS_BOOL_TRUE;
413 return MPLS_FAILURE;
416 mpls_return_enum ldp_state_ignore(ldp_global * g, ldp_session * session,
417 ldp_adj * adj, ldp_entity * entity, uint32_t event, ldp_mesg * msg,
418 mpls_dest * from)
420 return MPLS_SUCCESS;
423 mpls_return_enum ldp_state_close(ldp_global * g, ldp_session * s, ldp_adj * a,
424 ldp_entity * e, uint32_t event, ldp_mesg * msg, mpls_dest * from)
427 LDP_ENTER(g->user_data, "ldp_state_close: a = %p, e = %p s = %p",a,e,s);
429 /* JLEU: this need more work */
430 if (s) {
431 /* not sure why we got here but we should tear it completely down */
432 if (s->shutdown_fatal != MPLS_BOOL_TRUE) {
433 ldp_notif_send(g,s,NULL,s->shutdown_notif);
435 ldp_session_shutdown(g, s, MPLS_BOOL_TRUE);
438 LDP_EXIT(g->user_data, "ldp_state_close");
439 return MPLS_SUCCESS;
442 mpls_return_enum ldp_state_keepalive_maintainance(ldp_global * g,
443 ldp_session * s, ldp_adj * a, ldp_entity * e, uint32_t event, ldp_mesg * msg,
444 mpls_dest * from)
446 mpls_return_enum result;
448 MPLS_ASSERT(s);
450 LDP_ENTER(g->user_data, "ldp_state_keepalive_maintainance");
451 result = ldp_session_maintain_timer(g, s, LDP_KEEPALIVE_RECV);
453 LDP_EXIT(g->user_data, "ldp_state_keepalive_maintainance");
455 return result;
458 mpls_return_enum ldp_state_notif(ldp_global * g, ldp_session * s, ldp_adj * adj,
459 ldp_entity * entity, uint32_t event, ldp_mesg * msg, mpls_dest * from)
462 mpls_return_enum retval = MPLS_SUCCESS;
463 ldp_attr *r_attr = NULL;
464 mplsLdpNotifMsg_t *not = &msg->u.notif;
466 MPLS_ASSERT(s && msg);
468 LDP_ENTER(g->user_data, "ldp_state_notif");
470 if (!(r_attr = ldp_attr_create(NULL))) {
471 retval = MPLS_FAILURE;
472 goto ldp_state_notif_end;
475 MPLS_REFCNT_HOLD(r_attr);
477 not2attr(not, r_attr, LDP_ATTR_ALL);
478 retval = ldp_notif_process(g, s, adj, entity, r_attr);
480 MPLS_REFCNT_RELEASE(r_attr, ldp_attr_delete);
482 ldp_state_notif_end:
484 LDP_EXIT(g->user_data, "ldp_state_notif");
486 return retval;