1 | /********************************************************************************************************* |
---|
2 | * Software License Agreement (BSD License) * |
---|
3 | * Author: Sebastien Decugis <sdecugis@nict.go.jp> * |
---|
4 | * * |
---|
5 | * Copyright (c) 2011, WIDE Project and NICT * |
---|
6 | * All rights reserved. * |
---|
7 | * * |
---|
8 | * Redistribution and use of this software in source and binary forms, with or without modification, are * |
---|
9 | * permitted provided that the following conditions are met: * |
---|
10 | * * |
---|
11 | * * Redistributions of source code must retain the above * |
---|
12 | * copyright notice, this list of conditions and the * |
---|
13 | * following disclaimer. * |
---|
14 | * * |
---|
15 | * * Redistributions in binary form must reproduce the above * |
---|
16 | * copyright notice, this list of conditions and the * |
---|
17 | * following disclaimer in the documentation and/or other * |
---|
18 | * materials provided with the distribution. * |
---|
19 | * * |
---|
20 | * * Neither the name of the WIDE Project or NICT nor the * |
---|
21 | * names of its contributors may be used to endorse or * |
---|
22 | * promote products derived from this software without * |
---|
23 | * specific prior written permission of WIDE Project and * |
---|
24 | * NICT. * |
---|
25 | * * |
---|
26 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED * |
---|
27 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * |
---|
28 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * |
---|
29 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * |
---|
30 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * |
---|
31 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * |
---|
32 | * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * |
---|
33 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * |
---|
34 | *********************************************************************************************************/ |
---|
35 | |
---|
36 | #include "fdcore-internal.h" |
---|
37 | |
---|
38 | /* This file contains code to handle Device Watchdog messages (DWR and DWA) */ |
---|
39 | |
---|
40 | /* Check the value of Origin-State-Id is consistent in a DWR or DWA -- we just log if it is not the case */ |
---|
41 | static void check_state_id(struct msg * msg, struct fd_peer * peer) |
---|
42 | { |
---|
43 | struct avp * osi; |
---|
44 | /* Check if the request contains the Origin-State-Id */ |
---|
45 | CHECK_FCT_DO( fd_msg_search_avp ( msg, fd_dict_avp_OSI, &osi ), return ); |
---|
46 | if (osi) { |
---|
47 | /* Check the value is consistent with the saved one */ |
---|
48 | struct avp_hdr * hdr; |
---|
49 | CHECK_FCT_DO( fd_msg_avp_hdr( osi, &hdr ), return ); |
---|
50 | if (hdr->avp_value == NULL) { |
---|
51 | /* This is a sanity check */ |
---|
52 | TRACE_DEBUG(NONE, "BUG: Unset value in Origin-State-Id in DWR / DWA"); |
---|
53 | fd_msg_dump_one(NONE, osi); |
---|
54 | ASSERT(0); /* To check if this really happens, and understand why... */ |
---|
55 | } |
---|
56 | |
---|
57 | if (peer->p_hdr.info.runtime.pir_orstate != hdr->avp_value->u32) { |
---|
58 | fd_log_debug("Received a new Origin-State-Id from peer %s! (%x / %x)\n", |
---|
59 | peer->p_hdr.info.pi_diamid, |
---|
60 | hdr->avp_value->u32, |
---|
61 | peer->p_hdr.info.runtime.pir_orstate ); |
---|
62 | } |
---|
63 | } |
---|
64 | } |
---|
65 | |
---|
66 | /* Create and send a DWR */ |
---|
67 | static int send_DWR(struct fd_peer * peer) |
---|
68 | { |
---|
69 | struct msg * msg = NULL; |
---|
70 | |
---|
71 | /* Create a new DWR instance */ |
---|
72 | CHECK_FCT( fd_msg_new ( fd_dict_cmd_DWR, MSGFL_ALLOC_ETEID, &msg ) ); |
---|
73 | |
---|
74 | /* Add the content of the message (only the origin) */ |
---|
75 | CHECK_FCT( fd_msg_add_origin ( msg, 1 ) ); |
---|
76 | |
---|
77 | /* Now send this message */ |
---|
78 | CHECK_FCT( fd_out_send(&msg, NULL, peer, FD_CNX_ORDERED) ); |
---|
79 | |
---|
80 | /* And mark the pending DW */ |
---|
81 | peer->p_flags.pf_dw_pending = 1; |
---|
82 | |
---|
83 | return 0; |
---|
84 | } |
---|
85 | |
---|
86 | /* Handle an incoming message */ |
---|
87 | int fd_p_dw_handle(struct msg ** msg, int req, struct fd_peer * peer) |
---|
88 | { |
---|
89 | int reset_tmr = 0; |
---|
90 | |
---|
91 | TRACE_ENTRY("%p %d %p", msg, req, peer); |
---|
92 | |
---|
93 | /* Check the value of OSI for information */ |
---|
94 | check_state_id(*msg, peer); |
---|
95 | |
---|
96 | if (req) { |
---|
97 | /* If we receive a DWR, send back a DWA */ |
---|
98 | CHECK_FCT( fd_msg_new_answer_from_req ( fd_g_config->cnf_dict, msg, 0 ) ); |
---|
99 | CHECK_FCT( fd_msg_rescode_set( *msg, "DIAMETER_SUCCESS", NULL, NULL, 0 ) ); |
---|
100 | CHECK_FCT( fd_msg_add_origin ( *msg, 1 ) ); |
---|
101 | CHECK_FCT( fd_out_send( msg, peer->p_cnxctx, peer, FD_CNX_ORDERED) ); |
---|
102 | |
---|
103 | } else { |
---|
104 | /* Just discard the DWA */ |
---|
105 | CHECK_FCT_DO( fd_msg_free(*msg), /* continue */ ); |
---|
106 | *msg = NULL; |
---|
107 | |
---|
108 | /* And clear the pending DW flag */ |
---|
109 | peer->p_flags.pf_dw_pending = 0; |
---|
110 | } |
---|
111 | |
---|
112 | /* Now update timeout */ |
---|
113 | if (req) { |
---|
114 | /* Update timeout only if we did not already send a DWR ourselves */ |
---|
115 | reset_tmr = !peer->p_flags.pf_dw_pending; |
---|
116 | } else { |
---|
117 | /* Reset the timer */ |
---|
118 | reset_tmr = 1; |
---|
119 | } |
---|
120 | if (reset_tmr) { |
---|
121 | fd_psm_next_timeout(peer, 1, peer->p_hdr.info.config.pic_twtimer ?: fd_g_config->cnf_timer_tw); |
---|
122 | } |
---|
123 | |
---|
124 | /* If we are in REOPEN state, increment the counter */ |
---|
125 | fd_cpu_flush_cache(); |
---|
126 | if (peer->p_hdr.info.runtime.pir_state == STATE_REOPEN) { |
---|
127 | peer->p_flags.pf_reopen_cnt += 1; |
---|
128 | |
---|
129 | if (peer->p_flags.pf_reopen_cnt) { |
---|
130 | /* Send a new DWR */ |
---|
131 | CHECK_FCT( send_DWR(peer) ); |
---|
132 | } else { |
---|
133 | /* Move to OPEN state */ |
---|
134 | CHECK_FCT( fd_psm_change_state(peer, STATE_OPEN) ); |
---|
135 | } |
---|
136 | } |
---|
137 | |
---|
138 | return 0; |
---|
139 | } |
---|
140 | |
---|
141 | /* Handle a timeout in the PSM (OPEN or REOPEN state only) */ |
---|
142 | int fd_p_dw_timeout(struct fd_peer * peer) |
---|
143 | { |
---|
144 | TRACE_ENTRY("%p", peer); |
---|
145 | |
---|
146 | if (peer->p_flags.pf_dw_pending) { |
---|
147 | /* We have sent a DWR and received no answer during TwTimer */ |
---|
148 | CHECK_FCT( fd_psm_change_state(peer, STATE_SUSPECT) ); |
---|
149 | fd_psm_next_timeout(peer, 0, 2 * (peer->p_hdr.info.config.pic_twtimer ?: fd_g_config->cnf_timer_tw) ); |
---|
150 | } else { |
---|
151 | /* The timeout has expired, send a DWR */ |
---|
152 | CHECK_FCT( send_DWR(peer) ); |
---|
153 | fd_psm_next_timeout(peer, 0, peer->p_hdr.info.config.pic_twtimer ?: fd_g_config->cnf_timer_tw ); |
---|
154 | } |
---|
155 | |
---|
156 | return 0; |
---|
157 | } |
---|
158 | |
---|
159 | /* Handle DW exchanges after the peer has come alive again */ |
---|
160 | int fd_p_dw_reopen(struct fd_peer * peer) |
---|
161 | { |
---|
162 | TRACE_ENTRY("%p", peer); |
---|
163 | |
---|
164 | peer->p_flags.pf_reopen_cnt = 1; |
---|
165 | peer->p_flags.pf_cnx_pb = 0; |
---|
166 | CHECK_FCT( send_DWR(peer) ); |
---|
167 | |
---|
168 | return 0; |
---|
169 | } |
---|
170 | |
---|
171 | |
---|