You cannot possible compile the LSR (or the LDP) lib without a porting
[mpls-ldp-portable.git] / ldp / ldp_state_machine.c
blob1c83c3b894f6c166eb8cef25876d93c573c7f879
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 "ldp_struct.h"
11 #include "ldp_global.h"
12 #include "ldp_session.h"
13 #include "ldp_entity.h"
14 #include "ldp_peer.h"
15 #include "ldp_if.h"
16 #include "ldp_adj.h"
17 #include "ldp_mesg.h"
18 #include "ldp_buf.h"
19 #include "ldp_state_machine.h"
21 #include "mpls_assert.h"
22 #include "mpls_socket_impl.h"
23 #include "mpls_lock_impl.h"
24 #include "mpls_trace_impl.h"
26 /* HELLO CONNECT INIT KEEP ADDR LABEL NOTIF CLOSE HTIMER KTIMER */
27 /* SES_NONE new ignore ignore ignore ignore ignore ignore close ignore ignore */
28 /* SES_NON_EXISTENT maint connect close close close close close close close ignore */
29 /* SES_INITIALIZED maint close recv_init close close close notif close close ignore */
30 /* SES_OPENSENT maint close recv_init close close close notif close close ignore */
31 /* SES_OPENREC maint close close finish close close notif close close close */
32 /* SES_OPERATIONAL maint close kmaint kmaint process process notif close close close */
34 int ldp_state_table[LDP_STATE_NUM][LDP_EVENT_NUM] = {
35 {0, 6, 6, 6, 6, 6, 6, 7, 6, 6},
36 {1, 3, 7, 7, 7, 7, 7, 7, 7, 6},
37 {1, 7, 2, 7, 7, 7, 9, 7, 7, 6},
38 {1, 7, 2, 7, 7, 7, 9, 7, 7, 6},
39 {1, 7, 7, 4, 7, 7, 9, 7, 7, 7},
40 {1, 7, 8, 8, 5, 5, 9, 7, 7, 7}};
42 mpls_return_enum ldp_buf_process(ldp_global * g, mpls_socket_handle socket,
43 ldp_buf * buf, void *extra, ldp_event_enum event, mpls_dest * from,
44 mpls_bool * more);
46 mpls_return_enum(*ldp_state_func[LDP_FUNC_NUM]) (ldp_global *, ldp_session *,
47 ldp_adj *, ldp_entity *, uint32_t, ldp_mesg *, mpls_dest *) = {
48 ldp_state_new_adjacency, /* 0 */
49 ldp_state_maintainance, /* 1 */
50 ldp_state_recv_init, /* 2 */
51 ldp_state_connect, /* 3 */
52 ldp_state_finish_init, /* 4 */
53 ldp_state_process, /* 5 */
54 ldp_state_ignore, /* 6 */
55 ldp_state_close, /* 7 */
56 ldp_state_keepalive_maintainance, /* 8 */
57 ldp_state_notif /* 9 */
60 #define LDP_FUNC_CLOSE 7
62 mpls_return_enum ldp_event(mpls_cfg_handle handle, mpls_socket_handle socket,
63 void *extra, ldp_event_enum event)
65 mpls_return_enum retval = MPLS_SUCCESS;
66 ldp_global *g = (ldp_global*)handle;
68 mpls_socket_handle socket_new = (mpls_socket_handle)0;
69 ldp_session *session = NULL;
70 ldp_entity *entity = NULL;
71 ldp_adj *adj = NULL;
73 uint8_t buffer[MPLS_PDUMAXLEN];
74 mpls_dest from;
75 ldp_mesg mesg;
76 ldp_buf buf;
78 LDP_ENTER(g->user_data, "ldp_event");
80 mpls_lock_get(g->global_lock);
82 switch (event) {
83 case LDP_EVENT_TCP_DATA:
84 case LDP_EVENT_UDP_DATA:
86 mpls_bool more;
88 buf.current = buffer;
89 buf.buffer = buffer;
90 buf.total = MPLS_PDUMAXLEN;
91 buf.size = 0;
92 buf.current_size = 0;
93 buf.want = 0;
95 /* do this so a failure will know which session caused it */
96 if (event == LDP_EVENT_TCP_DATA) {
97 session = extra;
100 do {
101 retval = ldp_buf_process(g, socket, &buf, extra, event, &from, &more);
102 } while (retval == MPLS_SUCCESS && more == MPLS_BOOL_TRUE);
103 break;
105 case LDP_EVENT_TCP_LISTEN:
107 socket_new = mpls_socket_tcp_accept(g->socket_handle, socket, &from);
109 if (mpls_socket_handle_verify(g->socket_handle, socket_new) ==
110 MPLS_BOOL_FALSE) {
111 LDP_PRINT(g->user_data, "Failed accepting socket\n");
112 retval = MPLS_FAILURE;
113 } else if (!(session = ldp_session_create_passive(g, socket_new,
114 &from))) {
115 mpls_socket_close(g->socket_handle, socket_new);
116 LDP_PRINT(g->user_data, "Failure creating passive session\n");
117 retval = MPLS_FATAL;
118 } else {
119 retval = ldp_state_machine(g, session, NULL, NULL,
120 LDP_EVENT_CONNECT, &mesg, &from);
122 break;
124 case LDP_EVENT_TCP_CONNECT:
126 retval = mpls_socket_connect_status(g->socket_handle, socket);
127 session = (ldp_session *)extra;
129 if (retval == MPLS_SUCCESS) {
130 /* only get this case if we did a non-block connect */
131 mpls_socket_writelist_del(g->socket_handle, socket);
132 retval = ldp_state_machine(g, session, NULL, NULL,
133 LDP_EVENT_CONNECT, &mesg, &from);
134 } else if (retval != MPLS_NON_BLOCKING) {
135 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL, LDP_TRACE_FLAG_ERROR,
136 "ldp_event: LDP_EVENT_TCP_CONNECT errno = %d\n",
137 mpls_socket_get_errno(g->socket_handle, socket));
138 } else {
139 /* non-blocking connect is still blocking, we'll try again in a bit */
140 retval = MPLS_SUCCESS;
142 break;
144 case LDP_EVENT_CLOSE:
146 retval = ldp_state_machine(g, session, adj, entity,
147 LDP_EVENT_CLOSE, &mesg, &from);
148 break;
150 default:
152 MPLS_ASSERT(0);
156 /* ldp_state_machine return MPLS_SUCCESS when it has handled the event
157 to completion. If the handling off the event results in the session
158 needing to be shutdown MPLS_FAILURE is returned. If the handling of
159 the event requires the LDP be shutdown LD_FATAL is returned, and
160 passed back to the user. other values are invalid */
162 switch (retval) {
163 case MPLS_FAILURE:
165 /* if shutting down the session results in LDP_FATAL, then pass it
166 * back to the user */
168 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL, LDP_TRACE_FLAG_ERROR,
169 "ldp_event: FAILURE executing a CLOSE\n");
171 retval = ldp_state_machine(g, session, adj, entity, LDP_EVENT_CLOSE,
172 NULL, &from);
174 if (retval == MPLS_FATAL) {
175 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL, LDP_TRACE_FLAG_ERROR,
176 "ldp_event: CLOSE failed: FATAL propogated to the environemnt\n");
178 break;
180 case MPLS_FATAL:
182 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL, LDP_TRACE_FLAG_ERROR,
183 "ldp_event: FATAL propogated to the environemnt\n");
184 break;
186 case MPLS_SUCCESS:
188 break;
190 default:
192 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL, LDP_TRACE_FLAG_ERROR,
193 "ldp_event: invalid return value of %d\n", retval);
194 break;
198 mpls_lock_release(g->global_lock);
200 LDP_EXIT(g->user_data, "ldp_event");
202 return retval;
205 mpls_return_enum ldp_state_machine(ldp_global * g, ldp_session * session,
206 ldp_adj * adj, ldp_entity * entity, uint32_t event, ldp_mesg * msg,
207 mpls_dest * from)
209 int state = LDP_STATE_NONE;
210 int func = 0;
211 mpls_return_enum retval = MPLS_FAILURE;
213 LDP_ENTER(g->user_data, "ldp_state_machine");
215 if (session) {
216 state = session->state;
217 } else if (adj) {
218 state = LDP_STATE_NON_EXIST;
221 if (state >= LDP_STATE_NONE && state <= LDP_STATE_OPERATIONAL) {
222 if (event <= LDP_EVENT_KTIMER) {
223 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL, LDP_TRACE_FLAG_STATE,
224 "FSM: state %d, event %d\n", state, event);
225 func = ldp_state_table[state][event];
226 retval = ldp_state_func[func] (g, session, adj, entity, event, msg, from);
230 LDP_EXIT(g->user_data, "ldp_state_machine");
231 return retval;
234 mpls_return_enum ldp_buf_process(ldp_global * g, mpls_socket_handle socket,
235 ldp_buf * buf, void *extra, ldp_event_enum event, mpls_dest * from,
236 mpls_bool * more)
239 mpls_return_enum retval = MPLS_SUCCESS;
240 ldp_session *session = NULL;
241 ldp_entity *entity = NULL;
242 ldp_adj *adj = NULL;
243 ldp_mesg mesg;
245 int size = 0;
247 LDP_ENTER(g->user_data, "ldp_buf_process");
249 *more = MPLS_BOOL_TRUE;
251 memset(&mesg, 0, sizeof(mesg));
252 if (!buf->want) {
253 buf->want = MPLS_LDP_HDRSIZE;
256 read_again:
258 switch (event) {
259 case LDP_EVENT_TCP_DATA:
261 session = (ldp_session *) extra;
262 MPLS_ASSERT(session);
263 session->mesg_rx++;
265 size = mpls_socket_tcp_read(g->socket_handle, socket,
266 buf->buffer + buf->size, buf->want - buf->size);
268 if (!size) {
269 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL,
270 LDP_TRACE_FLAG_ERROR, "ldp_event: LDP_EVENT_TCP_DATA errno = %d\n",
271 mpls_socket_get_errno(g->socket_handle, socket));
273 retval = MPLS_FAILURE;
274 session->shutdown_notif = LDP_NOTIF_SHUTDOWN;
275 session->shutdown_fatal = MPLS_BOOL_TRUE;
276 goto ldp_event_end;
279 if (size < 0) {
280 retval = MPLS_SUCCESS;
281 *more = MPLS_BOOL_FALSE;
282 goto ldp_event_end;
284 break;
286 case LDP_EVENT_UDP_DATA:
288 size = mpls_socket_udp_recvfrom(g->socket_handle, socket,
289 buf->buffer + buf->size, buf->total - buf->size, from);
291 if (!size) {
292 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL,
293 LDP_TRACE_FLAG_ERROR, "ldp_event: LDP_EVENT_UDP_DATA errno = %d\n",
294 mpls_socket_get_errno(g->socket_handle, socket));
295 retval = MPLS_FAILURE;
296 goto ldp_event_end;
299 if (size < 0) {
300 retval = MPLS_SUCCESS;
301 *more = MPLS_BOOL_FALSE;
302 goto ldp_event_end;
304 break;
306 default:
308 MPLS_ASSERT(0);
309 break;
313 buf->current_size += size;
314 buf->size += size;
316 decode_again:
318 if (buf->size < buf->want) {
319 retval = MPLS_SUCCESS;
320 *more = MPLS_BOOL_FALSE;
321 goto ldp_event_end;
324 /* upon succesful decode the pduLength will be non 0 */
325 if (!mesg.header.pduLength) {
326 if (ldp_decode_header(g, buf, &mesg) != MPLS_SUCCESS) {
327 retval = MPLS_FAILURE;
329 if (session) {
330 session->shutdown_notif = LDP_NOTIF_BAD_MESG_LEN;
332 goto ldp_event_end;
335 /* -buf->size is already 10 (the size of the full header
336 * -pduLength include 6 bytes of the header
338 * therefore add 4 so we can compare buf->want to buf->size and
339 * not have to adjust
341 buf->want = mesg.header.pduLength + 4;
342 if (buf->size < buf->want) {
343 goto read_again;
345 if (buf->size > buf->want) {
346 buf->current_size = buf->want - MPLS_LDP_HDRSIZE;
350 do {
351 if (ldp_decode_one_mesg(g, buf, &mesg) != MPLS_SUCCESS) {
352 retval = MPLS_FAILURE;
354 if (session) {
355 session->shutdown_notif = LDP_NOTIF_BAD_MESG_LEN;
357 goto ldp_event_end_loop;
360 switch (ldp_mesg_get_type(&mesg)) {
361 case MPLS_HELLO_MSGTYPE:
363 mpls_oper_state_enum oper_state = MPLS_OPER_DOWN;
364 mpls_inet_addr addr;
365 int labelspace = 0;
366 int targeted;
368 event = LDP_EVENT_HELLO;
370 targeted = 0;
371 ldp_mesg_hello_get_targeted(&mesg, &targeted);
372 ldp_mesg_hdr_get_lsraddr(&mesg, &addr);
373 ldp_mesg_hdr_get_labelspace(&mesg, &labelspace);
375 if (targeted) {
376 ldp_peer *peer = NULL;
377 if ((peer = ldp_global_find_peer_addr(g, &addr))) {
378 entity = ldp_peer_get_entity(peer);
379 oper_state = peer->oper_state;
381 } else {
382 ldp_if *iff = NULL;
383 if ((iff = ldp_global_find_if_handle(g, from->if_handle))) {
384 entity = ldp_if_get_entity(iff);
385 oper_state = iff->oper_state;
389 if (!entity) {
390 /* No entity! No choice but to ignore this packet */
391 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL,
392 LDP_TRACE_FLAG_NORMAL, "ldp_event: unknown entity\n");
393 goto ldp_event_end_loop;
394 } else if (entity->admin_state == MPLS_ADMIN_DISABLE) {
395 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL,
396 LDP_TRACE_FLAG_NORMAL, "ldp_event: entity is disabled\n");
397 goto ldp_event_end_loop;
398 } else if (oper_state == MPLS_OPER_DOWN) {
399 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL,
400 LDP_TRACE_FLAG_NORMAL, "ldp_event: entity is down\n");
401 goto ldp_event_end_loop;
404 if (!(adj = ldp_entity_find_adj(entity, &mesg))) {
405 if ((adj = ldp_global_find_adj_ldpid(g, &addr, labelspace))) {
406 /* this could be a parallel link contributing to an adj */
407 ldp_entity_add_adj(entity, adj);
411 /* if we don't have an adj one will be create by state machine */
412 break;
414 case MPLS_INIT_MSGTYPE:
416 event = LDP_EVENT_INIT;
417 break;
419 case MPLS_NOT_MSGTYPE:
421 event = LDP_EVENT_NOTIF;
422 break;
424 case MPLS_KEEPAL_MSGTYPE:
426 event = LDP_EVENT_KEEP;
427 break;
429 case MPLS_LBLWITH_MSGTYPE:
430 case MPLS_LBLREL_MSGTYPE:
431 case MPLS_LBLREQ_MSGTYPE:
432 case MPLS_LBLMAP_MSGTYPE:
433 case MPLS_LBLABORT_MSGTYPE:
435 event = LDP_EVENT_LABEL;
436 break;
438 case MPLS_ADDR_MSGTYPE:
439 case MPLS_ADDRWITH_MSGTYPE:
441 event = LDP_EVENT_ADDR;
442 break;
444 default:
446 MPLS_ASSERT(0);
450 retval =
451 ldp_state_machine(g, session, adj, entity, event, &mesg, from);
453 ldp_event_end_loop:
455 if (retval != MPLS_SUCCESS) {
456 break;
458 } while ((buf->current_size > 0) && (*more == MPLS_BOOL_TRUE));
460 if (buf->want < buf->size) {
461 buf->current_size = buf->size - buf->want;
462 buf->size = buf->current_size;
463 memmove(buf->buffer, buf->current, buf->current_size);
464 } else {
465 buf->size = 0;
468 buf->current = buf->buffer;
469 memset(&mesg, 0, sizeof(mesg));
470 buf->want = MPLS_LDP_HDRSIZE;
472 if (buf->current_size) {
473 goto decode_again;
476 ldp_event_end:
478 LDP_EXIT(g->user_data, "ldp_buf_process");
480 return retval;