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
);
133 /* Fill the "from" address */
134 mpls_socket_get_remote_name(g
->socket_handle
, socket
, &from
);
135 retval
= ldp_state_machine(g
, session
, NULL
, NULL
,
136 LDP_EVENT_CONNECT
, &mesg
, &from
);
137 } else if (retval
!= MPLS_NON_BLOCKING
) {
138 LDP_TRACE_LOG(g
->user_data
, MPLS_TRACE_STATE_ALL
, LDP_TRACE_FLAG_ERROR
,
139 "ldp_event: LDP_EVENT_TCP_CONNECT errno = %d\n",
140 mpls_socket_get_errno(g
->socket_handle
, socket
));
142 /* non-blocking connect is still blocking, we'll try again in a bit */
143 retval
= MPLS_SUCCESS
;
147 case LDP_EVENT_CLOSE
:
149 retval
= ldp_state_machine(g
, session
, adj
, entity
,
150 LDP_EVENT_CLOSE
, &mesg
, &from
);
159 /* ldp_state_machine return MPLS_SUCCESS when it has handled the event
160 to completion. If the handling off the event results in the session
161 needing to be shutdown MPLS_FAILURE is returned. If the handling of
162 the event requires the LDP be shutdown LD_FATAL is returned, and
163 passed back to the user. other values are invalid */
168 /* if shutting down the session results in LDP_FATAL, then pass it
169 * back to the user */
171 LDP_TRACE_LOG(g
->user_data
, MPLS_TRACE_STATE_ALL
, LDP_TRACE_FLAG_ERROR
,
172 "ldp_event: FAILURE executing a CLOSE\n");
174 retval
= ldp_state_machine(g
, session
, adj
, entity
, LDP_EVENT_CLOSE
,
177 if (retval
== MPLS_FATAL
) {
178 LDP_TRACE_LOG(g
->user_data
, MPLS_TRACE_STATE_ALL
, LDP_TRACE_FLAG_ERROR
,
179 "ldp_event: CLOSE failed: FATAL propogated to the environemnt\n");
185 LDP_TRACE_LOG(g
->user_data
, MPLS_TRACE_STATE_ALL
, LDP_TRACE_FLAG_ERROR
,
186 "ldp_event: FATAL propogated to the environemnt\n");
195 LDP_TRACE_LOG(g
->user_data
, MPLS_TRACE_STATE_ALL
, LDP_TRACE_FLAG_ERROR
,
196 "ldp_event: invalid return value of %d\n", retval
);
201 mpls_lock_release(g
->global_lock
);
203 LDP_EXIT(g
->user_data
, "ldp_event");
208 mpls_return_enum
ldp_state_machine(ldp_global
* g
, ldp_session
* session
,
209 ldp_adj
* adj
, ldp_entity
* entity
, uint32_t event
, ldp_mesg
* msg
,
212 int state
= LDP_STATE_NONE
;
214 mpls_return_enum retval
= MPLS_FAILURE
;
216 LDP_ENTER(g
->user_data
, "ldp_state_machine");
219 state
= session
->state
;
221 state
= LDP_STATE_NON_EXIST
;
224 if (state
>= LDP_STATE_NONE
&& state
<= LDP_STATE_OPERATIONAL
) {
225 if (event
<= LDP_EVENT_KTIMER
) {
226 LDP_TRACE_LOG(g
->user_data
, MPLS_TRACE_STATE_ALL
, LDP_TRACE_FLAG_STATE
,
227 "FSM: state %d, event %d\n", state
, event
);
228 func
= ldp_state_table
[state
][event
];
229 retval
= ldp_state_func
[func
] (g
, session
, adj
, entity
, event
, msg
, from
);
233 LDP_EXIT(g
->user_data
, "ldp_state_machine");
237 mpls_return_enum
ldp_buf_process(ldp_global
* g
, mpls_socket_handle socket
,
238 ldp_buf
* buf
, void *extra
, ldp_event_enum event
, mpls_dest
* from
,
242 mpls_return_enum retval
= MPLS_SUCCESS
;
243 ldp_session
*session
= NULL
;
244 ldp_entity
*entity
= NULL
;
250 LDP_ENTER(g
->user_data
, "ldp_buf_process");
252 *more
= MPLS_BOOL_TRUE
;
254 memset(&mesg
, 0, sizeof(mesg
));
256 buf
->want
= MPLS_LDP_HDRSIZE
;
262 case LDP_EVENT_TCP_DATA
:
264 session
= (ldp_session
*) extra
;
265 MPLS_ASSERT(session
);
268 size
= mpls_socket_tcp_read(g
->socket_handle
, socket
,
269 buf
->buffer
+ buf
->size
, buf
->want
- buf
->size
);
272 LDP_TRACE_LOG(g
->user_data
, MPLS_TRACE_STATE_ALL
,
273 LDP_TRACE_FLAG_ERROR
, "ldp_event: LDP_EVENT_TCP_DATA errno = %d\n",
274 mpls_socket_get_errno(g
->socket_handle
, socket
));
276 retval
= MPLS_FAILURE
;
277 session
->shutdown_notif
= LDP_NOTIF_SHUTDOWN
;
278 session
->shutdown_fatal
= MPLS_BOOL_TRUE
;
283 retval
= MPLS_SUCCESS
;
284 *more
= MPLS_BOOL_FALSE
;
289 case LDP_EVENT_UDP_DATA
:
291 size
= mpls_socket_udp_recvfrom(g
->socket_handle
, socket
,
292 buf
->buffer
+ buf
->size
, buf
->total
- buf
->size
, from
);
295 LDP_TRACE_LOG(g
->user_data
, MPLS_TRACE_STATE_ALL
,
296 LDP_TRACE_FLAG_ERROR
, "ldp_event: LDP_EVENT_UDP_DATA errno = %d\n",
297 mpls_socket_get_errno(g
->socket_handle
, socket
));
298 retval
= MPLS_FAILURE
;
303 retval
= MPLS_SUCCESS
;
304 *more
= MPLS_BOOL_FALSE
;
316 buf
->current_size
+= size
;
321 if (buf
->size
< buf
->want
) {
322 retval
= MPLS_SUCCESS
;
323 *more
= MPLS_BOOL_FALSE
;
327 /* upon succesful decode the pduLength will be non 0 */
328 if (!mesg
.header
.pduLength
) {
329 if (ldp_decode_header(g
, buf
, &mesg
) != MPLS_SUCCESS
) {
330 retval
= MPLS_FAILURE
;
333 session
->shutdown_notif
= LDP_NOTIF_BAD_MESG_LEN
;
338 /* -buf->size is already 10 (the size of the full header
339 * -pduLength include 6 bytes of the header
341 * therefore add 4 so we can compare buf->want to buf->size and
344 buf
->want
= mesg
.header
.pduLength
+ 4;
345 if (buf
->size
< buf
->want
) {
348 if (buf
->size
> buf
->want
) {
349 buf
->current_size
= buf
->want
- MPLS_LDP_HDRSIZE
;
354 if (ldp_decode_one_mesg(g
, buf
, &mesg
) != MPLS_SUCCESS
) {
355 retval
= MPLS_FAILURE
;
358 session
->shutdown_notif
= LDP_NOTIF_BAD_MESG_LEN
;
360 goto ldp_event_end_loop
;
363 switch (ldp_mesg_get_type(&mesg
)) {
364 case MPLS_HELLO_MSGTYPE
:
366 mpls_oper_state_enum oper_state
= MPLS_OPER_DOWN
;
371 event
= LDP_EVENT_HELLO
;
374 ldp_mesg_hello_get_targeted(&mesg
, &targeted
);
375 ldp_mesg_hdr_get_lsraddr(&mesg
, &addr
);
376 ldp_mesg_hdr_get_labelspace(&mesg
, &labelspace
);
379 ldp_peer
*peer
= NULL
;
380 if ((peer
= ldp_global_find_peer_addr(g
, &addr
))) {
381 entity
= ldp_peer_get_entity(peer
);
382 oper_state
= peer
->oper_state
;
386 if ((iff
= ldp_global_find_if_handle(g
, from
->if_handle
))) {
387 entity
= ldp_if_get_entity(iff
);
388 oper_state
= iff
->oper_state
;
393 /* No entity! No choice but to ignore this packet */
394 LDP_TRACE_LOG(g
->user_data
, MPLS_TRACE_STATE_ALL
,
395 LDP_TRACE_FLAG_NORMAL
, "ldp_event: unknown entity\n");
396 goto ldp_event_end_loop
;
397 } else if (entity
->admin_state
== MPLS_ADMIN_DISABLE
) {
398 LDP_TRACE_LOG(g
->user_data
, MPLS_TRACE_STATE_ALL
,
399 LDP_TRACE_FLAG_NORMAL
, "ldp_event: entity is disabled\n");
400 goto ldp_event_end_loop
;
401 } else if (oper_state
== MPLS_OPER_DOWN
) {
402 LDP_TRACE_LOG(g
->user_data
, MPLS_TRACE_STATE_ALL
,
403 LDP_TRACE_FLAG_NORMAL
, "ldp_event: entity is down\n");
404 goto ldp_event_end_loop
;
408 if ((adj
= ldp_entity_find_adj(entity
, &mesg
))) {
409 session
= adj
->session
;
413 /* if we don't have an adj one will be create by state machine */
416 case MPLS_INIT_MSGTYPE
:
418 event
= LDP_EVENT_INIT
;
421 case MPLS_NOT_MSGTYPE
:
423 event
= LDP_EVENT_NOTIF
;
426 case MPLS_KEEPAL_MSGTYPE
:
428 event
= LDP_EVENT_KEEP
;
431 case MPLS_LBLWITH_MSGTYPE
:
432 case MPLS_LBLREL_MSGTYPE
:
433 case MPLS_LBLREQ_MSGTYPE
:
434 case MPLS_LBLMAP_MSGTYPE
:
435 case MPLS_LBLABORT_MSGTYPE
:
437 event
= LDP_EVENT_LABEL
;
440 case MPLS_ADDR_MSGTYPE
:
441 case MPLS_ADDRWITH_MSGTYPE
:
443 event
= LDP_EVENT_ADDR
;
453 ldp_state_machine(g
, session
, adj
, entity
, event
, &mesg
, from
);
457 if (retval
!= MPLS_SUCCESS
) {
460 } while ((buf
->current_size
> 0) && (*more
== MPLS_BOOL_TRUE
));
462 if (buf
->want
< buf
->size
) {
463 buf
->current_size
= buf
->size
- buf
->want
;
464 buf
->size
= buf
->current_size
;
465 memmove(buf
->buffer
, buf
->current
, buf
->current_size
);
470 buf
->current
= buf
->buffer
;
471 memset(&mesg
, 0, sizeof(mesg
));
472 buf
->want
= MPLS_LDP_HDRSIZE
;
474 if (buf
->current_size
) {
480 LDP_EXIT(g
->user_data
, "ldp_buf_process");