3 * Copyright (C) James R. Leu 2000
6 * This software is covered under the LGPL, for more
7 * info check out http://www.gnu.org/copyleft/lgpl.html
10 #include "ldp_struct.h"
11 #include "ldp_global.h"
12 #include "ldp_session.h"
13 #include "ldp_entity.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
,
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
;
73 uint8_t buffer
[MPLS_PDUMAXLEN
];
78 LDP_ENTER(g
->user_data
, "ldp_event");
80 mpls_lock_get(g
->global_lock
);
83 case LDP_EVENT_TCP_DATA
:
84 case LDP_EVENT_UDP_DATA
:
90 buf
.total
= MPLS_PDUMAXLEN
;
95 /* do this so a failure will know which session caused it */
96 if (event
== LDP_EVENT_TCP_DATA
) {
101 retval
= ldp_buf_process(g
, socket
, &buf
, extra
, event
, &from
, &more
);
102 } while (retval
== MPLS_SUCCESS
&& more
== MPLS_BOOL_TRUE
);
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
) ==
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
,
115 mpls_socket_close(g
->socket_handle
, socket_new
);
116 LDP_PRINT(g
->user_data
, "Failure creating passive session\n");
119 retval
= ldp_state_machine(g
, session
, NULL
, NULL
,
120 LDP_EVENT_CONNECT
, &mesg
, &from
);
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
));
139 /* non-blocking connect is still blocking, we'll try again in a bit */
140 retval
= MPLS_SUCCESS
;
144 case LDP_EVENT_CLOSE
:
146 retval
= ldp_state_machine(g
, session
, adj
, entity
,
147 LDP_EVENT_CLOSE
, &mesg
, &from
);
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 */
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
,
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");
182 LDP_TRACE_LOG(g
->user_data
, MPLS_TRACE_STATE_ALL
, LDP_TRACE_FLAG_ERROR
,
183 "ldp_event: FATAL propogated to the environemnt\n");
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
);
198 mpls_lock_release(g
->global_lock
);
200 LDP_EXIT(g
->user_data
, "ldp_event");
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
,
209 int state
= LDP_STATE_NONE
;
211 mpls_return_enum retval
= MPLS_FAILURE
;
213 LDP_ENTER(g
->user_data
, "ldp_state_machine");
216 state
= session
->state
;
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");
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
,
239 mpls_return_enum retval
= MPLS_SUCCESS
;
240 ldp_session
*session
= NULL
;
241 ldp_entity
*entity
= NULL
;
247 LDP_ENTER(g
->user_data
, "ldp_buf_process");
249 *more
= MPLS_BOOL_TRUE
;
251 memset(&mesg
, 0, sizeof(mesg
));
253 buf
->want
= MPLS_LDP_HDRSIZE
;
259 case LDP_EVENT_TCP_DATA
:
261 session
= (ldp_session
*) extra
;
262 MPLS_ASSERT(session
);
265 size
= mpls_socket_tcp_read(g
->socket_handle
, socket
,
266 buf
->buffer
+ buf
->size
, buf
->want
- buf
->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
;
280 retval
= MPLS_SUCCESS
;
281 *more
= MPLS_BOOL_FALSE
;
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
);
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
;
300 retval
= MPLS_SUCCESS
;
301 *more
= MPLS_BOOL_FALSE
;
313 buf
->current_size
+= size
;
318 if (buf
->size
< buf
->want
) {
319 retval
= MPLS_SUCCESS
;
320 *more
= MPLS_BOOL_FALSE
;
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
;
330 session
->shutdown_notif
= LDP_NOTIF_BAD_MESG_LEN
;
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
341 buf
->want
= mesg
.header
.pduLength
+ 4;
342 if (buf
->size
< buf
->want
) {
345 if (buf
->size
> buf
->want
) {
346 buf
->current_size
= buf
->want
- MPLS_LDP_HDRSIZE
;
351 if (ldp_decode_one_mesg(g
, buf
, &mesg
) != MPLS_SUCCESS
) {
352 retval
= MPLS_FAILURE
;
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
;
368 event
= LDP_EVENT_HELLO
;
371 ldp_mesg_hello_get_targeted(&mesg
, &targeted
);
372 ldp_mesg_hdr_get_lsraddr(&mesg
, &addr
);
373 ldp_mesg_hdr_get_labelspace(&mesg
, &labelspace
);
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
;
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
;
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 */
414 case MPLS_INIT_MSGTYPE
:
416 event
= LDP_EVENT_INIT
;
419 case MPLS_NOT_MSGTYPE
:
421 event
= LDP_EVENT_NOTIF
;
424 case MPLS_KEEPAL_MSGTYPE
:
426 event
= LDP_EVENT_KEEP
;
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
;
438 case MPLS_ADDR_MSGTYPE
:
439 case MPLS_ADDRWITH_MSGTYPE
:
441 event
= LDP_EVENT_ADDR
;
451 ldp_state_machine(g
, session
, adj
, entity
, event
, &mesg
, from
);
455 if (retval
!= MPLS_SUCCESS
) {
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
);
468 buf
->current
= buf
->buffer
;
469 memset(&mesg
, 0, sizeof(mesg
));
470 buf
->want
= MPLS_LDP_HDRSIZE
;
472 if (buf
->current_size
) {
478 LDP_EXIT(g
->user_data
, "ldp_buf_process");