Mercurial > hg > freeDiameter
comparison libfdcore/messages.c @ 1383:0d71c0b2eed4
Be loud, but don't exit on invalid mandatory AVP in Answer
author | Thomas Klausner <tk@giga.or.at> |
---|---|
date | Mon, 08 Jul 2019 17:46:51 +0200 |
parents | 10143e09abdf |
children | b09f1b4c9fad |
comparison
equal
deleted
inserted
replaced
1382:f62e18dc4800 | 1383:0d71c0b2eed4 |
---|---|
50 | 50 |
51 /* Resolve the dictionary objects */ | 51 /* Resolve the dictionary objects */ |
52 int fd_msg_init(void) | 52 int fd_msg_init(void) |
53 { | 53 { |
54 TRACE_ENTRY(""); | 54 TRACE_ENTRY(""); |
55 | 55 |
56 /* Initialize the dictionary objects that we may use frequently */ | 56 /* Initialize the dictionary objects that we may use frequently */ |
57 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Session-Id", &dict_avp_SI , ENOENT) ); | 57 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Session-Id", &dict_avp_SI , ENOENT) ); |
58 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-Host", &dict_avp_OH , ENOENT) ); | 58 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-Host", &dict_avp_OH , ENOENT) ); |
59 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-Realm", &dict_avp_OR , ENOENT) ); | 59 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-Realm", &dict_avp_OR , ENOENT) ); |
60 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-State-Id", &fd_dict_avp_OSI , ENOENT) ); | 60 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-State-Id", &fd_dict_avp_OSI , ENOENT) ); |
61 | 61 |
62 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Result-Code", &dict_avp_RC , ENOENT) ); | 62 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Result-Code", &dict_avp_RC , ENOENT) ); |
63 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Error-Message", &dict_avp_EM , ENOENT) ); | 63 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Error-Message", &dict_avp_EM , ENOENT) ); |
64 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Error-Reporting-Host", &dict_avp_ERH , ENOENT) ); | 64 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Error-Reporting-Host", &dict_avp_ERH , ENOENT) ); |
65 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Failed-AVP", &dict_avp_FAVP, ENOENT) ); | 65 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Failed-AVP", &dict_avp_FAVP, ENOENT) ); |
66 | 66 |
67 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Disconnect-Cause", &fd_dict_avp_DC , ENOENT) ); | 67 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Disconnect-Cause", &fd_dict_avp_DC , ENOENT) ); |
68 | 68 |
69 CHECK_FCT( fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Capabilities-Exchange-Request", &fd_dict_cmd_CER, ENOENT ) ); | 69 CHECK_FCT( fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Capabilities-Exchange-Request", &fd_dict_cmd_CER, ENOENT ) ); |
70 CHECK_FCT( fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Device-Watchdog-Request", &fd_dict_cmd_DWR, ENOENT ) ); | 70 CHECK_FCT( fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Device-Watchdog-Request", &fd_dict_cmd_DWR, ENOENT ) ); |
71 CHECK_FCT( fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Disconnect-Peer-Request", &fd_dict_cmd_DPR, ENOENT ) ); | 71 CHECK_FCT( fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Disconnect-Peer-Request", &fd_dict_cmd_DPR, ENOENT ) ); |
72 | 72 |
73 | 73 |
74 return 0; | 74 return 0; |
75 } | 75 } |
76 | 76 |
77 /* Add Origin-Host, Origin-Realm, Origin-State-Id AVPS at the end of the message */ | 77 /* Add Origin-Host, Origin-Realm, Origin-State-Id AVPS at the end of the message */ |
78 int fd_msg_add_origin ( struct msg * msg, int osi ) | 78 int fd_msg_add_origin ( struct msg * msg, int osi ) |
79 { | 79 { |
80 union avp_value val; | 80 union avp_value val; |
81 struct avp * avp_OH = NULL; | 81 struct avp * avp_OH = NULL; |
82 struct avp * avp_OR = NULL; | 82 struct avp * avp_OR = NULL; |
83 struct avp * avp_OSI = NULL; | 83 struct avp * avp_OSI = NULL; |
84 | 84 |
85 TRACE_ENTRY("%p", msg); | 85 TRACE_ENTRY("%p", msg); |
86 CHECK_PARAMS( msg ); | 86 CHECK_PARAMS( msg ); |
87 | 87 |
88 /* Create the Origin-Host AVP */ | 88 /* Create the Origin-Host AVP */ |
89 CHECK_FCT( fd_msg_avp_new( dict_avp_OH, 0, &avp_OH ) ); | 89 CHECK_FCT( fd_msg_avp_new( dict_avp_OH, 0, &avp_OH ) ); |
90 | 90 |
91 /* Set its value */ | 91 /* Set its value */ |
92 memset(&val, 0, sizeof(val)); | 92 memset(&val, 0, sizeof(val)); |
93 val.os.data = (os0_t)fd_g_config->cnf_diamid; | 93 val.os.data = (os0_t)fd_g_config->cnf_diamid; |
94 val.os.len = fd_g_config->cnf_diamid_len; | 94 val.os.len = fd_g_config->cnf_diamid_len; |
95 CHECK_FCT( fd_msg_avp_setvalue( avp_OH, &val ) ); | 95 CHECK_FCT( fd_msg_avp_setvalue( avp_OH, &val ) ); |
96 | 96 |
97 /* Add it to the message */ | 97 /* Add it to the message */ |
98 CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_OH ) ); | 98 CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_OH ) ); |
99 | 99 |
100 | 100 |
101 /* Create the Origin-Realm AVP */ | 101 /* Create the Origin-Realm AVP */ |
102 CHECK_FCT( fd_msg_avp_new( dict_avp_OR, 0, &avp_OR ) ); | 102 CHECK_FCT( fd_msg_avp_new( dict_avp_OR, 0, &avp_OR ) ); |
103 | 103 |
104 /* Set its value */ | 104 /* Set its value */ |
105 memset(&val, 0, sizeof(val)); | 105 memset(&val, 0, sizeof(val)); |
106 val.os.data = (os0_t)fd_g_config->cnf_diamrlm; | 106 val.os.data = (os0_t)fd_g_config->cnf_diamrlm; |
107 val.os.len = fd_g_config->cnf_diamrlm_len; | 107 val.os.len = fd_g_config->cnf_diamrlm_len; |
108 CHECK_FCT( fd_msg_avp_setvalue( avp_OR, &val ) ); | 108 CHECK_FCT( fd_msg_avp_setvalue( avp_OR, &val ) ); |
109 | 109 |
110 /* Add it to the message */ | 110 /* Add it to the message */ |
111 CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_OR ) ); | 111 CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_OR ) ); |
112 | 112 |
113 if (osi) { | 113 if (osi) { |
114 /* Create the Origin-State-Id AVP */ | 114 /* Create the Origin-State-Id AVP */ |
115 CHECK_FCT( fd_msg_avp_new( fd_dict_avp_OSI, 0, &avp_OSI ) ); | 115 CHECK_FCT( fd_msg_avp_new( fd_dict_avp_OSI, 0, &avp_OSI ) ); |
116 | 116 |
117 /* Set its value */ | 117 /* Set its value */ |
120 CHECK_FCT( fd_msg_avp_setvalue( avp_OSI, &val ) ); | 120 CHECK_FCT( fd_msg_avp_setvalue( avp_OSI, &val ) ); |
121 | 121 |
122 /* Add it to the message */ | 122 /* Add it to the message */ |
123 CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_OSI ) ); | 123 CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_OSI ) ); |
124 } | 124 } |
125 | 125 |
126 return 0; | 126 return 0; |
127 } | 127 } |
128 | 128 |
129 /* Create a new Session-Id and add at the beginning of the message. */ | 129 /* Create a new Session-Id and add at the beginning of the message. */ |
130 int fd_msg_new_session( struct msg * msg, os0_t opt, size_t optlen ) | 130 int fd_msg_new_session( struct msg * msg, os0_t opt, size_t optlen ) |
132 union avp_value val; | 132 union avp_value val; |
133 struct avp * avp = NULL; | 133 struct avp * avp = NULL; |
134 struct session * sess = NULL; | 134 struct session * sess = NULL; |
135 os0_t sid; | 135 os0_t sid; |
136 size_t sidlen; | 136 size_t sidlen; |
137 | 137 |
138 TRACE_ENTRY("%p %p %zd", msg, opt, optlen); | 138 TRACE_ENTRY("%p %p %zd", msg, opt, optlen); |
139 CHECK_PARAMS( msg ); | 139 CHECK_PARAMS( msg ); |
140 | 140 |
141 /* Check there is not already a session in the message */ | 141 /* Check there is not already a session in the message */ |
142 CHECK_FCT( fd_msg_sess_get(fd_g_config->cnf_dict, msg, &sess, NULL) ); | 142 CHECK_FCT( fd_msg_sess_get(fd_g_config->cnf_dict, msg, &sess, NULL) ); |
143 CHECK_PARAMS( sess == NULL ); | 143 CHECK_PARAMS( sess == NULL ); |
144 | 144 |
145 /* Ok, now create the session */ | 145 /* Ok, now create the session */ |
146 CHECK_FCT( fd_sess_new ( &sess, fd_g_config->cnf_diamid, fd_g_config->cnf_diamid_len, opt, optlen ) ); | 146 CHECK_FCT( fd_sess_new ( &sess, fd_g_config->cnf_diamid, fd_g_config->cnf_diamid_len, opt, optlen ) ); |
147 CHECK_FCT( fd_sess_getsid( sess, &sid, &sidlen) ); | 147 CHECK_FCT( fd_sess_getsid( sess, &sid, &sidlen) ); |
148 | 148 |
149 /* Create an AVP to hold it */ | 149 /* Create an AVP to hold it */ |
150 CHECK_FCT( fd_msg_avp_new( dict_avp_SI, 0, &avp ) ); | 150 CHECK_FCT( fd_msg_avp_new( dict_avp_SI, 0, &avp ) ); |
151 | 151 |
152 /* Set its value */ | 152 /* Set its value */ |
153 memset(&val, 0, sizeof(val)); | 153 memset(&val, 0, sizeof(val)); |
154 val.os.data = sid; | 154 val.os.data = sid; |
155 val.os.len = sidlen; | 155 val.os.len = sidlen; |
156 CHECK_FCT( fd_msg_avp_setvalue( avp, &val ) ); | 156 CHECK_FCT( fd_msg_avp_setvalue( avp, &val ) ); |
157 | 157 |
158 /* Add it to the message */ | 158 /* Add it to the message */ |
159 CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_FIRST_CHILD, avp ) ); | 159 CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_FIRST_CHILD, avp ) ); |
160 | 160 |
161 /* Save the session associated with the message */ | 161 /* Save the session associated with the message */ |
162 CHECK_FCT( fd_msg_sess_set( msg, sess) ); | 162 CHECK_FCT( fd_msg_sess_set( msg, sess) ); |
163 | 163 |
164 /* Done! */ | 164 /* Done! */ |
165 return 0; | 165 return 0; |
166 } | 166 } |
167 | 167 |
168 | 168 |
175 struct avp * avp_ERH = NULL; | 175 struct avp * avp_ERH = NULL; |
176 struct avp * avp_FAVP= NULL; | 176 struct avp * avp_FAVP= NULL; |
177 uint32_t rc_val = 0; | 177 uint32_t rc_val = 0; |
178 int set_e_bit=0; | 178 int set_e_bit=0; |
179 int std_err_msg=0; | 179 int std_err_msg=0; |
180 | 180 |
181 TRACE_ENTRY("%p %s %p %p %d", msg, rescode, errormsg, optavp, type_id); | 181 TRACE_ENTRY("%p %s %p %p %d", msg, rescode, errormsg, optavp, type_id); |
182 | 182 |
183 CHECK_PARAMS( msg && rescode ); | 183 CHECK_PARAMS( msg && rescode ); |
184 | 184 |
185 /* Find the enum value corresponding to the rescode string, this will give the class of error */ | 185 /* Find the enum value corresponding to the rescode string, this will give the class of error */ |
186 { | 186 { |
187 struct dict_object * enum_obj = NULL; | 187 struct dict_object * enum_obj = NULL; |
188 struct dict_enumval_request req; | 188 struct dict_enumval_request req; |
189 memset(&req, 0, sizeof(struct dict_enumval_request)); | 189 memset(&req, 0, sizeof(struct dict_enumval_request)); |
190 | 190 |
191 /* First, get the enumerated type of the Result-Code AVP (this is fast, no need to cache the object) */ | 191 /* First, get the enumerated type of the Result-Code AVP (this is fast, no need to cache the object) */ |
192 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_TYPE, TYPE_OF_AVP, dict_avp_RC, &(req.type_obj), ENOENT ) ); | 192 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_TYPE, TYPE_OF_AVP, dict_avp_RC, &(req.type_obj), ENOENT ) ); |
193 | 193 |
194 /* Now search for the value given as parameter */ | 194 /* Now search for the value given as parameter */ |
195 req.search.enum_name = rescode; | 195 req.search.enum_name = rescode; |
196 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &req, &enum_obj, ENOTSUP) ); | 196 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &req, &enum_obj, ENOTSUP) ); |
197 | 197 |
198 /* finally retrieve its data */ | 198 /* finally retrieve its data */ |
199 CHECK_FCT_DO( fd_dict_getval( enum_obj, &(req.search) ), return EINVAL ); | 199 CHECK_FCT_DO( fd_dict_getval( enum_obj, &(req.search) ), return EINVAL ); |
200 | 200 |
201 /* copy the found value, we're done */ | 201 /* copy the found value, we're done */ |
202 rc_val = req.search.enum_value.u32; | 202 rc_val = req.search.enum_value.u32; |
203 } | 203 } |
204 | 204 |
205 if (type_id == 1) { | 205 if (type_id == 1) { |
206 /* Add the Origin-Host and Origin-Realm AVP */ | 206 /* Add the Origin-Host and Origin-Realm AVP */ |
207 CHECK_FCT( fd_msg_add_origin ( msg, 0 ) ); | 207 CHECK_FCT( fd_msg_add_origin ( msg, 0 ) ); |
208 } | 208 } |
209 | 209 |
210 /* Create the Result-Code AVP */ | 210 /* Create the Result-Code AVP */ |
211 CHECK_FCT( fd_msg_avp_new( dict_avp_RC, 0, &avp_RC ) ); | 211 CHECK_FCT( fd_msg_avp_new( dict_avp_RC, 0, &avp_RC ) ); |
212 | 212 |
213 /* Set its value */ | 213 /* Set its value */ |
214 memset(&val, 0, sizeof(val)); | 214 memset(&val, 0, sizeof(val)); |
215 val.u32 = rc_val; | 215 val.u32 = rc_val; |
216 CHECK_FCT( fd_msg_avp_setvalue( avp_RC, &val ) ); | 216 CHECK_FCT( fd_msg_avp_setvalue( avp_RC, &val ) ); |
217 | 217 |
218 /* Add it to the message */ | 218 /* Add it to the message */ |
219 CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_RC ) ); | 219 CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_RC ) ); |
220 | 220 |
221 if (type_id == 2) { | 221 if (type_id == 2) { |
222 /* Add the Error-Reporting-Host AVP */ | 222 /* Add the Error-Reporting-Host AVP */ |
223 | 223 |
224 CHECK_FCT( fd_msg_avp_new( dict_avp_ERH, 0, &avp_ERH ) ); | 224 CHECK_FCT( fd_msg_avp_new( dict_avp_ERH, 0, &avp_ERH ) ); |
225 | 225 |
226 /* Set its value */ | 226 /* Set its value */ |
227 memset(&val, 0, sizeof(val)); | 227 memset(&val, 0, sizeof(val)); |
228 val.os.data = (uint8_t *)fd_g_config->cnf_diamid; | 228 val.os.data = (uint8_t *)fd_g_config->cnf_diamid; |
229 val.os.len = fd_g_config->cnf_diamid_len; | 229 val.os.len = fd_g_config->cnf_diamid_len; |
230 CHECK_FCT( fd_msg_avp_setvalue( avp_ERH, &val ) ); | 230 CHECK_FCT( fd_msg_avp_setvalue( avp_ERH, &val ) ); |
231 | 231 |
232 /* Add it to the message */ | 232 /* Add it to the message */ |
233 CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_ERH ) ); | 233 CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_ERH ) ); |
234 | 234 |
235 } | 235 } |
236 | 236 |
237 /* Now add the optavp in a FailedAVP if provided */ | 237 /* Now add the optavp in a FailedAVP if provided */ |
238 if (optavp) { | 238 if (optavp) { |
239 struct avp * optavp_cpy = NULL; | 239 struct avp * optavp_cpy = NULL; |
240 struct avp_hdr *opt_hdr, *optcpy_hdr; | 240 struct avp_hdr *opt_hdr, *optcpy_hdr; |
241 struct dict_object * opt_model = NULL; | 241 struct dict_object * opt_model = NULL; |
242 int is_grouped = 0; | 242 int is_grouped = 0; |
243 | 243 |
244 /* Create the Failed-AVP AVP */ | 244 /* Create the Failed-AVP AVP */ |
245 CHECK_FCT( fd_msg_avp_new( dict_avp_FAVP, 0, &avp_FAVP ) ); | 245 CHECK_FCT( fd_msg_avp_new( dict_avp_FAVP, 0, &avp_FAVP ) ); |
246 | 246 |
247 /* Was this AVP a grouped one? Best effort only here */ | 247 /* Was this AVP a grouped one? Best effort only here */ |
248 if (!fd_msg_model ( optavp, &opt_model ) && (opt_model != NULL)) { | 248 if (!fd_msg_model ( optavp, &opt_model ) && (opt_model != NULL)) { |
249 struct dict_avp_data dictdata; | 249 struct dict_avp_data dictdata; |
250 CHECK_FCT( fd_dict_getval(opt_model, &dictdata) ); | 250 CHECK_FCT( fd_dict_getval(opt_model, &dictdata) ); |
251 if (dictdata.avp_basetype == AVP_TYPE_GROUPED) | 251 if (dictdata.avp_basetype == AVP_TYPE_GROUPED) |
252 is_grouped = 1; | 252 is_grouped = 1; |
253 } | 253 } |
254 | 254 |
255 /* Create a new AVP with a copy of the data of the invalid or missing AVP */ | 255 /* Create a new AVP with a copy of the data of the invalid or missing AVP */ |
256 optavp_cpy = optavp; | 256 optavp_cpy = optavp; |
257 | 257 |
258 if (is_grouped) { | 258 if (is_grouped) { |
259 CHECK_FCT( fd_msg_avp_new( opt_model, 0, &optavp_cpy) ); | 259 CHECK_FCT( fd_msg_avp_new( opt_model, 0, &optavp_cpy) ); |
260 } else { | 260 } else { |
261 CHECK_FCT( fd_msg_avp_new( NULL, AVPFL_SET_BLANK_VALUE | AVPFL_SET_RAWDATA_FROM_AVP, &optavp_cpy) ); | 261 CHECK_FCT( fd_msg_avp_new( NULL, AVPFL_SET_BLANK_VALUE | AVPFL_SET_RAWDATA_FROM_AVP, &optavp_cpy) ); |
262 | 262 |
263 CHECK_FCT( fd_msg_avp_hdr(optavp, &opt_hdr) ); | 263 CHECK_FCT( fd_msg_avp_hdr(optavp, &opt_hdr) ); |
264 CHECK_FCT( fd_msg_avp_hdr(optavp_cpy, &optcpy_hdr) ); | 264 CHECK_FCT( fd_msg_avp_hdr(optavp_cpy, &optcpy_hdr) ); |
265 memcpy(optcpy_hdr, opt_hdr, sizeof(struct avp_hdr)); | 265 memcpy(optcpy_hdr, opt_hdr, sizeof(struct avp_hdr)); |
266 } | 266 } |
267 | 267 |
268 /* Add the passed AVP inside it */ | 268 /* Add the passed AVP inside it */ |
269 CHECK_FCT( fd_msg_avp_add( avp_FAVP, MSG_BRW_LAST_CHILD, optavp_cpy ) ); | 269 CHECK_FCT( fd_msg_avp_add( avp_FAVP, MSG_BRW_LAST_CHILD, optavp_cpy ) ); |
270 | 270 |
271 /* And add to the message */ | 271 /* And add to the message */ |
272 CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_FAVP ) ); | 272 CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_FAVP ) ); |
273 } | 273 } |
274 | 274 |
275 | 275 |
276 /* Deal with the 'E' bit and the error message */ | 276 /* Deal with the 'E' bit and the error message */ |
277 switch (rc_val / 1000) { | 277 switch (rc_val / 1000) { |
278 case 1: /* Informational */ | 278 case 1: /* Informational */ |
279 case 2: /* Success */ | 279 case 2: /* Success */ |
280 /* Nothing special here: no E bit, no error message unless one is specified */ | 280 /* Nothing special here: no E bit, no error message unless one is specified */ |
281 break; | 281 break; |
282 | 282 |
283 case 3: /* Protocol Errors */ | 283 case 3: /* Protocol Errors */ |
284 set_e_bit = 1; | 284 set_e_bit = 1; |
285 std_err_msg = 1; | 285 std_err_msg = 1; |
286 break; | 286 break; |
287 | 287 |
288 case 4: /* Transcient Failure */ | 288 case 4: /* Transcient Failure */ |
289 case 5: /* Permanent Failure */ | 289 case 5: /* Permanent Failure */ |
290 if (rc_val == 5017) /* DIAMETER_NO_COMMON_SECURITY */ { | 290 if (rc_val == 5017) /* DIAMETER_NO_COMMON_SECURITY */ { |
291 set_e_bit = 1; | 291 set_e_bit = 1; |
292 } | 292 } |
293 default: | 293 default: |
294 std_err_msg = 1; | 294 std_err_msg = 1; |
295 break; | 295 break; |
296 | 296 |
297 } | 297 } |
298 | 298 |
299 { | 299 { |
300 struct msg_hdr * hdr = NULL; | 300 struct msg_hdr * hdr = NULL; |
301 | 301 |
302 CHECK_FCT( fd_msg_hdr( msg, &hdr ) ); | 302 CHECK_FCT( fd_msg_hdr( msg, &hdr ) ); |
303 | 303 |
304 if (set_e_bit) | 304 if (set_e_bit) |
305 hdr->msg_flags |= CMD_FLAG_ERROR; | 305 hdr->msg_flags |= CMD_FLAG_ERROR; |
306 else | 306 else |
307 hdr->msg_flags &= ~ CMD_FLAG_ERROR; | 307 hdr->msg_flags &= ~ CMD_FLAG_ERROR; |
308 } | 308 } |
309 | 309 |
310 if (std_err_msg || errormsg) { | 310 if (std_err_msg || errormsg) { |
311 /* Add the Error-Message AVP */ | 311 /* Add the Error-Message AVP */ |
312 | 312 |
313 CHECK_FCT( fd_msg_avp_new( dict_avp_EM, 0, &avp_EM ) ); | 313 CHECK_FCT( fd_msg_avp_new( dict_avp_EM, 0, &avp_EM ) ); |
314 | 314 |
315 /* Set its value */ | 315 /* Set its value */ |
316 memset(&val, 0, sizeof(val)); | 316 memset(&val, 0, sizeof(val)); |
317 | 317 |
318 if (errormsg) { | 318 if (errormsg) { |
319 val.os.data = (uint8_t *)errormsg; | 319 val.os.data = (uint8_t *)errormsg; |
320 val.os.len = strlen(errormsg); | 320 val.os.len = strlen(errormsg); |
321 } else { | 321 } else { |
322 val.os.data = (uint8_t *)rescode; | 322 val.os.data = (uint8_t *)rescode; |
325 CHECK_FCT( fd_msg_avp_setvalue( avp_EM, &val ) ); | 325 CHECK_FCT( fd_msg_avp_setvalue( avp_EM, &val ) ); |
326 | 326 |
327 /* Add it to the message */ | 327 /* Add it to the message */ |
328 CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_EM ) ); | 328 CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_EM ) ); |
329 } | 329 } |
330 | 330 |
331 return 0; | 331 return 0; |
332 } | 332 } |
333 | 333 |
334 static int fd_msg_send_int( struct msg ** pmsg, void (*anscb)(void *, struct msg **), void * data, void (*expirecb)(void *, DiamId_t, size_t, struct msg **), const struct timespec *timeout ) | 334 static int fd_msg_send_int( struct msg ** pmsg, void (*anscb)(void *, struct msg **), void * data, void (*expirecb)(void *, DiamId_t, size_t, struct msg **), const struct timespec *timeout ) |
335 { | 335 { |
336 struct msg_hdr *hdr; | 336 struct msg_hdr *hdr; |
337 DiamId_t diamid; | 337 DiamId_t diamid; |
338 | 338 |
339 /* Save the callback in the message, with the timeout */ | 339 /* Save the callback in the message, with the timeout */ |
340 CHECK_FCT( fd_msg_anscb_associate( *pmsg, anscb, data, expirecb, timeout ) ); | 340 CHECK_FCT( fd_msg_anscb_associate( *pmsg, anscb, data, expirecb, timeout ) ); |
341 | 341 |
342 /* If this is a new request, call the HOOK_MESSAGE_LOCAL hook */ | 342 /* If this is a new request, call the HOOK_MESSAGE_LOCAL hook */ |
343 if ( (fd_msg_hdr(*pmsg, &hdr) == 0) | 343 if ( (fd_msg_hdr(*pmsg, &hdr) == 0) |
344 && (hdr->msg_flags & CMD_FLAG_REQUEST) | 344 && (hdr->msg_flags & CMD_FLAG_REQUEST) |
345 && (fd_msg_source_get(*pmsg, &diamid, NULL) == 0) | 345 && (fd_msg_source_get(*pmsg, &diamid, NULL) == 0) |
346 && (diamid == NULL)) { | 346 && (diamid == NULL)) { |
347 fd_hook_call(HOOK_MESSAGE_LOCAL, *pmsg, NULL, NULL, fd_msg_pmdl_get(*pmsg)); | 347 fd_hook_call(HOOK_MESSAGE_LOCAL, *pmsg, NULL, NULL, fd_msg_pmdl_get(*pmsg)); |
348 } | 348 } |
349 | 349 |
350 /* Post the message in the outgoing queue */ | 350 /* Post the message in the outgoing queue */ |
351 CHECK_FCT( fd_fifo_post(fd_g_outgoing, pmsg) ); | 351 CHECK_FCT( fd_fifo_post(fd_g_outgoing, pmsg) ); |
352 | 352 |
353 return 0; | 353 return 0; |
354 } | 354 } |
355 | 355 |
356 /* Send a message and optionally register a callback for an answer */ | 356 /* Send a message and optionally register a callback for an answer */ |
357 int fd_msg_send ( struct msg ** pmsg, void (*anscb)(void *, struct msg **), void * data ) | 357 int fd_msg_send ( struct msg ** pmsg, void (*anscb)(void *, struct msg **), void * data ) |
358 { | 358 { |
359 TRACE_ENTRY("%p %p %p", pmsg, anscb, data); | 359 TRACE_ENTRY("%p %p %p", pmsg, anscb, data); |
360 CHECK_PARAMS( pmsg ); | 360 CHECK_PARAMS( pmsg ); |
361 | 361 |
362 return fd_msg_send_int(pmsg, anscb, data, NULL, NULL); | 362 return fd_msg_send_int(pmsg, anscb, data, NULL, NULL); |
363 } | 363 } |
364 | 364 |
365 /* The variation of the same function with a timeout callback */ | 365 /* The variation of the same function with a timeout callback */ |
366 int fd_msg_send_timeout ( struct msg ** pmsg, void (*anscb)(void *, struct msg **), void * data, void (*expirecb)(void *, DiamId_t, size_t, struct msg **), const struct timespec *timeout ) | 366 int fd_msg_send_timeout ( struct msg ** pmsg, void (*anscb)(void *, struct msg **), void * data, void (*expirecb)(void *, DiamId_t, size_t, struct msg **), const struct timespec *timeout ) |
367 { | 367 { |
368 TRACE_ENTRY("%p %p %p %p %p", pmsg, anscb, data, expirecb, timeout); | 368 TRACE_ENTRY("%p %p %p %p %p", pmsg, anscb, data, expirecb, timeout); |
369 CHECK_PARAMS( pmsg && expirecb && timeout ); | 369 CHECK_PARAMS( pmsg && expirecb && timeout ); |
370 | 370 |
371 return fd_msg_send_int(pmsg, anscb, data, expirecb, timeout); | 371 return fd_msg_send_int(pmsg, anscb, data, expirecb, timeout); |
372 } | 372 } |
373 | 373 |
374 | 374 |
375 /* Parse a message against our dictionary, and in case of error log and eventually build the error reply -- returns the parsing status */ | 375 /* Parse a message against our dictionary, and in case of error log and eventually build the error reply -- returns the parsing status */ |
377 { | 377 { |
378 int ret = 0; | 378 int ret = 0; |
379 struct msg * m; | 379 struct msg * m; |
380 struct msg_hdr * hdr = NULL; | 380 struct msg_hdr * hdr = NULL; |
381 struct fd_pei pei; | 381 struct fd_pei pei; |
382 | 382 |
383 TRACE_ENTRY("%p", msg); | 383 TRACE_ENTRY("%p", msg); |
384 | 384 |
385 CHECK_PARAMS(msg && *msg && error); | 385 CHECK_PARAMS(msg && *msg && error); |
386 m = *msg; | 386 m = *msg; |
387 *error = NULL; | 387 *error = NULL; |
388 | 388 |
389 /* Parse the message against our dictionary */ | 389 /* Parse the message against our dictionary */ |
390 ret = fd_msg_parse_rules ( m, fd_g_config->cnf_dict, &pei); | 390 ret = fd_msg_parse_rules ( m, fd_g_config->cnf_dict, &pei); |
391 if ((ret != EBADMSG) /* Parsing grouped AVP failed / Conflicting rule found */ | 391 if ((ret != EBADMSG) /* Parsing grouped AVP failed / Conflicting rule found */ |
392 && (ret != ENOTSUP)) /* Command is not supported / Mandatory AVP is not supported */ | 392 && (ret != ENOTSUP)) /* Command is not supported / Mandatory AVP is not supported */ |
393 return ret; /* 0 or another error */ | 393 return ret; /* 0 or another error */ |
394 | 394 |
395 /* Log */ | 395 /* Log */ |
396 fd_hook_call(HOOK_MESSAGE_PARSING_ERROR, m, NULL, pei.pei_message ?: pei.pei_errcode, fd_msg_pmdl_get(m)); | 396 fd_hook_call(HOOK_MESSAGE_PARSING_ERROR, m, NULL, pei.pei_message ?: pei.pei_errcode, fd_msg_pmdl_get(m)); |
397 | 397 |
398 CHECK_FCT( fd_msg_hdr(m, &hdr) ); | 398 CHECK_FCT( fd_msg_hdr(m, &hdr) ); |
399 | 399 |
400 /* Now create an answer error if the message is a query */ | 400 /* Now create an answer error if the message is a query */ |
401 if (hdr->msg_flags & CMD_FLAG_REQUEST) { | 401 if (hdr->msg_flags & CMD_FLAG_REQUEST) { |
402 | 402 |
403 /* Create the error message */ | 403 /* Create the error message */ |
404 CHECK_FCT( fd_msg_new_answer_from_req ( fd_g_config->cnf_dict, &m, pei.pei_protoerr ? MSGFL_ANSW_ERROR : 0 ) ); | 404 CHECK_FCT( fd_msg_new_answer_from_req ( fd_g_config->cnf_dict, &m, pei.pei_protoerr ? MSGFL_ANSW_ERROR : 0 ) ); |
405 | 405 |
406 /* Set the error code */ | 406 /* Set the error code */ |
407 CHECK_FCT( fd_msg_rescode_set(m, pei.pei_errcode, pei.pei_message, pei.pei_avp, 1 ) ); | 407 CHECK_FCT( fd_msg_rescode_set(m, pei.pei_errcode, pei.pei_message, pei.pei_avp, 1 ) ); |
408 | 408 |
409 /* free the pei AVP to avoid memory leak */ | 409 /* free the pei AVP to avoid memory leak */ |
410 if (pei.pei_avp_free) { | 410 if (pei.pei_avp_free) { |
411 fd_msg_free(pei.pei_avp); | 411 fd_msg_free(pei.pei_avp); |
412 } | 412 } |
413 | 413 |
414 *msg = NULL; | 414 *msg = NULL; |
415 *error = m; | 415 *error = m; |
416 | 416 |
417 } else { | 417 } else { |
418 do { /* Rescue error messages */ | 418 do { /* Rescue error messages */ |
419 struct avp * avp; | 419 struct avp * avp; |
420 union avp_value * rc = NULL; | 420 union avp_value * rc = NULL; |
421 | 421 |
422 /* Search the Result-Code AVP */ | 422 /* Search the Result-Code AVP */ |
423 CHECK_FCT_DO( fd_msg_browse(*msg, MSG_BRW_FIRST_CHILD, &avp, NULL), break ); | 423 CHECK_FCT_DO( fd_msg_browse(*msg, MSG_BRW_FIRST_CHILD, &avp, NULL), break ); |
424 while (avp) { | 424 while (avp) { |
425 struct avp_hdr * ahdr; | 425 struct avp_hdr * ahdr; |
426 CHECK_FCT_DO( fd_msg_avp_hdr( avp, &ahdr ), break ); | 426 CHECK_FCT_DO( fd_msg_avp_hdr( avp, &ahdr ), break ); |
427 | 427 |
428 if ((ahdr->avp_code == AC_RESULT_CODE) && (! (ahdr->avp_flags & AVP_FLAG_VENDOR)) ) { | 428 if ((ahdr->avp_code == AC_RESULT_CODE) && (! (ahdr->avp_flags & AVP_FLAG_VENDOR)) ) { |
429 /* Parse this AVP */ | 429 /* Parse this AVP */ |
430 ASSERT( ahdr->avp_value ); | 430 if (fd_msg_parse_dict(avp, fd_g_config->cnf_dict, &pei) < 0) { |
431 TRACE_DEBUG(INFO, "error parsing Result-Code AVP"); | |
432 rc = NULL; | |
433 break; | |
434 } | |
431 rc = ahdr->avp_value; | 435 rc = ahdr->avp_value; |
436 if (rc == NULL) { | |
437 TRACE_DEBUG(INFO, "invalid Result-Code AVP"); | |
438 break; | |
439 } | |
432 break; | 440 break; |
433 } | 441 } |
434 | 442 |
435 /* Go to next AVP */ | 443 /* Go to next AVP */ |
436 CHECK_FCT_DO( fd_msg_browse(avp, MSG_BRW_NEXT, &avp, NULL), break ); | 444 CHECK_FCT_DO( fd_msg_browse(avp, MSG_BRW_NEXT, &avp, NULL), break ); |
437 } | 445 } |
438 | 446 |
439 if (rc) { | 447 if (rc) { |
440 switch (rc->u32 / 1000) { | 448 switch (rc->u32 / 1000) { |
441 case 1: /* 1xxx : Informational */ | 449 case 1: /* 1xxx : Informational */ |
442 case 2: /* 2xxx : Sucess */ | 450 case 2: /* 2xxx : Sucess */ |
443 /* In these cases, we want the message to validate the ABNF, so we will discard the bad message */ | 451 /* In these cases, we want the message to validate the ABNF, so we will discard the bad message */ |
444 break; | 452 break; |
445 | 453 |
446 default: /* Other errors */ | 454 default: /* Other errors */ |
447 /* We let the application decide what to do with the message, we rescue it */ | 455 /* We let the application decide what to do with the message, we rescue it */ |
448 *error = m; | 456 *error = m; |
449 } | 457 } |
450 } | 458 } |
451 } while (0); | 459 } while (0); |
452 } | 460 } |
453 | 461 |
454 return EBADMSG; /* We convert ENOTSUP to EBADMSG as well */ | 462 return EBADMSG; /* We convert ENOTSUP to EBADMSG as well */ |
455 } | 463 } |