2 p_nsdp=Proto("nsdp", "Netgear Switch Description Protocol")
4 local f_version=ProtoField.uint8("nsdp.version", "Version", base.DEC)
5 local f_code=ProtoField.uint8("nsdp.code", "Operation Code", base.DEC)
6 local f_error=ProtoField.uint8("nsdp.error", "Error Code", base.DEC)
7 local f_errattr=ProtoField.uint16("nsdp.errattr", "Erroneous Attribute", base.HEX)
8 local f_clientmac=ProtoField.ether("nsdp.clientmac", "Client MAC")
9 local f_switchmac=ProtoField.ether("nsdp.switchmac", "Switch MAC")
10 local f_seqnum=ProtoField.uint32("nsdp.seqnum", "Sequence Number", base.DEC)
13 f_version, f_code, f_error, f_errattr, f_clientmac, f_switchmac, f_seqnum
31 [7]="Invalid Password"
42 local bitrates_codes={
58 local vlan_type_codes={
66 local qos_type_codes={
82 local function dissect_port_statistics (buffer, offset, subtree)
84 subtree:add(buffer(offset+4, 1), string.format("Port: %i", buffer(offset+4, 1):uint()))
85 subtree:add(buffer(offset+4+1+8*0, 8), "Received:", tostring(buffer(offset+4+1+8*0, 8):uint64()))
86 subtree:add(buffer(offset+4+1+8*1, 8), "Sent: ", tostring(buffer(offset+4+1+8*1, 8):uint64()))
87 subtree:add(buffer(offset+4+1+8*5, 8), "CRC Errors:", tostring(buffer(offset+4+1+8*5, 8):uint64()))
93 local function dissect_port_status (buffer, offset, subtree)
95 local st=buffer(offset+5, 1):uint()
96 subtree:add(buffer(offset+4, 1), string.format("Port: %i", buffer(offset+4, 1):uint()))
97 subtree:add(buffer(offset+5, 1), string.format("Status: %i (%s)", st, status_codes[st] or "unk"))
103 local function dissect_qos_type (buffer, offset, subtree)
105 local t=buffer(offset+4, 1):uint()
106 subtree:add(buffer(offset+4, 1), string.format("QoS Type: %i (%s)", t, qos_type_codes[t] or "unk"))
112 local function dissect_qos_config (buffer, offset, subtree)
114 local p=buffer(offset+5, 1):uint()
115 subtree:add(buffer(offset+4, 1), string.format("Port: %i", buffer(offset+4, 1):uint()))
116 subtree:add(buffer(offset+5, 1), string.format("Priority: %i (%s)", p, prio_codes[p] or "unk"))
122 local function dissect_bitrate (buffer, offset, subtree)
124 local sp=buffer(offset+5, 4):uint()
125 subtree:add(buffer(offset+4, 1), string.format("Port: %i", buffer(offset+4, 1):uint()))
126 subtree:add(buffer(offset+5, 4), string.format("Speed: %i (%s)", sp, bitrates_codes[sp] or "unk"))
132 local function dissect_vlan_type (buffer, offset, subtree)
134 local vt=buffer(offset+4, 1):uint()
135 subtree:add(buffer(offset+4, 1), string.format("VLAN Type: %i (%s)", vt, vlan_type_codes[vt] or "unk"))
141 local function parse_ports (val)
149 val=math.floor(val/2)
158 local function dissect_vlan_port_conf (buffer, offset, subtree)
160 subtree:add(buffer(offset+4, 2), string.format("VLAN: %u", buffer(offset+4, 2):uint()))
162 if ( buffer(offset+2, 2):uint()>=3 ) then
163 subtree:add(buffer(offset+6, 1), "Ports:", parse_ports(buffer(offset+6, 1):uint()))
170 local function dissect_vlan_8021q_conf (buffer, offset, subtree)
172 subtree:add(buffer(offset+4, 2), string.format("VLAN: %u", buffer(offset+4, 2):uint()))
174 if ( buffer(offset+2, 2):uint()>=4 ) then
175 subtree:add(buffer(offset+6, 1), "Ports:", parse_ports(buffer(offset+6, 1):uint()))
176 subtree:add(buffer(offset+7, 1), "Tagged Ports:", parse_ports(buffer(offset+7, 1):uint()))
183 local function dissect_vlan_pvid (buffer, offset, subtree)
185 subtree:add(buffer(offset+4, 1), string.format("Port: %i", buffer(offset+4, 1):uint()))
186 subtree:add(buffer(offset+5, 2), string.format("VLAN: %u", buffer(offset+5, 2):uint()))
192 local function dissect_mirror (buffer, offset, subtree)
194 local op=buffer(offset+4, 1):uint()
197 subtree:add(buffer(offset+4, 1), "Disabled")
199 subtree:add(buffer(offset+4, 1), "Output Port:", op)
200 subtree:add(buffer(offset+6, 1), "Ports:", parse_ports(buffer(offset+6, 1):uint()))
207 local function dissect_igmp_enablevlan (buffer, offset, subtree)
209 subtree:add(buffer(offset+4, 2), string.format("Enable: %u", buffer(offset+4, 2):uint()))
210 subtree:add(buffer(offset+6, 2), string.format("VLAN: %u", buffer(offset+6, 2):uint()))
218 [0x0001]={name="Product", dissect="string"},
219 [0x0003]={name="Name", dissect="string"},
220 [0x0004]={name="MAC", dissect="ether"},
221 [0x0006]={name="IP", dissect="ipv4"},
222 [0x0007]={name="Mask", dissect="ipv4"},
223 [0x0008]={name="Gateway", dissect="ipv4"},
224 [0x0009]={name="New Password", dissect="string"},
225 [0x000A]={name="Password", dissect="string"},
226 [0x000B]={name="DHCP", dissect="uint"},
227 [0x000D]={name="Firmware Version", dissect="string"},
228 [0x0010]={name="Firmware Upgrade", dissect="uint"},
229 [0x0013]={name="Restart", dissect="uint"},
230 [0x0400]={name="Defaults", dissect="uint"},
231 [0x0C00]={name="Port Status", dissect=dissect_port_status},
232 [0x1000]={name="Port Statistics", dissect=dissect_port_statistics},
233 [0x1400]={name="Reset Ports Statistics", dissect="uint"},
234 [0x1800]={name="Cabletest Do", dissect=nil},
235 [0x1C00]={name="Cabletest Result", dissect=nil},
236 [0x2000]={name="VLAN Type", dissect=dissect_vlan_type},
237 [0x2400]={name="VLAN Port Conf", dissect=dissect_vlan_port_conf},
238 [0x2800]={name="VLAN 802.1Q Conf", dissect=dissect_vlan_8021q_conf},
239 [0x2C00]={name="Destroy VLAN", dissect="uint"},
240 [0x3000]={name="VLAN PVID", dissect=dissect_vlan_pvid},
241 [0x3400]={name="QoS Type", dissect=dissect_qos_type},
242 [0x3800]={name="QoS Config", dissect=dissect_qos_config},
243 [0x4C00]={name="Input Bitrate", dissect=dissect_bitrate},
244 [0x5000]={name="Output Bitrate", dissect=dissect_bitrate},
245 [0x5400]={name="Broadcast Filtering State", dissect="uint"},
246 [0x5800]={name="Broadcast Filtering Bitrate", dissect=dissect_bitrate},
247 [0x5C00]={name="Mirror", dissect=dissect_mirror},
248 [0x6000]={name="Ports Count", dissect="uint"},
249 [0x6800]={name="IGMP Enable & VLAN", dissect=dissect_igmp_enablevlan},
250 [0x6C00]={name="Block Unknown IGMP Addresses", dissect="uint"},
251 [0x7000]={name="Validate IGMPv3 Headers", dissect="uint"},
252 [0xFFFF]={name="End", dissect=nil}
260 local function dissect_header (buffer, subtree)
262 subtree:add(f_version, buffer(0, 1))
264 subtree:add(f_code, buffer(1, 1)):append_text(" ("..(op_codes[buffer(1, 1):uint()] or "unknown")..")")
266 local errcode=buffer(2, 1):uint()
267 subtree:add(f_error, buffer(2, 1)):append_text(" ("..(error_codes[errcode] or "unknown")..")")
269 -- add the erroneous attribute only if an error occurred
270 if ( errcode~=0 ) then
271 local atf=attributes[buffer(4, 2):uint()]
272 subtree:add(f_errattr, buffer(4, 2)):append_text(" ("..(atf and atf.name or "unk")..")")
275 subtree:add(f_clientmac, buffer(8, 6))
277 subtree:add(f_switchmac, buffer(14, 6))
279 subtree:add(f_seqnum, buffer(20, 4))
286 local function dissect_attributes (buffer, subtree)
290 while ( offset<buffer:len() ) do
292 if ( offset+4>buffer:len() ) then
293 -- no room for an attribute header, it is an error
294 subtree:add(buffer(offset), "Junk"):set_expert_flags(PI_MALFORMED, PI_ERROR)
298 local code=buffer(offset, 2):uint()
299 local len=buffer(offset+2, 2):uint()
300 local atf=attributes[code]
302 local attr=subtree:add(buffer(offset, math.min(4+len, buffer:len()-offset)), string.format("Attribute: 0x%04X (%s)", code, atf and atf.name or "unk"))
303 attr:add(buffer(offset, 2), string.format("Code: 0x%04X", code))
304 attr:add(buffer(offset+2, 2), string.format("Length: %u", len))
306 if ( offset+4+len>buffer:len() ) then
307 -- attribute length is bigger than remaining packet size, it is an error
308 attr:append_text(" [malformed]")
309 attr:set_expert_flags(PI_MALFORMED, PI_ERROR)
315 -- no data, display nothing
316 elseif ( atf==nil or atf.dissect==nil ) then
317 -- unknown attribute, display raw bytes
318 attr:add(buffer(offset+4, len), "Data:", tostring(buffer(offset+4, len):bytes()))
319 elseif ( type(atf.dissect)=="function" ) then
320 -- custom sub-dissector for complex type
321 atf.dissect(buffer, offset, attr)
323 -- simple type, directly show it
324 local func=assert(loadstring("return function(buffer, offset, len) return tostring(buffer(offset+4, len):"..atf.dissect.."()) end"))() -- ugly, isn't it ?
325 attr:add(buffer(offset+4, len), atf.name..":", func(buffer, offset, len))
336 function p_nsdp.dissector (buffer, pinfo, tree)
338 pinfo.cols.protocol=p_nsdp.name
339 local subtree=tree:add(p_nsdp, buffer())
341 -- stop if the packet is too small to be valid
342 if ( buffer:len()<32 ) then return end
344 dissect_header(buffer, subtree)
346 -- stop if it is just a header
347 if ( buffer:len()==32 ) then return end
349 local attr_list=subtree:add(buffer(32), "Attributes list")
350 dissect_attributes(buffer, attr_list)
356 function p_nsdp.init ()
361 local udp_dissector_table=DissectorTable.get("udp.port")
362 dissector=udp_dissector_table:get_dissector(63322)
363 udp_dissector_table:add(63322, p_nsdp)