PageRenderTime 67ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/epan/dissectors/packet-radius.c

https://gitlab.com/jvelando/wireshark
C | 1551 lines | 1200 code | 258 blank | 93 comment | 218 complexity | 317b8ba479245924762f7e95f8a3caa2 MD5 | raw file
  1. /* packet-radius.c
  2. *
  3. * Routines for RADIUS packet disassembly
  4. * Copyright 1999 Johan Feyaerts
  5. * Changed 03/12/2003 Rui Carmo (http://the.taoofmac.com - added all 3GPP VSAs, some parsing)
  6. * Changed 07/2005 Luis Ontanon <luis@ontanon.org> - use FreeRADIUS' dictionary
  7. * Changed 10/2006 Alejandro Vaquero <alejandrovaquero@yahoo.com> - add Conversations support
  8. * Changed 08/2015 Didier Arenzana <darenzana@yahoo.fr> - add response authenticator validation
  9. *
  10. * Wireshark - Network traffic analyzer
  11. * By Gerald Combs <gerald@wireshark.org>
  12. * Copyright 1998 Gerald Combs
  13. *
  14. * SPDX-License-Identifier: GPL-2.0-or-later
  15. *
  16. * References:
  17. *
  18. * RFC 2865 - Remote Authentication Dial In User Service (RADIUS)
  19. * RFC 2866 - RADIUS Accounting
  20. * RFC 2867 - RADIUS Accounting Modifications for Tunnel Protocol Support
  21. * RFC 2868 - RADIUS Attributes for Tunnel Protocol Support
  22. * RFC 2869 - RADIUS Extensions
  23. * RFC 3162 - RADIUS and IPv6
  24. * RFC 3576 - Dynamic Authorization Extensions to RADIUS
  25. * RFC 6929 - Remote Authentication Dial-In User Service (RADIUS) Protocol Extensions
  26. *
  27. * See also
  28. *
  29. * http://www.iana.org/assignments/radius-types
  30. *
  31. * and see
  32. *
  33. * http://freeradius.org/radiusd/man/dictionary.html
  34. *
  35. * for the dictionary file syntax.
  36. */
  37. /*
  38. TO (re)DO: (see svn rev 14786)
  39. - dissect_3gpp_ipv6_dns_servers()
  40. */
  41. #include "config.h"
  42. #include <stdlib.h>
  43. #include <errno.h>
  44. #include <epan/packet.h>
  45. #include <epan/exceptions.h>
  46. #include <epan/expert.h>
  47. #include <epan/prefs.h>
  48. #include <epan/sminmpec.h>
  49. #include <epan/conversation.h>
  50. #include <epan/tap.h>
  51. #include <epan/rtd_table.h>
  52. #include <epan/addr_resolv.h>
  53. #include <wsutil/filesystem.h>
  54. #include <wsutil/report_message.h>
  55. #include <wsutil/wsgcrypt.h>
  56. #include "packet-radius.h"
  57. #include "packet-e212.h"
  58. void proto_register_radius(void);
  59. void proto_reg_handoff_radius(void);
  60. typedef struct _e_radiushdr {
  61. guint8 rh_code;
  62. guint8 rh_ident;
  63. guint16 rh_pktlength;
  64. } e_radiushdr;
  65. typedef struct {
  66. wmem_array_t *hf;
  67. wmem_array_t *ett;
  68. wmem_array_t *vend_vs;
  69. } hfett_t;
  70. #define AUTHENTICATOR_LENGTH 16
  71. #define RD_HDR_LENGTH 4
  72. #define HDR_LENGTH (RD_HDR_LENGTH + AUTHENTICATOR_LENGTH)
  73. /* Item of request list */
  74. typedef struct _radius_call_t
  75. {
  76. guint code;
  77. guint ident;
  78. guint8 req_authenticator[AUTHENTICATOR_LENGTH];
  79. guint32 req_num; /* frame number request seen */
  80. guint32 rsp_num; /* frame number response seen */
  81. guint32 rspcode;
  82. nstime_t req_time;
  83. gboolean responded;
  84. } radius_call_t;
  85. /* Container for tapping relevant data */
  86. typedef struct _radius_info_t
  87. {
  88. guint code;
  89. guint ident;
  90. nstime_t req_time;
  91. gboolean is_duplicate;
  92. gboolean request_available;
  93. guint32 req_num; /* frame number request seen */
  94. guint32 rspcode;
  95. } radius_info_t;
  96. /*
  97. * Default RADIUS ports:
  98. * 1645 (Authentication, pre RFC 2865)
  99. * 1646 (Accounting, pre RFC 2866)
  100. * 1812 (Authentication, RFC 2865)
  101. * 1813 (Accounting, RFC 2866)
  102. * 1700 (Dynamic Authorization Extensions, pre RFC 3576)
  103. * 3799 (Dynamic Authorization Extensions, RFC 3576)
  104. */
  105. #define DEFAULT_RADIUS_PORT_RANGE "1645,1646,1700,1812,1813,3799"
  106. static radius_dictionary_t *dict = NULL;
  107. static int proto_radius = -1;
  108. static int hf_radius_req = -1;
  109. static int hf_radius_rsp = -1;
  110. static int hf_radius_req_frame = -1;
  111. static int hf_radius_rsp_frame = -1;
  112. static int hf_radius_time = -1;
  113. static int hf_radius_dup = -1;
  114. static int hf_radius_req_dup = -1;
  115. static int hf_radius_rsp_dup = -1;
  116. static int hf_radius_id = -1;
  117. static int hf_radius_code = -1;
  118. static int hf_radius_length = -1;
  119. static int hf_radius_authenticator = -1;
  120. static int hf_radius_authenticator_valid = -1;
  121. static int hf_radius_authenticator_invalid = -1;
  122. static int hf_radius_chap_password = -1;
  123. static int hf_radius_chap_ident = -1;
  124. static int hf_radius_chap_string = -1;
  125. static int hf_radius_framed_ip_address = -1;
  126. static int hf_radius_login_ip_host = -1;
  127. static int hf_radius_framed_ipx_network = -1;
  128. static int hf_radius_cosine_vpi = -1;
  129. static int hf_radius_cosine_vci = -1;
  130. static int hf_radius_ascend_data_filter = -1;
  131. static int hf_radius_ascend_data_filter_type = -1;
  132. static int hf_radius_ascend_data_filter_filteror = -1;
  133. static int hf_radius_ascend_data_filter_inout = -1;
  134. static int hf_radius_ascend_data_filter_spare = -1;
  135. static int hf_radius_ascend_data_filter_src_ipv4 = -1;
  136. static int hf_radius_ascend_data_filter_dst_ipv4 = -1;
  137. static int hf_radius_ascend_data_filter_src_ipv6 = -1;
  138. static int hf_radius_ascend_data_filter_dst_ipv6 = -1;
  139. static int hf_radius_ascend_data_filter_src_ip_prefix = -1;
  140. static int hf_radius_ascend_data_filter_dst_ip_prefix = -1;
  141. static int hf_radius_ascend_data_filter_protocol = -1;
  142. static int hf_radius_ascend_data_filter_established = -1;
  143. static int hf_radius_ascend_data_filter_src_port = -1;
  144. static int hf_radius_ascend_data_filter_dst_port = -1;
  145. static int hf_radius_ascend_data_filter_src_port_qualifier = -1;
  146. static int hf_radius_ascend_data_filter_dst_port_qualifier = -1;
  147. static int hf_radius_ascend_data_filter_reserved = -1;
  148. static int hf_radius_vsa_fragment = -1;
  149. static int hf_radius_eap_fragment = -1;
  150. static int hf_radius_avp = -1;
  151. static int hf_radius_avp_length = -1;
  152. static int hf_radius_avp_type = -1;
  153. static int hf_radius_avp_vendor_id = -1;
  154. static int hf_radius_avp_vendor_type = -1;
  155. static int hf_radius_avp_vendor_len = -1;
  156. static int hf_radius_avp_extended_type = -1;
  157. static int hf_radius_avp_extended_more = -1;
  158. static int hf_radius_3gpp_ms_tmime_zone = -1;
  159. static int hf_radius_egress_vlanid_tag = -1;
  160. static int hf_radius_egress_vlanid_pad = -1;
  161. static int hf_radius_egress_vlanid = -1;
  162. static int hf_radius_egress_vlan_name_tag = -1;
  163. static int hf_radius_egress_vlan_name = -1;
  164. static gint ett_radius = -1;
  165. static gint ett_radius_avp = -1;
  166. static gint ett_radius_authenticator = -1;
  167. static gint ett_radius_ascend = -1;
  168. static gint ett_eap = -1;
  169. static gint ett_chap = -1;
  170. static expert_field ei_radius_invalid_length = EI_INIT;
  171. /*
  172. * Define the tap for radius
  173. */
  174. static int radius_tap = -1;
  175. static radius_vendor_info_t no_vendor = {"Unknown Vendor", 0, NULL, -1, 1, 1, FALSE};
  176. static radius_attr_info_t no_dictionary_entry = {"Unknown-Attribute", { { 0, 0 } }, FALSE, FALSE, radius_octets, NULL, NULL, -1, -1, -1, -1, -1, NULL };
  177. static dissector_handle_t eap_handle;
  178. static dissector_handle_t radius_handle;
  179. static const gchar *shared_secret = "";
  180. static gboolean validate_authenticator = FALSE;
  181. static gboolean show_length = FALSE;
  182. static gboolean disable_extended_attributes = FALSE;
  183. static guint8 authenticator[AUTHENTICATOR_LENGTH];
  184. /* http://www.iana.org/assignments/radius-types */
  185. static const value_string radius_pkt_type_codes[] =
  186. {
  187. {RADIUS_PKT_TYPE_ACCESS_REQUEST, "Access-Request"}, /* 1 RFC2865 */
  188. {RADIUS_PKT_TYPE_ACCESS_ACCEPT, "Access-Accept"}, /* 2 RFC2865 */
  189. {RADIUS_PKT_TYPE_ACCESS_REJECT, "Access-Reject"}, /* 3 RFC2865 */
  190. {RADIUS_PKT_TYPE_ACCOUNTING_REQUEST, "Accounting-Request"}, /* 4 RFC2865 */
  191. {RADIUS_PKT_TYPE_ACCOUNTING_RESPONSE, "Accounting-Response"}, /* 5 RFC2865 */
  192. {RADIUS_PKT_TYPE_ACCOUNTING_STATUS, "Accounting-Status"}, /* 6 RFC3575 */
  193. {RADIUS_PKT_TYPE_PASSWORD_REQUEST, "Password-Request"}, /* 7 RFC3575 */
  194. {RADIUS_PKT_TYPE_PASSWORD_ACK, "Password-Ack"}, /* 8 RFC3575 */
  195. {RADIUS_PKT_TYPE_PASSWORD_REJECT, "Password-Reject"}, /* 9 RFC3575 */
  196. {RADIUS_PKT_TYPE_ACCOUNTING_MESSAGE, "Accounting-Message"}, /* 10 RFC3575 */
  197. {RADIUS_PKT_TYPE_ACCESS_CHALLENGE, "Access-Challenge"}, /* 11 RFC2865 */
  198. {RADIUS_PKT_TYPE_STATUS_SERVER, "Status-Server"}, /* 12 RFC2865 */
  199. {RADIUS_PKT_TYPE_STATUS_CLIENT, "Status-Client"}, /* 13 RFC2865 */
  200. {RADIUS_PKT_TYPE_RESOURCE_FREE_REQUEST, "Resource-Free-Request"}, /* 21 RFC3575 */
  201. {RADIUS_PKT_TYPE_RESOURCE_FREE_RESPONSE, "Resource-Free-Response"}, /* 22 RFC3575 */
  202. {RADIUS_PKT_TYPE_RESOURCE_QUERY_REQUEST, "Resource-Query-Request"}, /* 23 RFC3575 */
  203. {RADIUS_PKT_TYPE_RESOURCE_QUERY_RESPONSE, "Query_Response"}, /* 24 RFC3575 */
  204. {RADIUS_PKT_TYPE_ALTERNATE_RESOURCE_RECLAIM_REQUEST, "Alternate-Resource-Reclaim-Request"}, /* 25 RFC3575 */
  205. {RADIUS_PKT_TYPE_NAS_REBOOT_REQUEST, "NAS-Reboot-Request"}, /* 26 RFC3575 */
  206. {RADIUS_PKT_TYPE_NAS_REBOOT_RESPONSE, "NAS-Reboot-Response"}, /* 27 RFC3575 */
  207. {RADIUS_PKT_TYPE_NEXT_PASSCODE, "Next-Passcode"}, /* 29 RFC3575 */
  208. {RADIUS_PKT_TYPE_NEW_PIN, "New-Pin"}, /* 30 RFC3575 */
  209. {RADIUS_PKT_TYPE_TERMINATE_SESSION, "Terminate-Session"}, /* 31 RFC3575 */
  210. {RADIUS_PKT_TYPE_PASSWORD_EXPIRED, "Password-Expired"}, /* 32 RFC3575 */
  211. {RADIUS_PKT_TYPE_EVENT_REQUEST, "Event-Request"}, /* 33 RFC3575 */
  212. {RADIUS_PKT_TYPE_EVENT_RESPONSE, "Event-Response"}, /* 34 RFC3575|RFC5176 */
  213. {RADIUS_PKT_TYPE_DISCONNECT_REQUEST, "Disconnect-Request"}, /* 40 RFC3575|RFC5176 */
  214. {RADIUS_PKT_TYPE_DISCONNECT_ACK, "Disconnect-ACK"}, /* 41 RFC3575|RFC5176 */
  215. {RADIUS_PKT_TYPE_DISCONNECT_NAK, "Disconnect-NAK"}, /* 42 RFC3575|RFC5176 */
  216. {RADIUS_PKT_TYPE_COA_REQUEST, "CoA-Request"}, /* 43 RFC3575|RFC5176 */
  217. {RADIUS_PKT_TYPE_COA_ACK, "CoA-ACK"}, /* 44 RFC3575|RFC5176 */
  218. {RADIUS_PKT_TYPE_COA_NAK, "CoA-NAK"}, /* 45 RFC3575|RFC5176 */
  219. {RADIUS_PKT_TYPE_IP_ADDRESS_ALLOCATE, "IP-Address-Allocate"}, /* 50 RFC3575 */
  220. {RADIUS_PKT_TYPE_IP_ADDRESS_RELEASE, "IP-Address-Release"}, /* 51 RFC3575 */
  221. {RADIUS_PKT_TYPE_ALU_STATE_REQUEST, "ALU-State-Request"}, /* 129 ALU AAA */
  222. {RADIUS_PKT_TYPE_ALU_STATE_ACCEPT, "ALU-State-Accept"}, /* 130 ALU AAA */
  223. {RADIUS_PKT_TYPE_ALU_STATE_REJECT, "ALU-State-Reject"}, /* 131 ALU AAA */
  224. {RADIUS_PKT_TYPE_ALU_STATE_ERROR, "ALU-State-Error"}, /* 132 ALU AAA */
  225. /*
  226. 250-253 Experimental Use [RFC3575]
  227. 254-255 Reserved [RFC3575]
  228. */
  229. {0, NULL}
  230. };
  231. static value_string_ext radius_pkt_type_codes_ext = VALUE_STRING_EXT_INIT(radius_pkt_type_codes);
  232. typedef enum _radius_category {
  233. RADIUS_CAT_OVERALL = 0,
  234. RADIUS_CAT_ACCESS,
  235. RADIUS_CAT_ACCOUNTING,
  236. RADIUS_CAT_PASSWORD,
  237. RADIUS_CAT_RESOURCE_FREE,
  238. RADIUS_CAT_RESOURCE_QUERY,
  239. RADIUS_CAT_NAS_REBOOT,
  240. RADIUS_CAT_EVENT,
  241. RADIUS_CAT_DISCONNECT,
  242. RADIUS_CAT_COA,
  243. RADIUS_CAT_OTHERS,
  244. RADIUS_CAT_NUM_TIMESTATS
  245. } radius_category;
  246. static const value_string radius_message_code[] = {
  247. { RADIUS_CAT_OVERALL, "Overall"},
  248. { RADIUS_CAT_ACCESS, "Access"},
  249. { RADIUS_CAT_ACCOUNTING, "Accounting"},
  250. { RADIUS_CAT_PASSWORD, "Password"},
  251. { RADIUS_CAT_RESOURCE_FREE, "Resource Free"},
  252. { RADIUS_CAT_RESOURCE_QUERY, "Resource Query"},
  253. { RADIUS_CAT_NAS_REBOOT, "NAS Reboot"},
  254. { RADIUS_CAT_EVENT, "Event"},
  255. { RADIUS_CAT_DISCONNECT, "Disconnect"},
  256. { RADIUS_CAT_COA, "CoA"},
  257. { RADIUS_CAT_OTHERS, "Other"},
  258. { 0, NULL}
  259. };
  260. static tap_packet_status
  261. radiusstat_packet(void *prs, packet_info *pinfo, epan_dissect_t *edt _U_, const void *pri)
  262. {
  263. rtd_data_t *rtd_data = (rtd_data_t *)prs;
  264. rtd_stat_table *rs = &rtd_data->stat_table;
  265. const radius_info_t *ri = (const radius_info_t *)pri;
  266. nstime_t delta;
  267. radius_category radius_cat = RADIUS_CAT_OTHERS;
  268. tap_packet_status ret = TAP_PACKET_DONT_REDRAW;
  269. switch (ri->code) {
  270. case RADIUS_PKT_TYPE_ACCESS_REQUEST:
  271. case RADIUS_PKT_TYPE_ACCESS_ACCEPT:
  272. case RADIUS_PKT_TYPE_ACCESS_REJECT:
  273. radius_cat = RADIUS_CAT_ACCESS;
  274. break;
  275. case RADIUS_PKT_TYPE_ACCOUNTING_REQUEST:
  276. case RADIUS_PKT_TYPE_ACCOUNTING_RESPONSE:
  277. radius_cat = RADIUS_CAT_ACCOUNTING;
  278. break;
  279. case RADIUS_PKT_TYPE_PASSWORD_REQUEST:
  280. case RADIUS_PKT_TYPE_PASSWORD_ACK:
  281. case RADIUS_PKT_TYPE_PASSWORD_REJECT:
  282. radius_cat = RADIUS_CAT_PASSWORD;
  283. break;
  284. case RADIUS_PKT_TYPE_RESOURCE_FREE_REQUEST:
  285. case RADIUS_PKT_TYPE_RESOURCE_FREE_RESPONSE:
  286. radius_cat = RADIUS_CAT_RESOURCE_FREE;
  287. break;
  288. case RADIUS_PKT_TYPE_RESOURCE_QUERY_REQUEST:
  289. case RADIUS_PKT_TYPE_RESOURCE_QUERY_RESPONSE:
  290. radius_cat = RADIUS_CAT_RESOURCE_QUERY;
  291. break;
  292. case RADIUS_PKT_TYPE_NAS_REBOOT_REQUEST:
  293. case RADIUS_PKT_TYPE_NAS_REBOOT_RESPONSE:
  294. radius_cat = RADIUS_CAT_NAS_REBOOT;
  295. break;
  296. case RADIUS_PKT_TYPE_EVENT_REQUEST:
  297. case RADIUS_PKT_TYPE_EVENT_RESPONSE:
  298. radius_cat = RADIUS_CAT_EVENT;
  299. break;
  300. case RADIUS_PKT_TYPE_DISCONNECT_REQUEST:
  301. case RADIUS_PKT_TYPE_DISCONNECT_ACK:
  302. case RADIUS_PKT_TYPE_DISCONNECT_NAK:
  303. radius_cat = RADIUS_CAT_DISCONNECT;
  304. break;
  305. case RADIUS_PKT_TYPE_COA_REQUEST:
  306. case RADIUS_PKT_TYPE_COA_ACK:
  307. case RADIUS_PKT_TYPE_COA_NAK:
  308. radius_cat = RADIUS_CAT_COA;
  309. break;
  310. }
  311. switch (ri->code) {
  312. case RADIUS_PKT_TYPE_ACCESS_REQUEST:
  313. case RADIUS_PKT_TYPE_ACCOUNTING_REQUEST:
  314. case RADIUS_PKT_TYPE_PASSWORD_REQUEST:
  315. case RADIUS_PKT_TYPE_EVENT_REQUEST:
  316. case RADIUS_PKT_TYPE_DISCONNECT_REQUEST:
  317. case RADIUS_PKT_TYPE_COA_REQUEST:
  318. if (ri->is_duplicate) {
  319. /* Duplicate is ignored */
  320. rs->time_stats[RADIUS_CAT_OVERALL].req_dup_num++;
  321. rs->time_stats[radius_cat].req_dup_num++;
  322. } else {
  323. rs->time_stats[RADIUS_CAT_OVERALL].open_req_num++;
  324. rs->time_stats[radius_cat].open_req_num++;
  325. }
  326. break;
  327. case RADIUS_PKT_TYPE_ACCESS_ACCEPT:
  328. case RADIUS_PKT_TYPE_ACCESS_REJECT:
  329. case RADIUS_PKT_TYPE_ACCOUNTING_RESPONSE:
  330. case RADIUS_PKT_TYPE_PASSWORD_ACK:
  331. case RADIUS_PKT_TYPE_PASSWORD_REJECT:
  332. case RADIUS_PKT_TYPE_EVENT_RESPONSE:
  333. case RADIUS_PKT_TYPE_DISCONNECT_ACK:
  334. case RADIUS_PKT_TYPE_DISCONNECT_NAK:
  335. case RADIUS_PKT_TYPE_COA_ACK:
  336. case RADIUS_PKT_TYPE_COA_NAK:
  337. if (ri->is_duplicate) {
  338. /* Duplicate is ignored */
  339. rs->time_stats[RADIUS_CAT_OVERALL].rsp_dup_num++;
  340. rs->time_stats[radius_cat].rsp_dup_num++;
  341. } else if (!ri->request_available) {
  342. /* no request was seen */
  343. rs->time_stats[RADIUS_CAT_OVERALL].disc_rsp_num++;
  344. rs->time_stats[radius_cat].disc_rsp_num++;
  345. } else {
  346. rs->time_stats[RADIUS_CAT_OVERALL].open_req_num--;
  347. rs->time_stats[radius_cat].open_req_num--;
  348. /* calculate time delta between request and response */
  349. nstime_delta(&delta, &pinfo->abs_ts, &ri->req_time);
  350. time_stat_update(&(rs->time_stats[RADIUS_CAT_OVERALL].rtd[0]),&delta, pinfo);
  351. time_stat_update(&(rs->time_stats[radius_cat].rtd[0]),&delta, pinfo);
  352. ret = TAP_PACKET_REDRAW;
  353. }
  354. break;
  355. default:
  356. break;
  357. }
  358. return ret;
  359. }
  360. /*
  361. * Init Hash table stuff for conversation
  362. */
  363. typedef struct _radius_call_info_key
  364. {
  365. guint code;
  366. guint ident;
  367. conversation_t *conversation;
  368. nstime_t req_time;
  369. } radius_call_info_key;
  370. static wmem_map_t *radius_calls;
  371. typedef struct _radius_vsa_buffer_key
  372. {
  373. guint32 vendor_id;
  374. guint32 vsa_type;
  375. } radius_vsa_buffer_key;
  376. typedef struct _radius_vsa_buffer
  377. {
  378. radius_vsa_buffer_key key;
  379. guint8 *data;
  380. guint seg_num;
  381. guint len;
  382. } radius_vsa_buffer;
  383. static gint
  384. radius_vsa_equal(gconstpointer k1, gconstpointer k2)
  385. {
  386. const radius_vsa_buffer_key *key1 = (const radius_vsa_buffer_key *) k1;
  387. const radius_vsa_buffer_key *key2 = (const radius_vsa_buffer_key *) k2;
  388. return (((key1->vendor_id == key2->vendor_id) &&
  389. (key1->vsa_type == key2->vsa_type)
  390. ) ? TRUE : FALSE);
  391. }
  392. static guint
  393. radius_vsa_hash(gconstpointer k)
  394. {
  395. const radius_vsa_buffer_key *key = (const radius_vsa_buffer_key *) k;
  396. return key->vendor_id + key->vsa_type;
  397. }
  398. /* Compare 2 keys */
  399. static gboolean
  400. radius_call_equal(gconstpointer k1, gconstpointer k2)
  401. {
  402. const radius_call_info_key *key1 = (const radius_call_info_key *) k1;
  403. const radius_call_info_key *key2 = (const radius_call_info_key *) k2;
  404. if (key1->ident == key2->ident && key1->conversation == key2->conversation) {
  405. if (key1->code == key2->code)
  406. return TRUE;
  407. /* check the request and response are of the same code type */
  408. if ((key1->code == RADIUS_PKT_TYPE_ACCESS_REQUEST) &&
  409. ((key2->code == RADIUS_PKT_TYPE_ACCESS_ACCEPT) ||
  410. (key2->code == RADIUS_PKT_TYPE_ACCESS_REJECT) ||
  411. (key2->code == RADIUS_PKT_TYPE_ACCESS_CHALLENGE)))
  412. return TRUE;
  413. if ((key2->code == RADIUS_PKT_TYPE_ACCESS_REQUEST) &&
  414. ((key1->code == RADIUS_PKT_TYPE_ACCESS_ACCEPT) ||
  415. (key1->code == RADIUS_PKT_TYPE_ACCESS_REJECT) ||
  416. (key1->code == RADIUS_PKT_TYPE_ACCESS_CHALLENGE)))
  417. return TRUE;
  418. if ((key1->code == RADIUS_PKT_TYPE_ACCOUNTING_REQUEST) &&
  419. (key2->code == RADIUS_PKT_TYPE_ACCOUNTING_RESPONSE))
  420. return TRUE;
  421. if ((key2->code == RADIUS_PKT_TYPE_ACCOUNTING_REQUEST) &&
  422. (key1->code == RADIUS_PKT_TYPE_ACCOUNTING_RESPONSE))
  423. return TRUE;
  424. if ((key1->code == RADIUS_PKT_TYPE_PASSWORD_REQUEST) &&
  425. ((key2->code == RADIUS_PKT_TYPE_PASSWORD_ACK) ||
  426. (key2->code == RADIUS_PKT_TYPE_PASSWORD_REJECT)))
  427. return TRUE;
  428. if ((key2->code == RADIUS_PKT_TYPE_PASSWORD_REQUEST) &&
  429. ((key1->code == RADIUS_PKT_TYPE_PASSWORD_ACK) ||
  430. (key1->code == RADIUS_PKT_TYPE_PASSWORD_REJECT)))
  431. return TRUE;
  432. if ((key1->code == RADIUS_PKT_TYPE_RESOURCE_FREE_REQUEST) &&
  433. (key2->code == RADIUS_PKT_TYPE_RESOURCE_FREE_RESPONSE))
  434. return TRUE;
  435. if ((key2->code == RADIUS_PKT_TYPE_RESOURCE_FREE_REQUEST) &&
  436. (key1->code == RADIUS_PKT_TYPE_RESOURCE_FREE_RESPONSE))
  437. return TRUE;
  438. if ((key1->code == RADIUS_PKT_TYPE_RESOURCE_QUERY_REQUEST) &&
  439. (key2->code == RADIUS_PKT_TYPE_RESOURCE_QUERY_RESPONSE))
  440. return TRUE;
  441. if ((key2->code == RADIUS_PKT_TYPE_RESOURCE_QUERY_REQUEST) &&
  442. (key1->code == RADIUS_PKT_TYPE_RESOURCE_QUERY_RESPONSE))
  443. return TRUE;
  444. if ((key1->code == RADIUS_PKT_TYPE_NAS_REBOOT_REQUEST) &&
  445. (key2->code == RADIUS_PKT_TYPE_NAS_REBOOT_RESPONSE))
  446. return TRUE;
  447. if ((key2->code == RADIUS_PKT_TYPE_NAS_REBOOT_REQUEST) &&
  448. (key1->code == RADIUS_PKT_TYPE_NAS_REBOOT_RESPONSE))
  449. return TRUE;
  450. if ((key1->code == RADIUS_PKT_TYPE_EVENT_REQUEST) &&
  451. (key2->code == RADIUS_PKT_TYPE_EVENT_RESPONSE))
  452. return TRUE;
  453. if ((key2->code == RADIUS_PKT_TYPE_EVENT_REQUEST) &&
  454. (key1->code == RADIUS_PKT_TYPE_EVENT_RESPONSE))
  455. return TRUE;
  456. if ((key1->code == RADIUS_PKT_TYPE_DISCONNECT_REQUEST) &&
  457. ((key2->code == RADIUS_PKT_TYPE_DISCONNECT_ACK) ||
  458. (key2->code == RADIUS_PKT_TYPE_DISCONNECT_NAK)))
  459. return TRUE;
  460. if ((key2->code == RADIUS_PKT_TYPE_DISCONNECT_REQUEST) &&
  461. ((key1->code == RADIUS_PKT_TYPE_DISCONNECT_ACK) ||
  462. (key1->code == RADIUS_PKT_TYPE_DISCONNECT_NAK)))
  463. return TRUE;
  464. if ((key1->code == RADIUS_PKT_TYPE_COA_REQUEST) &&
  465. ((key2->code == RADIUS_PKT_TYPE_COA_ACK) ||
  466. (key2->code == RADIUS_PKT_TYPE_COA_NAK)))
  467. return TRUE;
  468. if ((key2->code == RADIUS_PKT_TYPE_COA_REQUEST) &&
  469. ((key1->code == RADIUS_PKT_TYPE_COA_ACK) ||
  470. (key1->code == RADIUS_PKT_TYPE_COA_NAK)))
  471. return TRUE;
  472. if ((key1->code == RADIUS_PKT_TYPE_ALU_STATE_REQUEST) &&
  473. ((key2->code == RADIUS_PKT_TYPE_ALU_STATE_ACCEPT) ||
  474. (key2->code == RADIUS_PKT_TYPE_ALU_STATE_REJECT) ||
  475. (key2->code == RADIUS_PKT_TYPE_ALU_STATE_ERROR)))
  476. return TRUE;
  477. if ((key2->code == RADIUS_PKT_TYPE_ALU_STATE_REQUEST) &&
  478. ((key1->code == RADIUS_PKT_TYPE_ALU_STATE_ACCEPT) ||
  479. (key1->code == RADIUS_PKT_TYPE_ALU_STATE_REJECT) ||
  480. (key1->code == RADIUS_PKT_TYPE_ALU_STATE_ERROR)))
  481. return TRUE;
  482. }
  483. return FALSE;
  484. }
  485. /* Calculate a hash key */
  486. static guint
  487. radius_call_hash(gconstpointer k)
  488. {
  489. const radius_call_info_key *key = (const radius_call_info_key *) k;
  490. return key->ident + key->conversation->conv_index;
  491. }
  492. static const gchar *
  493. dissect_chap_password(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_)
  494. {
  495. int len;
  496. proto_item *ti;
  497. proto_tree *chap_tree;
  498. len = tvb_reported_length(tvb);
  499. if (len != 17)
  500. return "[wrong length for CHAP-Password]";
  501. ti = proto_tree_add_item(tree, hf_radius_chap_password, tvb, 0, len, ENC_NA);
  502. chap_tree = proto_item_add_subtree(ti, ett_chap);
  503. proto_tree_add_item(chap_tree, hf_radius_chap_ident, tvb, 0, 1, ENC_BIG_ENDIAN);
  504. proto_tree_add_item(chap_tree, hf_radius_chap_string, tvb, 1, 16, ENC_NA);
  505. return (tvb_bytes_to_str(wmem_packet_scope(), tvb, 0, len));
  506. }
  507. static const gchar *
  508. dissect_framed_ip_address(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_)
  509. {
  510. int len;
  511. guint32 ip;
  512. guint32 ip_h;
  513. const gchar *str;
  514. len = tvb_reported_length(tvb);
  515. if (len != 4)
  516. return "[wrong length for IP address]";
  517. ip = tvb_get_ipv4(tvb, 0);
  518. ip_h = g_ntohl(ip);
  519. if (ip_h == 0xFFFFFFFF) {
  520. str = "Negotiated";
  521. proto_tree_add_ipv4_format_value(tree, hf_radius_framed_ip_address,
  522. tvb, 0, len, ip, "%s", str);
  523. } else if (ip_h == 0xFFFFFFFE) {
  524. str = "Assigned";
  525. proto_tree_add_ipv4_format_value(tree, hf_radius_framed_ip_address,
  526. tvb, 0, len, ip, "%s", str);
  527. } else {
  528. str = tvb_ip_to_str(pinfo->pool, tvb, 0);
  529. proto_tree_add_item(tree, hf_radius_framed_ip_address,
  530. tvb, 0, len, ENC_BIG_ENDIAN);
  531. }
  532. return str;
  533. }
  534. static const gchar *
  535. dissect_login_ip_host(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_)
  536. {
  537. int len;
  538. guint32 ip;
  539. guint32 ip_h;
  540. const gchar *str;
  541. len = tvb_reported_length(tvb);
  542. if (len != 4)
  543. return "[wrong length for IP address]";
  544. ip = tvb_get_ipv4(tvb, 0);
  545. ip_h = g_ntohl(ip);
  546. if (ip_h == 0xFFFFFFFF) {
  547. str = "User-selected";
  548. proto_tree_add_ipv4_format_value(tree, hf_radius_login_ip_host,
  549. tvb, 0, len, ip, "%s", str);
  550. } else if (ip_h == 0) {
  551. str = "NAS-selected";
  552. proto_tree_add_ipv4_format_value(tree, hf_radius_login_ip_host,
  553. tvb, 0, len, ip, "%s", str);
  554. } else {
  555. str = tvb_ip_to_str(pinfo->pool, tvb, 0);
  556. proto_tree_add_item(tree, hf_radius_login_ip_host,
  557. tvb, 0, len, ENC_BIG_ENDIAN);
  558. }
  559. return str;
  560. }
  561. static const value_string ascenddf_filtertype[] = { {0, "generic"}, {1, "ipv4"}, {3, "ipv6"}, {0, NULL} };
  562. static const value_string ascenddf_filteror[] = { {0, "drop"}, {1, "forward"}, {0, NULL} };
  563. static const value_string ascenddf_inout[] = { {0, "out"}, {1, "in"}, {0, NULL} };
  564. static const value_string ascenddf_proto[] = { {1, "icmp"}, {6, "tcp"}, {17, "udp"}, {0, NULL} };
  565. static const value_string ascenddf_portq[] = { {1, "lt"}, {2, "eq"}, {3, "gt"}, {4, "ne"}, {0, NULL} };
  566. static const gchar *
  567. dissect_ascend_data_filter(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_)
  568. {
  569. wmem_strbuf_t *filterstr;
  570. proto_item *ti;
  571. proto_tree *ascend_tree;
  572. int len;
  573. guint8 type, proto, srclen, dstlen;
  574. address srcip, dstip;
  575. guint16 srcport, dstport;
  576. guint8 srcportq, dstportq;
  577. guint8 iplen = 4;
  578. guint offset = 0;
  579. len=tvb_reported_length(tvb);
  580. if (len != 24 && len != 48) {
  581. return wmem_strdup_printf(wmem_packet_scope(), "Wrong attribute length %d", len);
  582. }
  583. filterstr = wmem_strbuf_sized_new(wmem_packet_scope(), 128, 128);
  584. ti = proto_tree_add_item(tree, hf_radius_ascend_data_filter, tvb, 0, -1, ENC_NA);
  585. ascend_tree = proto_item_add_subtree(ti, ett_radius_ascend);
  586. proto_tree_add_item(ascend_tree, hf_radius_ascend_data_filter_type, tvb, offset, 1, ENC_BIG_ENDIAN);
  587. type = tvb_get_guint8(tvb, 0);
  588. offset += 1;
  589. if (type == 3) { /* IPv6 */
  590. iplen = 16;
  591. }
  592. proto_tree_add_item(ascend_tree, hf_radius_ascend_data_filter_filteror, tvb, offset, 1, ENC_BIG_ENDIAN);
  593. offset += 1;
  594. proto_tree_add_item(ascend_tree, hf_radius_ascend_data_filter_inout, tvb, offset, 1, ENC_BIG_ENDIAN);
  595. offset += 1;
  596. proto_tree_add_item(ascend_tree, hf_radius_ascend_data_filter_spare, tvb, offset, 1, ENC_BIG_ENDIAN);
  597. offset += 1;
  598. if (type == 3) { /* IPv6 */
  599. proto_tree_add_item(ascend_tree, hf_radius_ascend_data_filter_src_ipv6, tvb, offset, 16, ENC_NA);
  600. offset += 16;
  601. proto_tree_add_item(ascend_tree, hf_radius_ascend_data_filter_dst_ipv6, tvb, offset, 16, ENC_NA);
  602. offset += 16;
  603. } else { /* IPv4 */
  604. proto_tree_add_item(ascend_tree, hf_radius_ascend_data_filter_src_ipv4, tvb, offset, 4, ENC_BIG_ENDIAN);
  605. offset += 4;
  606. proto_tree_add_item(ascend_tree, hf_radius_ascend_data_filter_dst_ipv4, tvb, offset, 4, ENC_BIG_ENDIAN);
  607. offset += 4;
  608. }
  609. proto_tree_add_item(ascend_tree, hf_radius_ascend_data_filter_src_ip_prefix, tvb, offset, 1, ENC_BIG_ENDIAN);
  610. offset += 1;
  611. proto_tree_add_item(ascend_tree, hf_radius_ascend_data_filter_dst_ip_prefix, tvb, offset, 1, ENC_BIG_ENDIAN);
  612. offset += 1;
  613. proto_tree_add_item(ascend_tree, hf_radius_ascend_data_filter_protocol, tvb, offset, 1, ENC_BIG_ENDIAN);
  614. offset += 1;
  615. proto_tree_add_item(ascend_tree, hf_radius_ascend_data_filter_established, tvb, offset, 1, ENC_BIG_ENDIAN);
  616. offset += 1;
  617. proto_tree_add_item(ascend_tree, hf_radius_ascend_data_filter_src_port, tvb, offset, 2, ENC_BIG_ENDIAN);
  618. offset += 2;
  619. proto_tree_add_item(ascend_tree, hf_radius_ascend_data_filter_dst_port, tvb, offset, 2, ENC_BIG_ENDIAN);
  620. offset += 2;
  621. proto_tree_add_item(ascend_tree, hf_radius_ascend_data_filter_src_port_qualifier, tvb, offset, 1, ENC_BIG_ENDIAN);
  622. offset += 1;
  623. proto_tree_add_item(ascend_tree, hf_radius_ascend_data_filter_dst_port_qualifier, tvb, offset, 1, ENC_BIG_ENDIAN);
  624. offset += 1;
  625. proto_tree_add_item(ascend_tree, hf_radius_ascend_data_filter_reserved, tvb, offset, 2, ENC_BIG_ENDIAN);
  626. wmem_strbuf_append_printf(filterstr, "%s %s %s",
  627. val_to_str(type, ascenddf_filtertype, "%u"),
  628. val_to_str(tvb_get_guint8(tvb, 2), ascenddf_inout, "%u"),
  629. val_to_str(tvb_get_guint8(tvb, 1), ascenddf_filteror, "%u"));
  630. proto = tvb_get_guint8(tvb, 6+iplen*2);
  631. if (proto) {
  632. wmem_strbuf_append_printf(filterstr, " %s",
  633. val_to_str(proto, ascenddf_proto, "%u"));
  634. }
  635. if (type == 3) { /* IPv6 */
  636. set_address_tvb(&srcip, AT_IPv6, 16, tvb, 4);
  637. } else {
  638. set_address_tvb(&srcip, AT_IPv4, 4, tvb, 4);
  639. }
  640. srclen = tvb_get_guint8(tvb, 4+iplen*2);
  641. srcport = tvb_get_ntohs(tvb, 9+iplen*2);
  642. srcportq = tvb_get_guint8(tvb, 12+iplen*2);
  643. if (srclen || srcportq) {
  644. wmem_strbuf_append_printf(filterstr, " srcip %s/%d", address_to_display(wmem_packet_scope(), &srcip), srclen);
  645. if (srcportq)
  646. wmem_strbuf_append_printf(filterstr, " srcport %s %d",
  647. val_to_str(srcportq, ascenddf_portq, "%u"), srcport);
  648. }
  649. if (type == 3) { /* IPv6-*/
  650. set_address_tvb(&dstip, AT_IPv6, 16, tvb, 4+iplen);
  651. } else {
  652. set_address_tvb(&dstip, AT_IPv4, 4, tvb, 4+iplen);
  653. }
  654. dstlen = tvb_get_guint8(tvb, 5+iplen*2);
  655. dstport = tvb_get_ntohs(tvb, 10+iplen*2);
  656. dstportq = tvb_get_guint8(tvb, 13+iplen*2);
  657. if (dstlen || dstportq) {
  658. wmem_strbuf_append_printf(filterstr, " dstip %s/%d", address_to_display(wmem_packet_scope(), &dstip), dstlen);
  659. if (dstportq)
  660. wmem_strbuf_append_printf(filterstr, " dstport %s %d",
  661. val_to_str(dstportq, ascenddf_portq, "%u"), dstport);
  662. }
  663. return wmem_strbuf_get_str(filterstr);
  664. }
  665. static const gchar *
  666. dissect_framed_ipx_network(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_)
  667. {
  668. int len;
  669. guint32 net;
  670. const gchar *str;
  671. len = tvb_reported_length(tvb);
  672. if (len != 4)
  673. return "[wrong length for IPX network]";
  674. net = tvb_get_ntohl(tvb, 0);
  675. if (net == 0xFFFFFFFE)
  676. str = "NAS-selected";
  677. else
  678. str = wmem_strdup_printf(wmem_packet_scope(), "0x%08X", net);
  679. proto_tree_add_ipxnet_format_value(tree, hf_radius_framed_ipx_network, tvb, 0,
  680. len, net, "Framed-IPX-Network: %s", str);
  681. return str;
  682. }
  683. static const gchar *
  684. dissect_cosine_vpvc(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_)
  685. {
  686. guint vpi, vci;
  687. if (tvb_reported_length(tvb) != 4)
  688. return "[Wrong Length for VP/VC AVP]";
  689. vpi = tvb_get_ntohs(tvb, 0);
  690. vci = tvb_get_ntohs(tvb, 2);
  691. proto_tree_add_uint(tree, hf_radius_cosine_vpi, tvb, 0, 2, vpi);
  692. proto_tree_add_uint(tree, hf_radius_cosine_vci, tvb, 2, 2, vci);
  693. return wmem_strdup_printf(wmem_packet_scope(), "%u/%u", vpi, vci);
  694. }
  695. static const value_string daylight_saving_time_vals[] = {
  696. {0, "No adjustment"},
  697. {1, "+1 hour adjustment for Daylight Saving Time"},
  698. {2, "+2 hours adjustment for Daylight Saving Time"},
  699. {3, "Reserved"},
  700. {0, NULL}
  701. };
  702. static const gchar *
  703. dissect_radius_3gpp_imsi(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo)
  704. {
  705. return dissect_e212_utf8_imsi(tvb, pinfo, tree, 0, tvb_reported_length(tvb));
  706. }
  707. static const gchar *
  708. dissect_radius_3gpp_ms_tmime_zone(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_)
  709. {
  710. int offset = 0;
  711. guint8 oct, daylight_saving_time;
  712. char sign;
  713. /* 3GPP TS 23.040 version 6.6.0 Release 6
  714. * 9.2.3.11 TP-Service-Centre-Time-Stamp (TP-SCTS)
  715. * :
  716. * The Time Zone indicates the difference, expressed in quarters of an hour,
  717. * between the local time and GMT. In the first of the two semi-octets,
  718. * the first bit (bit 3 of the seventh octet of the TP-Service-Centre-Time-Stamp field)
  719. * represents the algebraic sign of this difference (0: positive, 1: negative).
  720. */
  721. oct = tvb_get_guint8(tvb, offset);
  722. sign = (oct & 0x08) ? '-' : '+';
  723. oct = (oct >> 4) + (oct & 0x07) * 10;
  724. daylight_saving_time = tvb_get_guint8(tvb, offset+1) & 0x3;
  725. proto_tree_add_bytes_format_value(tree, hf_radius_3gpp_ms_tmime_zone, tvb, offset, 2, NULL,
  726. "GMT %c%d hours %d minutes %s", sign, oct / 4, oct % 4 * 15,
  727. val_to_str_const(daylight_saving_time, daylight_saving_time_vals, "Unknown"));
  728. return wmem_strdup_printf(wmem_packet_scope(), "Timezone: GMT %c%d hours %d minutes %s ",
  729. sign, oct / 4, oct % 4 * 15, val_to_str_const(daylight_saving_time, daylight_saving_time_vals, "Unknown"));
  730. }
  731. static const value_string egress_vlan_tag_vals[] = {
  732. { 0x31, "Tagged"},
  733. { 0x32, "Untagged"},
  734. { 0, NULL}
  735. };
  736. static const gchar *
  737. dissect_rfc4675_egress_vlanid(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_)
  738. {
  739. int len;
  740. guint32 vlanid;
  741. len = tvb_reported_length(tvb);
  742. if (len != 4)
  743. return "[wrong length for Egress-VLANID ]";
  744. proto_tree_add_item(tree, hf_radius_egress_vlanid_tag, tvb, 0, 4, ENC_BIG_ENDIAN);
  745. proto_tree_add_item(tree, hf_radius_egress_vlanid_pad, tvb, 0, 4, ENC_BIG_ENDIAN);
  746. proto_tree_add_item(tree, hf_radius_egress_vlanid, tvb, 0, 4, ENC_BIG_ENDIAN);
  747. vlanid = tvb_get_ntohl(tvb, 0);
  748. return wmem_strdup_printf(wmem_packet_scope(), "%s, Vlan ID: %u",
  749. val_to_str_const(((vlanid&0xFF000000)>>24), egress_vlan_tag_vals, "Unknown"), vlanid&0xFFF);
  750. }
  751. static const gchar *
  752. dissect_rfc4675_egress_vlan_name(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_)
  753. {
  754. int len;
  755. guint8 tag;
  756. const guint8 *name;
  757. len = tvb_reported_length(tvb);
  758. if (len < 2)
  759. return "[wrong length for Egress-VLAN-Name ]";
  760. proto_tree_add_item(tree, hf_radius_egress_vlan_name_tag, tvb, 0, 1, ENC_BIG_ENDIAN);
  761. tag = tvb_get_guint8(tvb, 0);
  762. len -= 1;
  763. proto_tree_add_item_ret_string(tree, hf_radius_egress_vlan_name, tvb, 1, len, ENC_ASCII|ENC_NA, wmem_packet_scope(), &name);
  764. return wmem_strdup_printf(wmem_packet_scope(), "%s, Vlan Name: %s",
  765. val_to_str_const(tag, egress_vlan_tag_vals, "Unknown"), name);
  766. }
  767. static void
  768. radius_decrypt_avp(gchar *dest, int dest_len, tvbuff_t *tvb, int offset, int length)
  769. {
  770. gcry_md_hd_t md5_handle;
  771. guint8 digest[HASH_MD5_LENGTH];
  772. int i, j;
  773. gint totlen = 0, returned_length, padded_length;
  774. guint8 *pd;
  775. guchar c;
  776. DISSECTOR_ASSERT(dest_len > 0);
  777. dest[0] = '\0';
  778. if (length <= 0)
  779. return;
  780. /* The max avp length is 253 (255 - 2 for type & length), but only the
  781. * User-Password is marked with encrypt=1 in dictionary.rfc2865, and the
  782. * User-Password max length is only 128 (130 - 2 for type & length) per
  783. * tools.ietf.org/html/rfc2865#section-5.2, so enforce that limit here.
  784. */
  785. if (length > 128)
  786. length = 128;
  787. if (gcry_md_open(&md5_handle, GCRY_MD_MD5, 0)) {
  788. return;
  789. }
  790. gcry_md_write(md5_handle, (const guint8 *)shared_secret, (int)strlen(shared_secret));
  791. gcry_md_write(md5_handle, authenticator, AUTHENTICATOR_LENGTH);
  792. memcpy(digest, gcry_md_read(md5_handle, 0), HASH_MD5_LENGTH);
  793. padded_length = length + ((length % AUTHENTICATOR_LENGTH) ?
  794. (AUTHENTICATOR_LENGTH - (length % AUTHENTICATOR_LENGTH)) : 0);
  795. pd = (guint8 *)wmem_alloc0(wmem_packet_scope(), padded_length);
  796. tvb_memcpy(tvb, pd, offset, length);
  797. for (i = 0; i < padded_length; i += AUTHENTICATOR_LENGTH) {
  798. for (j = 0; j < AUTHENTICATOR_LENGTH; j++) {
  799. c = pd[i + j] ^ digest[j];
  800. if (g_ascii_isprint(c)) {
  801. returned_length = snprintf(&dest[totlen], dest_len - totlen,
  802. "%c", c);
  803. totlen += MIN(returned_length, dest_len - totlen - 1);
  804. }
  805. else if (c) {
  806. returned_length = snprintf(&dest[totlen], dest_len - totlen,
  807. "\\%03o", c);
  808. totlen += MIN(returned_length, dest_len - totlen - 1);
  809. }
  810. }
  811. gcry_md_reset(md5_handle);
  812. gcry_md_write(md5_handle, (const guint8 *)shared_secret, (int)strlen(shared_secret));
  813. gcry_md_write(md5_handle, &pd[i], AUTHENTICATOR_LENGTH);
  814. memcpy(digest, gcry_md_read(md5_handle, 0), HASH_MD5_LENGTH);
  815. }
  816. gcry_md_close(md5_handle);
  817. }
  818. static void
  819. add_avp_to_tree_with_dissector(proto_tree *avp_tree, proto_item *avp_item, packet_info *pinfo, tvbuff_t *tvb, radius_avp_dissector_t *avp_dissector, guint32 avp_length, guint32 offset);
  820. void
  821. radius_integer(radius_attr_info_t *a, proto_tree *tree, packet_info *pinfo _U_, tvbuff_t *tvb, int offset, int len, proto_item *avp_item)
  822. {
  823. guint32 uintv;
  824. switch (len) {
  825. case 1:
  826. uintv = tvb_get_guint8(tvb, offset);
  827. break;
  828. case 2:
  829. uintv = tvb_get_ntohs(tvb, offset);
  830. break;
  831. case 3:
  832. uintv = tvb_get_ntoh24(tvb, offset);
  833. break;
  834. case 4:
  835. uintv = tvb_get_ntohl(tvb, offset);
  836. break;
  837. case 8: {
  838. guint64 uintv64 = tvb_get_ntoh64(tvb, offset);
  839. proto_tree_add_uint64(tree, a->hf_alt, tvb, offset, len, uintv64);
  840. proto_item_append_text(avp_item, "%" PRIu64, uintv64);
  841. return;
  842. }
  843. default:
  844. proto_item_append_text(avp_item, "[unhandled integer length(%u)]", len);
  845. return;
  846. }
  847. proto_tree_add_item(tree, a->hf, tvb, offset, len, ENC_BIG_ENDIAN);
  848. if (a->vs) {
  849. proto_item_append_text(avp_item, "%s(%u)", val_to_str_const(uintv, a->vs, "Unknown"), uintv);
  850. } else {
  851. proto_item_append_text(avp_item, "%u", uintv);
  852. }
  853. }
  854. void
  855. radius_signed(radius_attr_info_t *a, proto_tree *tree, packet_info *pinfo _U_, tvbuff_t *tvb, int offset, int len, proto_item *avp_item)
  856. {
  857. guint32 uintv;
  858. switch (len) {
  859. case 1:
  860. uintv = tvb_get_guint8(tvb, offset);
  861. break;
  862. case 2:
  863. uintv = tvb_get_ntohs(tvb, offset);
  864. break;
  865. case 3:
  866. uintv = tvb_get_ntoh24(tvb, offset);
  867. break;
  868. case 4:
  869. uintv = tvb_get_ntohl(tvb, offset);
  870. break;
  871. case 8: {
  872. guint64 uintv64 = tvb_get_ntoh64(tvb, offset);
  873. proto_tree_add_int64(tree, a->hf_alt, tvb, offset, len, uintv64);
  874. proto_item_append_text(avp_item, "%" PRIu64, uintv64);
  875. return;
  876. }
  877. default:
  878. proto_item_append_text(avp_item, "[unhandled signed integer length(%u)]", len);
  879. return;
  880. }
  881. proto_tree_add_int(tree, a->hf, tvb, offset, len, uintv);
  882. if (a->vs) {
  883. proto_item_append_text(avp_item, "%s(%d)", val_to_str_const(uintv, a->vs, "Unknown"), uintv);
  884. } else {
  885. proto_item_append_text(avp_item, "%d", uintv);
  886. }
  887. }
  888. void
  889. radius_string(radius_attr_info_t *a, proto_tree *tree, packet_info *pinfo _U_, tvbuff_t *tvb, int offset, int len, proto_item *avp_item)
  890. {
  891. switch (a->encrypt) {
  892. case 0: /* not encrypted */
  893. proto_tree_add_item(tree, a->hf, tvb, offset, len, ENC_UTF_8|ENC_NA);
  894. proto_item_append_text(avp_item, "%s", tvb_format_text(pinfo->pool, tvb, offset, len));
  895. break;
  896. case 1: /* encrypted like User-Password as defined in RFC 2865 */
  897. if (*shared_secret == '\0') {
  898. proto_item_append_text(avp_item, "Encrypted");
  899. proto_tree_add_item(tree, a->hf_alt, tvb, offset, len, ENC_NA);
  900. } else {
  901. gchar *buffer;
  902. buffer = (gchar *)wmem_alloc(wmem_packet_scope(), 1024); /* an AVP value can be at most 253 bytes */
  903. radius_decrypt_avp(buffer, 1024, tvb, offset, len);
  904. proto_item_append_text(avp_item, "Decrypted: %s", buffer);
  905. proto_tree_add_string(tree, a->hf, tvb, offset, len, buffer);
  906. }
  907. break;
  908. case 2: /* encrypted like Tunnel-Password as defined in RFC 2868 */
  909. proto_item_append_text(avp_item, "Encrypted");
  910. proto_tree_add_item(tree, a->hf_alt, tvb, offset, len, ENC_NA);
  911. break;
  912. case 3: /* encrypted like Ascend-Send-Secret as defined by Ascend^WLucent^WAlcatel-Lucent */
  913. proto_item_append_text(avp_item, "Encrypted");
  914. proto_tree_add_item(tree, a->hf_alt, tvb, offset, len, ENC_NA);
  915. break;
  916. }
  917. }
  918. void
  919. radius_octets(radius_attr_info_t *a, proto_tree *tree, packet_info *pinfo _U_, tvbuff_t *tvb, int offset, int len, proto_item *avp_item)
  920. {
  921. if (len == 0) {
  922. proto_item_append_text(avp_item, "[wrong length]");
  923. return;
  924. }
  925. proto_tree_add_item(tree, a->hf, tvb, offset, len, ENC_NA);
  926. proto_item_append_text(avp_item, "%s", tvb_bytes_to_str(wmem_packet_scope(), tvb, offset, len));
  927. }
  928. void
  929. radius_ipaddr(radius_attr_info_t *a, proto_tree *tree, packet_info *pinfo _U_, tvbuff_t *tvb, int offset, int len, proto_item *avp_item)
  930. {
  931. if (len != 4) {
  932. proto_item_append_text(avp_item, "[wrong length for IP address]");
  933. return;
  934. }
  935. proto_tree_add_item(tree, a->hf, tvb, offset, len, ENC_BIG_ENDIAN);
  936. proto_item_append_text(avp_item, "%s", tvb_ip_to_str(pinfo->pool, tvb, offset));
  937. }
  938. void
  939. radius_ipv6addr(radius_attr_info_t *a, proto_tree *tree, packet_info *pinfo _U_, tvbuff_t *tvb, int offset, int len, proto_item *avp_item)
  940. {
  941. if (len != 16) {
  942. proto_item_append_text(avp_item, "[wrong length for IPv6 address]");
  943. return;
  944. }
  945. proto_tree_add_item(tree, a->hf, tvb, offset, len, ENC_NA);
  946. proto_item_append_text(avp_item, "%s", tvb_ip6_to_str(pinfo->pool, tvb, offset));
  947. }
  948. void
  949. radius_ipv6prefix(radius_attr_info_t *a, proto_tree *tree, packet_info *pinfo _U_, tvbuff_t *tvb, int offset, int len, proto_item *avp_item)
  950. {
  951. ws_in6_addr ipv6_buff;
  952. gchar txtbuf[256];
  953. guint8 n;
  954. if ((len < 2) || (len > 18)) {
  955. proto_item_append_text(avp_item, "[wrong length for IPv6 prefix]");
  956. return;
  957. }
  958. /* first byte is reserved == 0x00 */
  959. if (tvb_get_guint8(tvb, offset)) {
  960. proto_item_append_text(avp_item, "[invalid reserved byte for IPv6 prefix]");
  961. return;
  962. }
  963. /* this is the prefix length */
  964. n = tvb_get_guint8(tvb, offset + 1);
  965. if (n > 128) {
  966. proto_item_append_text(avp_item, "[invalid IPv6 prefix length]");
  967. return;
  968. }
  969. proto_tree_add_item(tree, a->hf, tvb, offset, len, ENC_NA);
  970. /* cannot use tvb_get_ipv6() here, since the prefix most likely is truncated */
  971. memset(&ipv6_buff, 0, sizeof ipv6_buff);
  972. tvb_memcpy(tvb, &ipv6_buff, offset + 2, len - 2);
  973. ip6_to_str_buf(&ipv6_buff, txtbuf, sizeof(txtbuf));
  974. proto_item_append_text(avp_item, "%s/%u", txtbuf, n);
  975. }
  976. void
  977. radius_combo_ip(radius_attr_info_t *a, proto_tree *tree, packet_info *pinfo _U_, tvbuff_t *tvb, int offset, int len, proto_item *avp_item)
  978. {
  979. if (len == 4) {
  980. proto_tree_add_item(tree, a->hf, tvb, offset, len, ENC_BIG_ENDIAN);
  981. proto_item_append_text(avp_item, "%s", tvb_ip_to_str(pinfo->pool, tvb, offset));
  982. } else if (len == 16) {
  983. proto_tree_add_item(tree, a->hf_alt, tvb, offset, len, ENC_NA);
  984. proto_item_append_text(avp_item, "%s", tvb_ip6_to_str(pinfo->pool, tvb, offset));
  985. } else {
  986. proto_item_append_text(avp_item, "[wrong length for both of IPv4 and IPv6 address]");
  987. return;
  988. }
  989. }
  990. void
  991. radius_ipxnet(radius_attr_info_t *a, proto_tree *tree, packet_info *pinfo _U_, tvbuff_t *tvb, int offset, int len, proto_item *avp_item)
  992. {
  993. guint32 net;
  994. if (len != 4) {
  995. proto_item_append_text(avp_item, "[wrong length for IPX network]");
  996. return;
  997. }
  998. net = tvb_get_ntohl(tvb, offset);
  999. proto_tree_add_item(tree, a->hf, tvb, offset, len, ENC_NA);
  1000. proto_item_append_text(avp_item, "0x%08X", net);
  1001. }
  1002. void
  1003. radius_date(radius_attr_info_t *a, proto_tree *tree, packet_info *pinfo _U_, tvbuff_t *tvb, int offset, int len, proto_item *avp_item)
  1004. {
  1005. nstime_t time_ptr;
  1006. if (len != 4) {
  1007. proto_item_append_text(avp_item, "[wrong length for timestamp]");
  1008. return;
  1009. }
  1010. time_ptr.secs = tvb_get_ntohl(tvb, offset);
  1011. time_ptr.nsecs = 0;
  1012. proto_tree_add_time(tree, a->hf, tvb, offset, len, &time_ptr);
  1013. proto_item_append_text(avp_item, "%s", abs_time_to_str(wmem_packet_scope(), &time_ptr, ABSOLUTE_TIME_LOCAL, TRUE));
  1014. }
  1015. /*
  1016. * "abinary" is Ascend's binary format for filters. See dissect_ascend_data_filter().
  1017. */
  1018. void
  1019. radius_abinary(radius_attr_info_t *a, proto_tree *tree, packet_info *pinfo _U_, tvbuff_t *tvb, int offset, int len, proto_item *avp_item)
  1020. {
  1021. if (a->code.u8_code[0] == 242) {
  1022. add_avp_to_tree_with_dissector(tree, avp_item, pinfo, tvb, dissect_ascend_data_filter, len, offset);
  1023. return;
  1024. }
  1025. proto_tree_add_item(tree, a->hf, tvb, offset, len, ENC_NA);
  1026. proto_item_append_text(avp_item, "%s", tvb_bytes_to_str(wmem_packet_scope(), tvb, offset, len));
  1027. }
  1028. void
  1029. radius_ether(radius_attr_info_t *a, proto_tree *tree, packet_info *pinfo _U_, tvbuff_t *tvb, int offset, int len, proto_item *avp_item)
  1030. {
  1031. if (len != 6) {
  1032. proto_item_append_text(avp_item, "[wrong length for ethernet address]");
  1033. return;
  1034. }
  1035. proto_tree_add_item(tree, a->hf, tvb, offset, len, ENC_NA);
  1036. proto_item_append_text(avp_item, "%s", tvb_ether_to_str(pinfo->pool, tvb, offset));
  1037. }
  1038. void
  1039. radius_ifid(radius_attr_info_t *a, proto_tree *tree, packet_info *pinfo _U_, tvbuff_t *tvb, int offset, int len, proto_item *avp_item)
  1040. {
  1041. proto_tree_add_item(tree, a->hf, tvb, offset, len, ENC_NA);
  1042. proto_item_append_text(avp_item, "%s", tvb_bytes_to_str(wmem_packet_scope(), tvb, offset, len));
  1043. }
  1044. static void
  1045. add_tlv_to_tree(proto_tree *tlv_tree, proto_item *tlv_item, packet_info *pinfo, tvbuff_t *tvb, radius_attr_info_t *dictionary_entry, guint32 tlv_length, guint32 offset)
  1046. {
  1047. proto_item_append_text(tlv_item, ": ");
  1048. dictionary_entry->type(dictionary_entry, tlv_tree, pinfo, tvb, offset, tlv_length, tlv_item);
  1049. }
  1050. void
  1051. radius_tlv(radius_attr_info_t *a, proto_tree *tree, packet_info *pinfo _U_, tvbuff_t *tvb, int offset, int len, proto_item *avp_item)
  1052. {
  1053. gint tlv_num = 0;
  1054. while (len > 0) {
  1055. radius_attr_info_t *dictionary_entry = NULL;
  1056. guint32 tlv_type;
  1057. guint32 tlv_length;
  1058. proto_item *tlv_item;
  1059. proto_item *tlv_len_item;
  1060. proto_tree *tlv_tree;
  1061. if (len < 2) {
  1062. proto_tree_add_expert_format(tree, pinfo, &ei_radius_invalid_length, tvb, offset, 0,
  1063. "Not enough room in packet for TLV header");
  1064. return;
  1065. }
  1066. tlv_type = tvb_get_guint8(tvb, offset);
  1067. tlv_length = tvb_get_guint8(tvb, offset+1);
  1068. if (tlv_length < 2) {
  1069. proto_tree_add_expert_format(tree, pinfo, &ei_radius_invalid_length, tvb, offset, 0,
  1070. "TLV too short: length %u < 2", tlv_length);
  1071. return;
  1072. }
  1073. if (len < (gint)tlv_length) {
  1074. proto_tree_add_expert_format(tree, pinfo, &ei_radius_invalid_length, tvb, offset, 0,
  1075. "Not enough room in packet for TLV");
  1076. return;
  1077. }
  1078. len -= tlv_length;
  1079. dictionary_entry = (radius_attr_info_t *)g_hash_table_lookup(a->tlvs_by_id, GUINT_TO_POINTER(tlv_type));
  1080. if (!dictionary_entry) {
  1081. dictionary_entry = &no_dictionary_entry;
  1082. }
  1083. tlv_tree = proto_tree_add_subtree_format(tree, tvb, offset, tlv_length,
  1084. dictionary_entry->ett, &tlv_item, "TLV: t=%s(%u) l=%u ", dictionary_entry->name, tlv_type,
  1085. tlv_length);
  1086. tlv_length -= 2;
  1087. offset += 2;
  1088. if (show_length) {
  1089. tlv_len_item = proto_tree_add_uint(tlv_tree,
  1090. dictionary_entry->hf_len,
  1091. tvb, 0, 0, tlv_length);
  1092. proto_item_set_generated(tlv_len_item);
  1093. }
  1094. add_tlv_to_tree(tlv_tree, tlv_item, pinfo, tvb, dictionary_entry,
  1095. tlv_length, offset);
  1096. offset += tlv_length;
  1097. tlv_num++;
  1098. }
  1099. proto_item_append_text(avp_item, "%d TLV(s) inside", tlv_num);
  1100. }
  1101. static void
  1102. add_avp_to_tree_with_dissector(proto_tree *avp_tree, proto_item *avp_item, packet_info *pinfo, tvbuff_t *tvb, radius_avp_dissector_t *avp_dissector, guint32 avp_length, guint32 offset)
  1103. {
  1104. tvbuff_t *tvb_value;
  1105. const gchar *str;
  1106. tvb_value = tvb_new_subset_length(tvb, offset, avp_length);
  1107. str = avp_dissector(avp_tree, tvb_value, pinfo);
  1108. proto_item_append_text(avp_item, "%s", str);
  1109. }
  1110. static void
  1111. add_avp_to_tree(proto_tree *avp_tree, proto_item *avp_item, packet_info *pinfo, tvbuff_t *tvb, radius_attr_info_t *dictionary_entry, guint32 avp_length, guint32 offset)
  1112. {
  1113. if (dictionary_entry->tagged) {
  1114. guint tag;
  1115. if (avp_length == 0) {
  1116. proto_tree_add_expert_format(avp_tree, pinfo, &ei_radius_invalid_length, tvb, offset,
  1117. 0, "AVP too short for tag");
  1118. return;
  1119. }
  1120. tag = tvb_get_guint8(tvb, offset);
  1121. if (tag <= 0x1f) {
  1122. proto_tree_add_uint(avp_tree,
  1123. dictionary_entry->hf_tag,
  1124. tvb, offset, 1, tag);
  1125. proto_item_append_text(avp_item,
  1126. " Tag=0x%.2x", tag);
  1127. offset++;
  1128. avp_length--;
  1129. }
  1130. }
  1131. proto_item_append_text(avp_item, " val=");
  1132. if (dictionary_entry->dissector) {
  1133. add_avp_to_tree_with_dissector(avp_tree, avp_item, pinfo, tvb, dictionary_entry->dissector, avp_length, offset);
  1134. return;
  1135. }
  1136. dictionary_entry->type(dictionary_entry, avp_tree, pinfo, tvb, offset, avp_length, avp_item);
  1137. }
  1138. static gboolean
  1139. vsa_buffer_destroy(gpointer k _U_, gpointer v, gpointer p _U_)
  1140. {
  1141. radius_vsa_buffer *vsa_buffer = (radius_vsa_buffer *)v;
  1142. g_free((gpointer)vsa_buffer->data);
  1143. g_free(v);
  1144. return TRUE;
  1145. }
  1146. static void
  1147. eap_buffer_free_indirect(void *context)
  1148. {
  1149. guint8 *eap_buffer = *(guint8 **)context;
  1150. g_free(eap_buffer);
  1151. }
  1152. static void
  1153. vsa_buffer_table_destroy_indirect(void *context)
  1154. {
  1155. GHashTable *vsa_buffer_table = *(GHashTable **)context;
  1156. if (vsa_buffer_table) {
  1157. g_hash_table_foreach_remove(vsa_buffer_table, vsa_buffer_destroy, NULL);
  1158. g_hash_table_destroy(vsa_buffer_table);
  1159. }
  1160. }
  1161. void
  1162. dissect_attribute_value_pairs(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, int offset, guint length)
  1163. {
  1164. gboolean last_eap = FALSE;
  1165. guint8 *eap_buffer = NULL;
  1166. guint eap_seg_num = 0;
  1167. guint eap_tot_len_captured = 0;
  1168. guint eap_tot_len = 0;
  1169. proto_tree *eap_tree = NULL;
  1170. tvbuff_t *eap_tvb = NULL;
  1171. GHashTable *vsa_buffer_table = NULL;
  1172. if (hf_radius_code == -1)
  1173. proto_registrar_get_byname("radius.code");
  1174. /*
  1175. * In case we throw an exception, clean up whatever stuff we've
  1176. * allocated (if any).
  1177. */
  1178. CLEANUP_PUSH_PFX(la, eap_buffer_free_indirect, &eap_buffer);
  1179. CLEANUP_PUSH_PFX(lb, vsa_buffer_table_destroy_indirect, &vsa_buffer_table);
  1180. while (length > 0) {
  1181. radius_attr_info_t *dictionary_entry = NULL;
  1182. guint32 avp_type0 = 0, avp_type1 = 0;
  1183. radius_attr_type_t avp_type;
  1184. guint32 avp_length;
  1185. guint32 vendor_id;
  1186. gboolean avp_is_extended = FALSE;
  1187. int avp_offset_start = offset;
  1188. proto_item *avp_item;
  1189. proto_item *avp_len_item;
  1190. proto_tree *avp_tree;
  1191. if (length < 2) {
  1192. proto_tree_add_expert_format(tree, pinfo, &ei_radius_invalid_length, tvb, offset, 0,
  1193. "Not enough room in packet for AVP header");
  1194. break; /* exit outer loop, then cleanup & return */
  1195. }
  1196. avp_type0 = tvb_get_guint8(tvb, offset);
  1197. avp_length = tvb_get_guint8(tvb, offset+1);
  1198. avp_is_extended = RADIUS_ATTR_TYPE_IS_EXTENDED(avp_type0);
  1199. if (avp_is_extended) {
  1200. avp_type1 = tvb_get_guint8(tvb, offset+2);
  1201. }
  1202. memset(&avp_type, 0, sizeof(avp_type));
  1203. avp_type.u8_code[0] = avp_type0;
  1204. avp_type.u8_code[1] = avp_type1;
  1205. if (disable_extended_attributes) {
  1206. avp_is_extended = FALSE;
  1207. avp_type.u8_code[1] = 0;
  1208. }
  1209. if (avp_length < 2) {
  1210. proto_tree_add_expert_format(tree, pinfo, &ei_radius_invalid_length, tvb, offset, 0,
  1211. "AVP too short: length %u < 2", avp_length);
  1212. break; /* exit outer loop, then cleanup & return */
  1213. }
  1214. if (avp_is_extended && avp_length < 3) {
  1215. proto_tree_add_expert_format(tree, pinfo, &ei_radius_invalid_length, tvb, offset, 0,
  1216. "Extended AVP too short: length %u < 3", avp_length);
  1217. break; /* exit outer loop, then cleanup & return */
  1218. }
  1219. if (length < avp_length) {
  1220. proto_tree_add_expert_format(tree, pinfo, &ei_radius_invalid_length, tvb, offset, 0,
  1221. "Not enough room in packet for AVP");
  1222. break; /* exit outer loop, then cleanup & return */
  1223. }
  1224. length -= avp_length;
  1225. dictionary_entry = (radius_attr_info_t *)g_hash_table_lookup(dict->attrs_by_id, GUINT_TO_POINTER(avp_type.value));
  1226. if (!dictionary_entry) {
  1227. dictionary_entry = &no_dictionary_entry;
  1228. }
  1229. avp_item = proto_tree_add_bytes_format_value(tree, hf_radius_avp, tvb, offset, avp_length,
  1230. NULL, "t=%s", dictionary_entry->name);
  1231. if (avp_is_extended)
  1232. proto_item_append_text(avp_item, "(%u.%u)", avp_type0, avp_type1);
  1233. else
  1234. proto_item_append_text(avp_item, "(%u)", avp_type0);
  1235. proto_item_append_text(avp_item, " l=%u", avp_length);
  1236. avp_length -= 2;
  1237. offset += 2;
  1238. if (avp_is_extended) {
  1239. avp_length -= 1;
  1240. offset += 1;
  1241. if (RADIUS_ATTR_TYPE_IS_EXTENDED_LONG(avp_type0)) {
  1242. avp_length -= 1;
  1243. offset += 1;
  1244. }
  1245. }
  1246. if (avp_type0 == RADIUS_ATTR_TYPE_VENDOR_SPECIFIC || (avp_is_extended && avp_type1 == RADIUS_ATTR_TYPE_VENDOR_SPECIFIC)) {
  1247. radius_vendor_info_t *vendor;
  1248. proto_tree *vendor_tree;
  1249. gint max_offset = offset + avp_length;
  1250. const gchar *vendor_str;
  1251. int vendor_offset;
  1252. /* XXX TODO: handle 2 byte codes for USR */
  1253. if (avp_length < 4) {
  1254. expert_add_info_format(pinfo, avp_item, &ei_radius_invalid_length, "AVP too short; no room for vendor ID");
  1255. offset += avp_length;
  1256. continue; /* while (length > 0) */
  1257. }
  1258. vendor_id = tvb_get_ntohl(tvb, offset);
  1259. avp_length -= 4;
  1260. offset += 4;
  1261. vendor = (radius_vendor_info_t *)g_hash_table_lookup(dict->vendors_by_id, GUINT_TO_POINTER(vendor_id));
  1262. vendor_str = enterprises_lookup(vendor_id, "Unknown");
  1263. if (!vendor) {
  1264. vendor = &no_vendor;
  1265. }
  1266. proto_item_append_text(avp_item, " vnd=%s(%u)", vendor_str,
  1267. vendor_id);
  1268. vendor_tree = proto_item_add_subtree(avp_item, vendor->ett);
  1269. vendor_offset = avp_offset_start;
  1270. proto_tree_add_item(vendor_tree, hf_radius_avp_type, tvb, vendor_offset, 1, ENC_BIG_ENDIAN);
  1271. proto_tree_add_item(vendor_tree, hf_radius_avp_length, tvb, vendor_offset+1, 1, ENC_BIG_ENDIAN);
  1272. vendor_offset += 2;
  1273. if (avp_is_extended) {
  1274. proto_tree_add_item(vendor_tree, hf_radius_avp_extended_type, tvb, vendor_offset, 1, ENC_BIG_ENDIAN);
  1275. vendor_offset += 1;
  1276. if (RADIUS_ATTR_TYPE_IS_EXTENDED_LONG(avp_type0)) {
  1277. proto_tree_add_item(vendor_tree, hf_radius_avp_extended_more, tvb, vendor_offset, 1, ENC_BIG_ENDIAN);
  1278. vendor_offset += 1;
  1279. }
  1280. }
  1281. proto_tree_add_uint_format_value(vendor_tree, hf_radius_avp_vendor_id, tvb, vendor_offset, 4, vendor_id, "%s (%u)", vendor_str, vendor_id);
  1282. vendor_offset += 4;
  1283. while (offset < max_offset) {
  1284. radius_attr_type_t vendor_type;
  1285. guint32 avp_vsa_type;
  1286. guint32 avp_vsa_len;
  1287. guint8 avp_vsa_flags = 0;
  1288. guint32 avp_vsa_header_len;
  1289. guint32 vendor_attribute_len;
  1290. switch (vendor->type_octets) {
  1291. case 1:
  1292. avp_vsa_type = tvb_get_guint8(tvb, offset++);
  1293. break;