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 <sys/socket.h>
11 #include "ldp_struct.h"
12 #include "ldp_global.h"
13 #include "ldp_session.h"
14 #include "ldp_entity.h"
19 #include "ldp_hello.h"
21 #include "ldp_label_rel_with.h"
22 #include "ldp_label_mapping.h"
23 #include "ldp_label_request.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
;
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
) {
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
);
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");
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
;
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
) {
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
);
135 ldp_state_maintainance_end
:
137 LDP_EXIT(g
->user_data
, "ldp_state_maintainance");
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
;
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
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
);
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");
207 ldp_state_recv_init_shutdown
:
209 LDP_EXIT(g
->user_data
, "ldp_state_recv_init-error");
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 */
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
);
239 s
->shutdown_notif
= LDP_NOTIF_INTERNAL_ERROR
;
240 s
->shutdown_fatal
= MPLS_BOOL_TRUE
;
241 retval
= MPLS_FAILURE
;
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");
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
;
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");
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
;
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
;
290 for (i
= 0; i
< rw
->fecTlv
.numberFecElements
; i
++) {
291 fec_tlv2mpls_fec(&rw
->fecTlv
, i
, &fec
);
292 if (!(r_attr
= ldp_attr_create(&fec
))) {
293 goto ldp_state_process_error
;
296 MPLS_REFCNT_HOLD(r_attr
);
298 rel_with2attr(rw
, r_attr
);
299 f
= ldp_fec_find(g
, &fec
);
300 retval
= ldp_label_withdraw_process(g
, s
, a
, e
, r_attr
, f
);
302 MPLS_REFCNT_RELEASE(r_attr
, ldp_attr_delete
);
303 if (retval
!= MPLS_SUCCESS
)
308 case MPLS_LBLREL_MSGTYPE
:
310 mplsLdpLbl_W_R_Msg_t
*rw
= &msg
->u
.release
;
313 for (i
= 0; i
< rw
->fecTlv
.numberFecElements
; i
++) {
314 fec_tlv2mpls_fec(&rw
->fecTlv
, i
, &fec
);
315 if (!(r_attr
= ldp_attr_create(&fec
))) {
316 goto ldp_state_process_error
;
319 MPLS_REFCNT_HOLD(r_attr
);
321 rel_with2attr(rw
, r_attr
);
322 f
= ldp_fec_find(g
, &fec
);
323 retval
= ldp_label_release_process(g
, s
, a
, e
, r_attr
, f
);
325 MPLS_REFCNT_RELEASE(r_attr
, ldp_attr_delete
);
326 if (retval
!= MPLS_SUCCESS
)
331 case MPLS_LBLREQ_MSGTYPE
:
333 mplsLdpLblReqMsg_t
*req
= &msg
->u
.request
;
336 MPLS_ASSERT(req
->fecTlv
.numberFecElements
== 1);
338 for (i
= 0; i
< req
->fecTlv
.numberFecElements
; i
++) {
339 fec_tlv2mpls_fec(&req
->fecTlv
, i
, &fec
);
340 if (!(r_attr
= ldp_attr_create(&fec
))) {
341 goto ldp_state_process_error
;
344 MPLS_REFCNT_HOLD(r_attr
);
346 req2attr(req
, r_attr
, LDP_ATTR_ALL
& ~LDP_ATTR_FEC
);
347 f
= ldp_fec_find(g
, &fec
);
348 retval
= ldp_label_request_process(g
, s
, a
, e
, r_attr
, f
);
350 MPLS_REFCNT_RELEASE(r_attr
, ldp_attr_delete
);
351 if (retval
!= MPLS_SUCCESS
)
356 case MPLS_LBLMAP_MSGTYPE
:
358 mplsLdpLblMapMsg_t
*map
= &msg
->u
.map
;
361 for (i
= 0; i
< map
->fecTlv
.numberFecElements
; i
++) {
362 fec_tlv2mpls_fec(&map
->fecTlv
, i
, &fec
);
363 if (!(r_attr
= ldp_attr_create(&fec
))) {
364 goto ldp_state_process_error
;
366 MPLS_REFCNT_HOLD(r_attr
);
368 map2attr(map
, r_attr
, LDP_ATTR_ALL
& ~LDP_ATTR_FEC
);
369 f
= ldp_fec_find(g
, &fec
);
370 retval
= ldp_label_mapping_process(g
, s
, a
, e
, r_attr
, f
);
372 MPLS_REFCNT_RELEASE(r_attr
, ldp_attr_delete
);
373 if (retval
!= MPLS_SUCCESS
)
378 case MPLS_LBLABORT_MSGTYPE
:
380 mplsLdpLblAbortMsg_t
*abrt
= &msg
->u
.abort
;
383 for (i
= 0; i
< abrt
->fecTlv
.numberFecElements
; i
++) {
384 fec_tlv2mpls_fec(&abrt
->fecTlv
, i
, &fec
);
385 if (!(r_attr
= ldp_attr_create(&fec
))) {
386 goto ldp_state_process_error
;
389 MPLS_REFCNT_HOLD(r_attr
);
390 abort2attr(abrt
, r_attr
, LDP_ATTR_ALL
& ~LDP_ATTR_FEC
);
391 f
= ldp_fec_find(g
, &fec
);
392 retval
= ldp_label_abort_process(g
, s
, a
, e
, r_attr
, f
);
394 MPLS_REFCNT_RELEASE(r_attr
, ldp_attr_delete
);
395 if (retval
!= MPLS_SUCCESS
)
400 case MPLS_ADDRWITH_MSGTYPE
:
401 case MPLS_ADDR_MSGTYPE
:
403 retval
= ldp_addr_process(g
, s
, e
, msg
);
413 LDP_EXIT(g
->user_data
, "ldp_state_process");
417 ldp_state_process_error
:
419 LDP_EXIT(g
->user_data
, "ldp_state_process");
421 s
->shutdown_notif
= LDP_NOTIF_INTERNAL_ERROR
;
422 s
->shutdown_fatal
= MPLS_BOOL_TRUE
;
426 mpls_return_enum
ldp_state_ignore(ldp_global
* g
, ldp_session
* session
,
427 ldp_adj
* adj
, ldp_entity
* entity
, uint32_t event
, ldp_mesg
* msg
,
433 mpls_return_enum
ldp_state_close(ldp_global
* g
, ldp_session
* s
, ldp_adj
* a
,
434 ldp_entity
* e
, uint32_t event
, ldp_mesg
* msg
, mpls_dest
* from
)
437 LDP_ENTER(g
->user_data
, "ldp_state_close: a = %p, e = %p s = %p",a
,e
,s
);
439 /* JLEU: this need more work */
441 /* not sure why we got here but we should tear it completely down */
442 if (s
->shutdown_fatal
!= MPLS_BOOL_TRUE
) {
443 ldp_notif_send(g
,s
,NULL
,s
->shutdown_notif
);
445 ldp_session_shutdown(g
, s
, MPLS_BOOL_TRUE
);
448 LDP_EXIT(g
->user_data
, "ldp_state_close");
452 mpls_return_enum
ldp_state_keepalive_maintainance(ldp_global
* g
,
453 ldp_session
* s
, ldp_adj
* a
, ldp_entity
* e
, uint32_t event
, ldp_mesg
* msg
,
456 mpls_return_enum result
;
460 LDP_ENTER(g
->user_data
, "ldp_state_keepalive_maintainance");
461 result
= ldp_session_maintain_timer(g
, s
, LDP_KEEPALIVE_RECV
);
463 LDP_EXIT(g
->user_data
, "ldp_state_keepalive_maintainance");
468 mpls_return_enum
ldp_state_notif(ldp_global
* g
, ldp_session
* s
, ldp_adj
* adj
,
469 ldp_entity
* entity
, uint32_t event
, ldp_mesg
* msg
, mpls_dest
* from
)
472 mpls_return_enum retval
= MPLS_SUCCESS
;
473 ldp_attr
*r_attr
= NULL
;
474 mplsLdpNotifMsg_t
*not = &msg
->u
.notif
;
476 MPLS_ASSERT(s
&& msg
);
478 LDP_ENTER(g
->user_data
, "ldp_state_notif");
480 if (!(r_attr
= ldp_attr_create(NULL
))) {
481 retval
= MPLS_FAILURE
;
482 goto ldp_state_notif_end
;
485 MPLS_REFCNT_HOLD(r_attr
);
487 not2attr(not, r_attr
, LDP_ATTR_ALL
);
488 retval
= ldp_notif_process(g
, s
, adj
, entity
, r_attr
);
490 MPLS_REFCNT_RELEASE(r_attr
, ldp_attr_delete
);
494 LDP_EXIT(g
->user_data
, "ldp_state_notif");