1 /* packet-lon.c
2  * Traffic analyzer for Lontalk/EIA-709.1 networks
3  * Daniel Willmann <daniel@totalueberwachung.de>
4  * (c) 2011 Daniel Willmann
5  *
6  * Used some code by habibi_khalid <khalidhabibi@gmx.de> and
7  * Honorine_KEMGNE_NGUIFFO <honorinekemgne@yahoo.fr> from
8  * https://gitlab.com/wireshark/wireshark/-/issues/4704
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 
17 #include "config.h"
18 
19 #include <epan/packet.h>
20 #include <epan/expert.h>
21 
22 void proto_register_lon(void);
23 void proto_reg_handoff_lon(void);
24 
25 static const value_string pdu_fmt_vs[]=
26 {
27 	{0x00, "TPDU"},
28 	{0x01, "SPDU"},
29 	{0x02, "AuthPDU"},
30 	{0x03, "APDU"},
31 	{0, NULL}
32 };
33 
34 static const value_string addr_fmt_vs[]=
35 {
36 	{0x00, "Broadcast (0)"},
37 	{0x01, "Multicast (1)"},
38 	{0x02, "Unicast (2a)/Multicast (2b)"},
39 	{0x03, "Unicast (3)"},
40 	{0, NULL}
41 };
42 
43 static const value_string domain_length_vs[]=
44 {
45 	{0x00, "0 bit"},
46 	{0x01, "8 bit"},
47 	{0x02, "24 bit"},
48 	{0x03, "48 bit"},
49 	{0, NULL}
50 };
51 
52 static const value_string tpdu_type_vs[]=
53 {
54 	{0x00, "ACKD"},
55 	{0x01, "UnACKD_RPT"},
56 	{0x02, "ACK"},
57 	{0x04, "REMINDER"},
58 	{0x05, "REM/MSG"},
59 	{0, NULL}
60 };
61 
62 static const value_string spdu_type_vs[]=
63 {
64 	{0x00, "REQUEST"},
65 	{0x02, "RESPONSE"},
66 	{0x04, "REMINDER"},
67 	{0x05, "REM/MSG"},
68 	{0, NULL}
69 };
70 
71 static const value_string authpdu_type_vs[]=
72 {
73 	{0x00, "CHALLENGE"},
74 	{0x02, "REPLY"},
75 	{0, NULL}
76 };
77 
78 static const value_string nm_code_vs[]=
79 {
80 	{0x61, "NM_QUERY_ID"},
81 	{0x62, "NM_RESPOND_TO_QUERY"},
82 	{0x63, "NM_UPDATE_DOMAIN"},
83 	{0x64, "NM_LEAVE_DOMAIN"},
84 	{0x65, "NM_UPDATE_KEY"},
85 	{0x66, "NM_UPDATE_ADDR"},
86 	{0x67, "NM_QUERY_ADDR"},
87 	{0x68, "NM_QUERY_NV_CNFG"},
88 	{0x69, "NM_UPDATE_GROUP_ADDR"},
89 	{0x6A, "NM_QUERY_DOMAIN"},
90 	{0x6B, "NM_UPDATE_NV_CNFG"},
91 	{0x6C, "NM_SET_NODE_MODE"},
92 	{0x6D, "NM_READ_MEMORY"},
93 	{0x6E, "NM_WRITE_MEMORY"},
94 	{0x6F, "NM_CHECKSUM_RECALC"},
95 	{0x70, "NM_WINK"},
96 	{0x71, "NM_MEMORY_REFRESH"},
97 	{0x72, "NM_QUERY_SNVT"},
98 	{0x73, "NM_NV_FETCH"},
99 	{0x7F, "NM_MANUAL_SERVICE_REQUEST"},
100 	{ 0, NULL}
101 };
102 
103 static const value_string nd_code_vs[]=
104 {
105 	{0x51, "ND_QUERY_STATUS"},
106 	{0x52, "ND_PROXY_COMMAND"},
107 	{0x53, "ND_CLEAR_STATUS"},
108 	{0x54, "ND_QUERY_XCVR"},
109 	{0, NULL}
110 };
111 
112 static gint hf_lon_ppdu			= -1;
113 static gint hf_lon_ppdu_prio		= -1;
114 static gint hf_lon_ppdu_alt		= -1;
115 static gint hf_lon_ppdu_deltabl		= -1;
116 static gint hf_lon_npdu			= -1;
117 static gint hf_lon_npdu_version		= -1;
118 static gint hf_lon_npdu_pdu_fmt		= -1;
119 static gint hf_lon_npdu_addr_fmt	= -1;
120 static gint hf_lon_npdu_dom_len		= -1;
121 static gint hf_lon_addr_srcsub		= -1;
122 static gint hf_lon_addr_srcnode		= -1;
123 static gint hf_lon_addr_dstsub		= -1;
124 static gint hf_lon_addr_dstgrp		= -1;
125 static gint hf_lon_addr_dstnode		= -1;
126 static gint hf_lon_addr_grp		= -1;
127 static gint hf_lon_addr_grpmem		= -1;
128 static gint hf_lon_addr_uid		= -1;
129 static gint hf_lon_name			= -1;
130 static gint hf_lon_domain		= -1;
131 static gint hf_lon_tpdu			= -1;
132 static gint hf_lon_auth			= -1;
133 static gint hf_lon_tpdu_tpdu_type	= -1;
134 static gint hf_lon_trans_no		= -1;
135 static gint hf_lon_spdu			= -1;
136 static gint hf_lon_spdu_spdu_type	= -1;
137 static gint hf_lon_mlen			= -1;
138 static gint hf_lon_mlist		= -1;
139 static gint hf_lon_authpdu		= -1;
140 static gint hf_lon_authpdu_fmt		= -1;
141 static gint hf_lon_authpdu_authpdu_type	= -1;
142 static gint hf_lon_nv_dir		= -1;
143 static gint hf_lon_nv_selector		= -1;
144 static gint hf_lon_app_code		= -1;
145 static gint hf_lon_nm_code		= -1;
146 static gint hf_lon_nd_code		= -1;
147 static gint hf_lon_ff_code		= -1;
148 static gint hf_lon_nv			= -1;
149 static gint hf_lon_app			= -1;
150 static gint hf_lon_nm			= -1;
151 static gint hf_lon_nd			= -1;
152 static gint hf_lon_ff			= -1;
153 /* static gint hf_lon_checksum		= -1; */
154 static gint proto_lon			= -1;
155 
156 
157 static gint ett_lon                     = -1;
158 static gint ett_ppdu			= -1;
159 static gint ett_npdu			= -1;
160 static gint ett_tpdu                    = -1;
161 static gint ett_spdu                    = -1;
162 static gint ett_authpdu                 = -1;
163 static gint ett_apdu                    = -1;
164 static gint ett_nv                      = -1;
165 static gint ett_app                     = -1;
166 static gint ett_nm                      = -1;
167 static gint ett_nd                      = -1;
168 static gint ett_ff                      = -1;
169 
170 static gint ett_address			= -1;
171 
172 static expert_field ei_lon_tpdu_tpdu_type_unknown = EI_INIT;
173 static expert_field ei_lon_tpdu_spdu_type_unknown = EI_INIT;
174 static expert_field ei_lon_tpdu_authpdu_type_unknown = EI_INIT;
175 static expert_field ei_lon_tpdu_apdu_dest_type = EI_INIT;
176 
177 static gint dissect_apdu(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb,
178 		gint offset);
179 
180 static gint
dissect_lon(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)181 dissect_lon(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
182 {
183 	gint offset = 0;
184 
185 	gint pdu_fmt, addr_fmt, dom_len, pdutype, length;
186 	gint addr_a;
187 
188 	proto_tree *ti;
189 	proto_tree *lon_tree;
190 	gint npdu, type;
191 
192 	col_set_str(pinfo->cinfo, COL_PROTOCOL, "LON");
193 	col_clear(pinfo->cinfo, COL_INFO);
194 
195 	npdu = tvb_get_guint8(tvb, 0);
196 	type = tvb_get_guint8(tvb, 1);
197 	type = (type&0x30)>>4;
198 	col_add_fstr(pinfo->cinfo, COL_INFO,
199 			     "%sDelta_BL: %i Type: %s",
200 			     npdu&0x80?"Priority ":"",
201 			     npdu&0x3F,
202 			     val_to_str_const(type, pdu_fmt_vs, "Unknown"));
203 
204 	ti = proto_tree_add_item(tree, proto_lon, tvb, offset, -1, ENC_NA);
205 	lon_tree = proto_item_add_subtree(ti, ett_lon);
206 
207 	{
208 		static int * const ppdu_fields[] = {
209 			&hf_lon_ppdu_prio,
210 			&hf_lon_ppdu_alt,
211 			&hf_lon_ppdu_deltabl,
212 			NULL
213 		};
214 		proto_tree_add_bitmask(lon_tree, tvb, offset, hf_lon_ppdu,
215 					ett_ppdu, ppdu_fields, ENC_BIG_ENDIAN);
216 		offset++;
217 	}
218 	{
219 		static int * const npdu_fields[] = {
220 			&hf_lon_npdu_version,
221 			&hf_lon_npdu_pdu_fmt,
222 			&hf_lon_npdu_addr_fmt,
223 			&hf_lon_npdu_dom_len,
224 			NULL
225 		};
226 		proto_tree_add_bitmask(lon_tree, tvb, offset, hf_lon_npdu,
227 					ett_npdu, npdu_fields, ENC_BIG_ENDIAN);
228 
229 		pdu_fmt  = (tvb_get_guint8(tvb, offset) >> 4) & 0x03;
230 		addr_fmt = (tvb_get_guint8(tvb, offset) >> 2) & 0x03;
231 		dom_len  = tvb_get_guint8(tvb, offset) & 0x03;
232 		offset++;
233 	}
234 	/* Address part */
235 	switch(addr_fmt)
236 	{
237 	case 0: /* Broadcast */
238 		ti = proto_tree_add_subtree(lon_tree, tvb, offset, 3, ett_address, NULL, "Address type 0 (broadcast)");
239 		proto_tree_add_item(ti, hf_lon_addr_srcsub, tvb, offset, 1, ENC_BIG_ENDIAN);
240 		proto_tree_add_item(ti, hf_lon_addr_srcnode, tvb, offset+1, 1, ENC_BIG_ENDIAN);
241 		proto_tree_add_item(ti, hf_lon_addr_dstsub, tvb, offset+2, 1, ENC_BIG_ENDIAN);
242 		offset += 3;
243 		break;
244 	case 1: /* Multicast */
245 		ti = proto_tree_add_subtree(lon_tree, tvb, offset, 3, ett_address, NULL, "Address type 1 (multicast)");
246 		proto_tree_add_item(ti, hf_lon_addr_srcsub, tvb, offset, 1, ENC_BIG_ENDIAN);
247 		proto_tree_add_item(ti, hf_lon_addr_srcnode, tvb, offset+1, 1, ENC_BIG_ENDIAN);
248 		proto_tree_add_item(ti, hf_lon_addr_dstgrp, tvb, offset+2, 1, ENC_BIG_ENDIAN);
249 		offset += 3;
250 		break;
251 	case 2: /* Unicast/Multicast */
252 		addr_a = tvb_get_guint8(tvb, offset+1) >> 7;
253 		if (addr_a) { /* Type 2a */
254 			ti = proto_tree_add_subtree(lon_tree, tvb, offset, 4, ett_address, NULL, "Address type 2a (unicast)");
255 			proto_tree_add_item(ti, hf_lon_addr_srcsub, tvb, offset, 1, ENC_BIG_ENDIAN);
256 			proto_tree_add_item(ti, hf_lon_addr_srcnode, tvb, offset+1, 1, ENC_BIG_ENDIAN);
257 			proto_tree_add_item(ti, hf_lon_addr_dstsub, tvb, offset+2, 1, ENC_BIG_ENDIAN);
258 			proto_tree_add_item(ti, hf_lon_addr_dstnode, tvb, offset+3, 1, ENC_BIG_ENDIAN);
259 			offset += 4;
260 		} else { /* Type 2b */
261 			ti = proto_tree_add_subtree(lon_tree, tvb, offset, 6, ett_address, NULL, "Address type 2b (multicast)");
262 			proto_tree_add_item(ti, hf_lon_addr_srcsub, tvb, offset, 1, ENC_BIG_ENDIAN);
263 			proto_tree_add_item(ti, hf_lon_addr_srcnode, tvb, offset+1, 1, ENC_BIG_ENDIAN);
264 			proto_tree_add_item(ti, hf_lon_addr_dstgrp, tvb, offset+2, 1, ENC_BIG_ENDIAN);
265 			proto_tree_add_item(ti, hf_lon_addr_dstnode, tvb, offset+3, 1, ENC_BIG_ENDIAN);
266 			proto_tree_add_item(ti, hf_lon_addr_grp, tvb, offset+4, 1, ENC_BIG_ENDIAN);
267 			proto_tree_add_item(ti, hf_lon_addr_grpmem, tvb, offset+5, 1, ENC_BIG_ENDIAN);
268 			offset += 6;
269 		}
270 		break;
271 	case 3: /* UID */
272 		ti = proto_tree_add_subtree(lon_tree, tvb, offset, 9, ett_address, NULL, "Address type 3 (UID)");
273 		proto_tree_add_item(ti, hf_lon_addr_srcsub, tvb, offset, 1, ENC_BIG_ENDIAN);
274 		proto_tree_add_item(ti, hf_lon_addr_srcnode, tvb, offset+1, 1, ENC_BIG_ENDIAN);
275 		proto_tree_add_item(ti, hf_lon_addr_dstsub, tvb, offset+2, 1, ENC_BIG_ENDIAN);
276 		proto_tree_add_item(ti, hf_lon_addr_uid, tvb, offset+3, 6, ENC_NA);
277 		offset += 9;
278 		break;
279 	}
280 	/* END Address part */
281 	/* Domain */
282 	switch(dom_len)
283 	{
284 	case 0: /* Domain-wide */
285 		proto_tree_add_bytes_format(lon_tree, hf_lon_domain, tvb, offset, 0, NULL, "Domain wide addressing");
286 		break;
287 	case 1:
288 		proto_tree_add_item(lon_tree, hf_lon_domain, tvb, offset, 1, ENC_NA);
289 		offset++;
290 		break;
291 	case 2:
292 		proto_tree_add_item(lon_tree, hf_lon_domain, tvb, offset, 3, ENC_NA);
293 		offset += 3;
294 		break;
295 	case 3:
296 		proto_tree_add_item(lon_tree, hf_lon_domain, tvb, offset, 6, ENC_NA);
297 		offset += 6;
298 		break;
299 	}
300 	/* END Domain */
301 	/* *PDU */
302 	switch(pdu_fmt)
303 	{
304 	case 0:        /* TPDU */
305 		{
306 		static int * const tpdu_fields[] = {
307 			&hf_lon_auth,
308 			&hf_lon_tpdu_tpdu_type,
309 			&hf_lon_trans_no,
310 			NULL
311 		};
312 		proto_tree_add_bitmask(lon_tree, tvb, offset, hf_lon_tpdu,
313 					ett_tpdu, tpdu_fields, ENC_BIG_ENDIAN);
314 
315 		pdutype = (tvb_get_guint8(tvb, offset)>>4)& 0x07;
316 		offset++;
317 		switch(pdutype)
318 		{
319 		case 0:
320 		case 1: /* ACKD and UnACKD_RPT */
321 			offset += dissect_apdu(lon_tree, pinfo, tvb, offset);
322 			break;
323 		case 2: /* ACK */
324 			break;
325 		case 4: /* REMINDER */
326 			length = tvb_get_guint8(tvb, offset);
327 			proto_tree_add_item(lon_tree, hf_lon_mlen, tvb, offset, 1, ENC_BIG_ENDIAN);
328 			offset++;
329 			proto_tree_add_item(lon_tree, hf_lon_mlist, tvb, offset, length, ENC_BIG_ENDIAN);
330 			offset += length;
331 			break;
332 		case 5: /* REM/MSG */
333 			length = tvb_get_guint8(tvb, offset);
334 			proto_tree_add_item(lon_tree, hf_lon_mlen, tvb, offset, 1, ENC_BIG_ENDIAN);
335 			offset++;
336 			if (length > 0)
337 				proto_tree_add_item(lon_tree, hf_lon_mlist, tvb, offset, length, ENC_BIG_ENDIAN);
338 			offset += length;
339 			offset += dissect_apdu(lon_tree, pinfo, tvb, offset);
340 			break;
341 		default:
342 			expert_add_info_format(pinfo, lon_tree, &ei_lon_tpdu_tpdu_type_unknown, "Unexpected TPDU type %i", pdutype);
343 			break;
344 		}
345 		}
346 		break;
347 	case 1: /* SPDU */
348 		{
349 		static int * const spdu_fields[] = {
350 			&hf_lon_auth,
351 			&hf_lon_spdu_spdu_type,
352 			&hf_lon_trans_no,
353 			NULL
354 		};
355 		proto_tree_add_bitmask(lon_tree, tvb, offset, hf_lon_spdu,
356 					ett_spdu, spdu_fields, ENC_BIG_ENDIAN);
357 		pdutype = (tvb_get_guint8(tvb, offset)>>4)& 0x07;
358 		offset++;
359 		switch(pdutype)
360 		{
361 		case 0: /* REQUEST */
362 			offset += dissect_apdu(lon_tree, pinfo, tvb, offset);
363 			break;
364 		case 2: /* RESPONSE */
365 			offset += dissect_apdu(lon_tree, pinfo, tvb, offset);
366 			break;
367 		case 4: /* REMINDER */
368 			length = tvb_get_guint8(tvb, offset);
369 			proto_tree_add_item(lon_tree, hf_lon_mlen, tvb, offset, 1, ENC_BIG_ENDIAN);
370 			offset++;
371 			proto_tree_add_item(lon_tree, hf_lon_mlist, tvb, offset, length, ENC_BIG_ENDIAN);
372 			offset += length;
373 			break;
374 		case 5: /* REM/MSG */
375 			length = tvb_get_guint8(tvb, offset);
376 			proto_tree_add_item(lon_tree, hf_lon_mlen, tvb, offset, 1, ENC_BIG_ENDIAN);
377 			offset++;
378 			if (length > 0)
379 				proto_tree_add_item(lon_tree, hf_lon_mlist, tvb, offset, length, ENC_BIG_ENDIAN);
380 			offset += length;
381 			offset += dissect_apdu(lon_tree, pinfo, tvb, offset);
382 			break;
383 		default:
384 			expert_add_info_format(pinfo, lon_tree, &ei_lon_tpdu_spdu_type_unknown, "Unexpected SPDU type %i", pdutype);
385 			break;
386 		}
387 		}
388 		break;
389 	case 2: /* AuthPDU */
390 		{
391 		static int * const authpdu_fields[] = {
392 			&hf_lon_authpdu_fmt,
393 			&hf_lon_authpdu_authpdu_type,
394 			&hf_lon_trans_no,
395 			NULL
396 		};
397 		proto_tree_add_bitmask(lon_tree, tvb, offset, hf_lon_authpdu,
398 					ett_authpdu, authpdu_fields, ENC_BIG_ENDIAN);
399 
400 		pdutype = (tvb_get_guint8(tvb, offset)>>4)& 0x03;
401 		offset++;
402 		switch(pdutype)
403 		{
404 		case 0: /* CHALLENGE */
405 		case 2: /* REPLY */
406 			offset += 9;
407 			break;
408 		default:
409 			expert_add_info_format(pinfo, lon_tree, &ei_lon_tpdu_authpdu_type_unknown, "Unexpected AuthPDU type %i", pdutype);
410 			break;
411 		}
412 		}
413 		break;
414 	case 3: /* APDU */
415 		offset += dissect_apdu(lon_tree, pinfo, tvb, offset);
416 		break;
417 	}
418 	/* END *PDU */
419 
420 	return offset;
421 }
422 
423 static gint
dissect_apdu(proto_tree * tree,packet_info * pinfo,tvbuff_t * tvb,gint offset)424 dissect_apdu(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb,
425 		gint offset)
426 {
427 	tvbuff_t *next_tvb;
428 	gint old_offset = offset, dest_type;
429 
430 	dest_type = tvb_get_guint8(tvb, offset);
431 
432 	if ((dest_type&0x80) == 0x80) { /* Network variable */
433 		static int * const nv_fields[] = {
434 			&hf_lon_nv_dir,
435 			&hf_lon_nv_selector,
436 			NULL
437 		};
438 		proto_tree_add_bitmask(tree, tvb, offset, hf_lon_nv,
439 					ett_nv, nv_fields, ENC_BIG_ENDIAN);
440 		offset += 2;
441 	} else if ((dest_type&0xc0) == 0) { /* Application */
442 		static int * const app_fields[] = {
443 			&hf_lon_app_code,
444 			NULL
445 		};
446 		proto_tree_add_bitmask(tree, tvb, offset, hf_lon_app,
447 					ett_app, app_fields, ENC_BIG_ENDIAN);
448 		offset++;
449 	} else if ((dest_type&0xe0) == 0x60) { /* Network Management */
450 		static int * const nm_fields[] = {
451 			&hf_lon_nm_code,
452 			NULL
453 		};
454 		proto_tree_add_bitmask(tree, tvb, offset, hf_lon_nm,
455 					ett_nm, nm_fields, ENC_BIG_ENDIAN);
456 		offset++;
457 
458 		if (dest_type == 0x7F) {
459 			proto_tree_add_item(tree, hf_lon_addr_uid, tvb, offset, 6, ENC_NA);
460 			offset += 6;
461 			proto_tree_add_item(tree, hf_lon_name, tvb, offset, 8, ENC_NA);
462 			offset += 8;
463 		}
464 
465 	} else if ((dest_type&0xf0) == 0x50) { /* Network Diagnostic */
466 		static int * const nd_fields[] = {
467 			&hf_lon_nd_code,
468 			NULL
469 		};
470 		proto_tree_add_bitmask(tree, tvb, offset, hf_lon_nd,
471 					ett_nd, nd_fields, ENC_BIG_ENDIAN);
472 		offset++;
473 	} else if ((dest_type&0xf0) == 0x40) { /* Foreign Frame */
474 		static int * const ff_fields[] = {
475 			&hf_lon_ff_code,
476 			NULL
477 		};
478 		proto_tree_add_bitmask(tree, tvb, offset, hf_lon_ff,
479 					ett_ff, ff_fields, ENC_BIG_ENDIAN);
480 		offset++;
481 	} else { /* Shouldn't get here */
482 		expert_add_info_format(pinfo, tree, &ei_lon_tpdu_apdu_dest_type, "Malformed APDU destin&type %i", dest_type);
483 	}
484 
485 	next_tvb = tvb_new_subset_remaining(tvb, offset);
486 
487 	return offset - old_offset + call_data_dissector(next_tvb, pinfo, tree);
488 }
489 
490 void
proto_register_lon(void)491 proto_register_lon(void)
492 {
493 	static hf_register_info hf[] =
494 	{
495 		{&hf_lon_ppdu,
496 			{"PPDU", "lon.ppdu",
497 			FT_UINT8, BASE_HEX, NULL, 0,
498 			NULL, HFILL }
499 		},
500 		{&hf_lon_ppdu_prio,
501 			{"Priority", "lon.prio",
502 			FT_UINT8, BASE_DEC, NULL, 0x80,
503 			"Priority packet", HFILL }
504 		},
505 		{&hf_lon_ppdu_alt,
506 			{"Alt path", "lon.alt_path",
507 			FT_UINT8, BASE_DEC, NULL, 0x40,
508 			"Alternate path", HFILL }
509 		},
510 		{&hf_lon_ppdu_deltabl,
511 			{"Delta BL", "lon.delta_bl",
512 			FT_UINT8, BASE_DEC, NULL, 0x3f,
513 			"How many packets to expect from this one", HFILL }
514 		},
515 		{&hf_lon_npdu,
516 			{"NPDU", "lon.npdu",
517 			FT_UINT8, BASE_DEC, NULL, 0,
518 			NULL, HFILL }
519 		},
520 		{&hf_lon_npdu_version,
521 			{"version", "lon.vers",
522 			FT_UINT8, BASE_HEX, NULL, 0xc0,
523 			"LON protocol version", HFILL }
524 		},
525 		{&hf_lon_npdu_pdu_fmt,
526 			{"PDU format", "lon.pdufmt",
527 			FT_UINT8, BASE_HEX, VALS(pdu_fmt_vs), 0x30,
528 			NULL, HFILL }
529 		},
530 		{&hf_lon_npdu_addr_fmt,
531 			{"Address format", "lon.addrfmt",
532 			FT_UINT8, BASE_HEX, VALS(addr_fmt_vs), 0x0c,
533 			NULL, HFILL }
534 		},
535 		{&hf_lon_npdu_dom_len,
536 			{"Domain length", "lon.domainlen",
537 			FT_UINT8, BASE_HEX, VALS(domain_length_vs), 0x03,
538 			NULL, HFILL }
539 		},
540 		{&hf_lon_addr_srcsub,
541 			{"Source subnet", "lon.srcnet",
542 			FT_UINT8, BASE_HEX, NULL, 0,
543 			NULL, HFILL }
544 		},
545 		{&hf_lon_addr_srcnode,
546 			{"Source node", "lon.srcnode",
547 			FT_UINT8, BASE_HEX, NULL, 0x7f,
548 			NULL, HFILL }
549 		},
550 		{&hf_lon_addr_dstsub,
551 			{"Destination subnet", "lon.dstnet",
552 			FT_UINT8, BASE_HEX, NULL, 0,
553 			NULL, HFILL }
554 		},
555 		{&hf_lon_addr_dstgrp,
556 			{"Destination group", "lon.dstgrp",
557 			FT_UINT8, BASE_HEX, NULL, 0,
558 			NULL, HFILL }
559 		},
560 		{&hf_lon_addr_dstnode,
561 			{"Destination node", "lon.dstnode",
562 			FT_UINT8, BASE_HEX, NULL, 0x7f,
563 			NULL, HFILL }
564 		},
565 		{&hf_lon_addr_grp,
566 			{"Group", "lon.grp",
567 			FT_UINT8, BASE_HEX, NULL, 0,
568 			NULL, HFILL }
569 		},
570 		{&hf_lon_addr_grpmem,
571 			{"Group member", "lon.grpmem",
572 			FT_UINT8, BASE_HEX, NULL, 0,
573 			NULL, HFILL }
574 		},
575 		{&hf_lon_addr_uid,
576 			{"Unique node ID", "lon.uid",
577 			FT_BYTES, BASE_NONE, NULL, 0,
578 			NULL, HFILL }
579 		},
580 		{&hf_lon_domain,
581 			{"Domain", "lon.domain",
582 			FT_BYTES, BASE_NONE, NULL , 0,
583 			NULL, HFILL }
584 		},
585 		{&hf_lon_tpdu,
586 			{"TPDU", "lon.tpdu",
587 			FT_UINT8, BASE_HEX, NULL, 0,
588 			NULL, HFILL }
589 		},
590 		{&hf_lon_auth,
591 			{"Auth", "lon.auth",
592 			FT_UINT8, BASE_HEX, NULL, 0x80,
593 			NULL, HFILL }
594 		},
595 		{&hf_lon_tpdu_tpdu_type,
596 			{"TPDU type", "lon.tpdu_type",
597 			FT_UINT8, BASE_HEX, VALS(tpdu_type_vs), 0x70,
598 			NULL, HFILL }
599 		},
600 		{&hf_lon_trans_no,
601 			{"Transaction number", "lon.trans_no",
602 			FT_UINT8, BASE_HEX, NULL, 0x0f,
603 			NULL, HFILL }
604 		},
605 		{&hf_lon_spdu,
606 			{"SPDU", "lon.spdu",
607 			FT_UINT8, BASE_HEX, NULL, 0,
608 			NULL, HFILL }
609 		},
610 		{&hf_lon_spdu_spdu_type,
611 			{"SPDU type", "lon.spdu_type",
612 			FT_UINT8, BASE_HEX, VALS(spdu_type_vs), 0x70,
613 			NULL, HFILL }
614 		},
615 		{&hf_lon_mlen,
616 			{"Length of M_List", "lon.spdu.mlen",
617 			FT_UINT8, BASE_HEX, NULL, 0,
618 			NULL, HFILL }
619 		},
620 		{&hf_lon_mlist,
621 			{"M_List", "lon.spdu.mlist",
622 			FT_UINT8, BASE_HEX, NULL, 0,
623 			NULL, HFILL }
624 		},
625 		{&hf_lon_authpdu,
626 			{"AuthPDU", "lon.authpdu",
627 			FT_UINT8, BASE_HEX, NULL, 0,
628 			NULL, HFILL }
629 		},
630 		{&hf_lon_authpdu_fmt,
631 			{"FMT (same as AddrFmt)", "lon.authpdu_addrfmt",
632 			FT_UINT8, BASE_HEX, NULL, 0xc,
633 			NULL, HFILL }
634 		},
635 		{&hf_lon_authpdu_authpdu_type,
636 			{"AuthPDU type", "lon.authpdu_type",
637 			FT_UINT8, BASE_HEX, VALS(authpdu_type_vs), 0x2,
638 			NULL, HFILL }
639 		},
640 		{&hf_lon_nv,
641 			{"Network Variable", "lon.nv",
642 			FT_UINT16, BASE_HEX, NULL, 0,
643 			NULL, HFILL }
644 		},
645 		{&hf_lon_nv_dir,
646 			{"NV direction", "lon.nv.dir",
647 			FT_UINT16, BASE_HEX, NULL, 0x4000,
648 			NULL, HFILL }
649 		},
650 		{&hf_lon_nv_selector,
651 			{"NV selector", "lon.nv.selector",
652 			FT_UINT16, BASE_HEX, NULL, 0x3fff,
653 			NULL, HFILL }
654 		},
655 		{&hf_lon_app,
656 			{"Application", "lon.application",
657 			FT_UINT8, BASE_HEX, NULL, 0,
658 			NULL, HFILL }
659 		},
660 		{&hf_lon_app_code,
661 			{"Code", "lon.code",
662 			FT_UINT8, BASE_HEX, NULL, 0x3f,
663 			NULL, HFILL }
664 		},
665 		{&hf_lon_nm,
666 			{"Network Management", "lon.nm",
667 			FT_UINT8, BASE_HEX, NULL, 0,
668 			NULL, HFILL }
669 		},
670 		{&hf_lon_nm_code,
671 			{"Code", "lon.code",
672 			FT_UINT8, BASE_HEX, VALS(nm_code_vs), 0xff,
673 			NULL, HFILL }
674 		},
675 		{&hf_lon_nd,
676 			{"Network Diagnostic", "lon.nd",
677 			FT_UINT8, BASE_HEX, NULL, 0,
678 			NULL, HFILL }
679 		},
680 		{&hf_lon_nd_code,
681 			{"Code", "lon.code",
682 			FT_UINT8, BASE_HEX, VALS(nd_code_vs), 0xff,
683 			NULL, HFILL }
684 		},
685 		{&hf_lon_ff,
686 			{"Foreign Frame", "lon.ff",
687 			FT_UINT8, BASE_HEX, NULL, 0,
688 			NULL, HFILL }
689 		},
690 		{&hf_lon_ff_code,
691 			{"Code", "lon.code",
692 			FT_UINT8, BASE_HEX, NULL, 0x0f,
693 			NULL, HFILL }
694 		},
695 		{&hf_lon_name,
696 			{"Node name", "lon.name",
697 			FT_BYTES, BASE_NONE, NULL, 0,
698 			NULL, HFILL }
699 		},
700 #if 0
701 		{&hf_lon_checksum,
702 			{"Checksum", "lon.chksum",
703 			FT_BYTES, BASE_NONE, NULL, 0,
704 			NULL, HFILL }
705 		}
706 #endif
707 	};
708 
709 	static gint *ett[] =
710 	{
711 		&ett_lon,
712 		&ett_address,
713 		&ett_ppdu,
714 		&ett_npdu,
715 		&ett_tpdu,
716 		&ett_spdu,
717 		&ett_authpdu,
718 		&ett_apdu,
719 		&ett_nv,
720 		&ett_app,
721 		&ett_nm,
722 		&ett_nd,
723 		&ett_ff
724 	};
725 
726 	static ei_register_info ei[] = {
727 		{ &ei_lon_tpdu_tpdu_type_unknown, { "lon.tpdu_type.unknown", PI_PROTOCOL, PI_WARN, "Unexpected TPDU type", EXPFILL }},
728 		{ &ei_lon_tpdu_spdu_type_unknown, { "lon.spdu_type.unknown", PI_PROTOCOL, PI_WARN, "Unexpected SPDU type", EXPFILL }},
729 		{ &ei_lon_tpdu_authpdu_type_unknown, { "lon.authpdu_type.unknown", PI_PROTOCOL, PI_WARN, "Unexpected AuthPDU type", EXPFILL }},
730 		{ &ei_lon_tpdu_apdu_dest_type, { "lon.authpdu_dest_type.unknown", PI_PROTOCOL, PI_WARN, "Malformed APDU destin&type", EXPFILL }},
731 	};
732 
733 	expert_module_t* expert_lon;
734 
735 	proto_lon = proto_register_protocol("Local Operating Network",
736 			"LON", "lon");
737 
738 	proto_register_field_array (proto_lon, hf, array_length (hf));
739 	proto_register_subtree_array (ett, array_length (ett));
740 	expert_lon = expert_register_protocol(proto_lon);
741 	expert_register_field_array(expert_lon, ei, array_length(ei));
742 }
743 
744 
745 void
proto_reg_handoff_lon(void)746 proto_reg_handoff_lon(void)
747 {
748 	dissector_handle_t lon_handle;
749 
750 	lon_handle = create_dissector_handle(dissect_lon, proto_lon);
751 
752 	dissector_add_uint("cnip.protocol", 0, lon_handle);
753 }
754 
755 /*
756  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
757  *
758  * Local variables:
759  * c-basic-offset: 8
760  * tab-width: 8
761  * indent-tabs-mode: t
762  * End:
763  *
764  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
765  * :indentSize=8:tabSize=8:noTabs=false:
766  */
767