├── README.md ├── LICENSE └── LonDissector.lua /README.md: -------------------------------------------------------------------------------- 1 | # LonDissector 2 | A LON protocol dissector for Wireshark 3 | 4 | See https://www.g3gg0.de/wordpress/esp32/mes-wifi-bringing-a-windhager-pellet-heater-online/ for an use case 5 | 6 | Place it in %APPDATA%\Wireshark\plugins folder to load on startup. 7 | Reload it using Analyze -> Reload Lua plugins 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 2-Clause License 2 | 3 | Copyright (c) 2022, g3gg0.de 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /LonDissector.lua: -------------------------------------------------------------------------------- 1 | 2 | -- declare our protocol 3 | mes_proto = Proto("Windhager", "Windhager MES-WiFi LON Protocol") 4 | 5 | function getTime(buffer, pos) 6 | local tm_sec = buffer(pos,4):le_uint(); 7 | pos = pos + 4; 8 | local tm_min = buffer(pos,4):le_uint(); 9 | pos = pos + 4; 10 | local tm_hour = buffer(pos,4):le_uint(); 11 | pos = pos + 4; 12 | local tm_mday = buffer(pos,4):le_uint(); 13 | pos = pos + 4; 14 | local tm_mon = buffer(pos,4):le_uint(); 15 | pos = pos + 4; 16 | local tm_year = buffer(pos,4):le_uint(); 17 | pos = pos + 4; 18 | local tm_wday = buffer(pos,4):le_uint(); 19 | pos = pos + 4; 20 | local tm_yday = buffer(pos,4):le_uint(); 21 | pos = pos + 4; 22 | local tm_isdst = buffer(pos,4):le_uint(); 23 | pos = pos + 4; 24 | 25 | if(tm_sec > 60 or tm_min > 60 or tm_hour > 24 or tm_mday > 31 or tm_mon > 11 or tm_year > 300) then 26 | return "failed"; 27 | end 28 | 29 | return string.format("%02d", tm_mday) .. "." .. string.format("%02d", tm_mon+1) .. ".".. (tm_year + 1900) .. " " .. string.format("%02d", tm_hour).. ":" .. string.format("%02d", tm_min) .. ":" .. string.format("%02d", tm_sec); 30 | end 31 | 32 | -- create a function to dissect it 33 | function mes_proto.dissector(buffer, pinfo, tree) 34 | pinfo.cols.protocol = "MES-WiFi" 35 | local subtree = tree:add(mes_proto, buffer(), "MES-WiFi LON") 36 | local meswifi = subtree:add(mes_proto, buffer(), "Frame Info") 37 | local pos = 0; 38 | local msgType = buffer(pos,1):le_uint(); 39 | 40 | local msgTypes = { "System report", "LON Frame" } 41 | local errorCodes = { "none", "Bit time exceeded (stop bit)", "Bit time too short", "Bit phase error", "Buffer overflow", "Sync failed", "CRC Error" } 42 | 43 | meswifi:add(buffer(pos,1),"Message type: " .. msgType .. " (".. msgTypes[msgType] .. ")") 44 | pos = pos + 1; 45 | 46 | local info = ""; 47 | local bitTiming = 80/4; 48 | 49 | if(msgType == 1) then 50 | bitLen = buffer(pos,4):le_uint(); 51 | meswifi:add(buffer(pos,4),"Bit length 0 min: " .. bitLen .. "(" .. string.format("%02.2f",bitLen/bitTiming) .. "us)") 52 | pos = pos + 4; 53 | bitLen = buffer(pos,4):le_uint(); 54 | meswifi:add(buffer(pos,4),"Bit length 0 avg: " .. bitLen .. "(" .. string.format("%02.2f",bitLen/bitTiming) .. "us)") 55 | pos = pos + 4; 56 | bitLen = buffer(pos,4):le_uint(); 57 | meswifi:add(buffer(pos,4),"Bit length 0 max: " .. bitLen .. "(" .. string.format("%02.2f",bitLen/bitTiming) .. "us)") 58 | pos = pos + 4; 59 | bitLen = buffer(pos,4):le_uint(); 60 | meswifi:add(buffer(pos,4),"Bit length 1 min: " .. bitLen .. "(" .. string.format("%02.2f",bitLen/bitTiming) .. "us)") 61 | pos = pos + 4; 62 | bitLen = buffer(pos,4):le_uint(); 63 | meswifi:add(buffer(pos,4),"Bit length 1 avg: " .. bitLen .. "(" .. string.format("%02.2f",bitLen/bitTiming) .. "us)") 64 | pos = pos + 4; 65 | bitLen = buffer(pos,4):le_uint(); 66 | meswifi:add(buffer(pos,4),"Bit length 1 max: " .. bitLen .. "(" .. string.format("%02.2f",bitLen/bitTiming) .. "us)") 67 | pos = pos + 4; 68 | rcvd = buffer(pos,4):le_uint(); 69 | meswifi:add(buffer(pos,4),"Packets received: " .. rcvd) 70 | pos = pos + 4; 71 | crcerr = buffer(pos,4):le_uint(); 72 | meswifi:add(buffer(pos,4),"Packets CRC Errors: " .. crcerr .. " (" .. string.format("%02.2f",crcerr*100/rcvd) .. "%)") 73 | pos = pos + 4; 74 | 75 | local val = buffer(pos,4):le_uint(); 76 | meswifi:add(buffer(pos,4),"Free heap: " .. val) 77 | pos = pos + 4; 78 | val = buffer(pos,4):le_uint(); 79 | meswifi:add(buffer(pos,4),"Max heap: " .. val) 80 | pos = pos + 4; 81 | val = buffer(pos,4):le_uint(); 82 | meswifi:add(buffer(pos,4),"Free PSRAM: " .. val) 83 | pos = pos + 4; 84 | val = buffer(pos,4):le_uint(); 85 | meswifi:add(buffer(pos,4),"Max PSRAM: " .. val) 86 | pos = pos + 4; 87 | 88 | 89 | local timeString = getTime(buffer, pos); 90 | meswifi:add(buffer(pos,4*9),"Startup time: " .. timeString); 91 | pos = pos + 36; 92 | timeString = getTime(buffer, pos); 93 | meswifi:add(buffer(pos,4*9),"Statistics start: " .. timeString); 94 | pos = pos + 36; 95 | val = buffer(pos,4):le_uint(); 96 | meswifi:add(buffer(pos,4),"Ignites/24h: " .. val) 97 | pos = pos + 4; 98 | 99 | local timesStart = pos; 100 | local times = ""; 101 | local ignites = ""; 102 | for hour=0,23 do 103 | times = times .. " "..string.format("%02d", hour); 104 | end 105 | for hour=0,23 do 106 | local sum = 0; 107 | for hour_sub=0,11 do 108 | sum = sum + buffer(pos + hour_sub,1):le_uint(); 109 | end 110 | ignites = ignites .. " "..string.format("%02d", sum); 111 | pos = pos + 12; 112 | end 113 | meswifi:add(buffer(timesStart,pos - timesStart)," Time: " .. times) 114 | meswifi:add(buffer(timesStart,pos - timesStart)," Ignites: " .. ignites) 115 | 116 | val = buffer(pos,4):le_uint(); 117 | meswifi:add(buffer(pos,4),"Temperature: " .. string.format("%02.2f", val / 100.0)) 118 | pos = pos + 4; 119 | 120 | pinfo.cols['info'] = "System report"; 121 | 122 | elseif (msgType == 2) then 123 | local ppdu = subtree:add(mes_proto,buffer(),"PPDU") 124 | local npdu = ppdu:add(mes_proto,buffer(),"NPDU") 125 | local address = npdu:add(mes_proto,buffer(),"Address") 126 | local domain = npdu:add(mes_proto,buffer(),"Domain") 127 | 128 | NV = {}; 129 | TPDU = {}; 130 | SPDU = {}; 131 | APDU = {}; 132 | AuthPDU = {}; 133 | NPDU = {}; 134 | PPDU = {}; 135 | Address = {}; 136 | 137 | local errorCode = buffer(pos,1):uint(); 138 | 139 | meswifi:add(buffer(pos,1),"Error code: " .. errorCode .. " (".. errorCodes[buffer(pos,1):uint() + 1] .. ")") 140 | pos = pos + 1; 141 | meswifi:add(buffer(pos,2),"Bits sampled: " .. buffer(pos,2):le_uint()) 142 | pos = pos + 2; 143 | bitLen = buffer(pos,2):le_uint(); 144 | meswifi:add(buffer(pos,2),"Bit duration: " .. bitLen .. "(" .. string.format("%02.2f",bitLen/8) .. "us)") 145 | pos = pos + 2; 146 | 147 | if(errorCode > 1) then 148 | return; 149 | end 150 | PPDU.Prior = buffer(pos,1):bitfield(0, 1); 151 | PPDU.AltPath = buffer(pos,1):bitfield(1, 1); 152 | PPDU.DeltaBL = buffer(pos,1):bitfield(2, 6); 153 | ppdu:add(buffer(pos,1),"Prior: " .. PPDU.Prior) 154 | ppdu:add(buffer(pos,1),"AltPath: " .. PPDU.AltPath) 155 | ppdu:add(buffer(pos,1),"DeltaBL: " .. PPDU.DeltaBL) 156 | pos = pos + 1; 157 | 158 | NPDU.Version = buffer(pos,1):bitfield(0, 2); 159 | NPDU.PDUFmt = buffer(pos,1):bitfield(2, 2); 160 | NPDU.AddrFmt = buffer(pos,1):bitfield(4, 2); 161 | NPDU.Length = buffer(pos,1):bitfield(6, 2); 162 | pos = pos + 1; 163 | 164 | npdu:add(buffer(pos,1),"Version: " .. NPDU.Version) 165 | npdu:add(buffer(pos,1),"PDUFmt: " .. NPDU.PDUFmt) 166 | npdu:add(buffer(pos,1),"AddrFmt: " .. NPDU.AddrFmt) 167 | npdu:add(buffer(pos,1),"Length: " .. NPDU.Length) 168 | 169 | 170 | if(NPDU.AddrFmt == 0) then 171 | Address.SrcSubnet = buffer(pos,1):bitfield(0, 8); 172 | address:add(buffer(pos,1),"SrcSubnet: " .. Address.SrcSubnet) 173 | pos = pos + 1; 174 | Address.SrcNode = buffer(pos,1):bitfield(1, 7); 175 | address:add(buffer(pos,1),"SrcNode: " .. Address.SrcNode) 176 | pos = pos + 1; 177 | Address.DstSubnet = buffer(pos,1); 178 | address:add(buffer(pos,1),"DstSubnet: " .. Address.DstSubnet) 179 | pos = pos + 1; 180 | elseif(NPDU.AddrFmt == 1) then 181 | Address.SrcSubnet = buffer(pos,1):bitfield(0, 8); 182 | address:add(buffer(pos,1),"SrcSubnet: " .. Address.SrcSubnet) 183 | pos = pos + 1; 184 | Address.SrcNode = buffer(pos,1):bitfield(1, 7); 185 | address:add(buffer(pos,1),"SrcNode: " .. Address.SrcNode) 186 | pos = pos + 1; 187 | Address.DstSubnet = buffer(pos,1); 188 | address:add(buffer(pos,1),"DstSubnet: " .. Address.DstSubnet) 189 | pos = pos + 1; 190 | elseif(NPDU.AddrFmt == 2) then 191 | Address.SrcSubnet = buffer(pos,1):bitfield(0, 8); 192 | address:add(buffer(pos,1),"SrcSubnet: " .. Address.SrcSubnet) 193 | pos = pos + 1; 194 | Address.SubType = buffer(pos,1):bitfield(0, 1); 195 | Address.SrcNode = buffer(pos,1):bitfield(1, 7); 196 | address:add(buffer(pos,1),"SrcNode: " .. Address.SrcNode) 197 | pos = pos + 1; 198 | Address.DstSubnet = buffer(pos,1); 199 | address:add(buffer(pos,1),"DstSubnet: " .. Address.DstSubnet) 200 | pos = pos + 1; 201 | Address.DstNode = buffer(pos,1):bitfield(1, 7); 202 | address:add(buffer(pos,1),"DstNode: " .. Address.DstNode) 203 | pos = pos + 1; 204 | 205 | if(Address.SubType == 0) then 206 | Address.Group = buffer(pos,1); 207 | address:add(buffer(pos,1),"Group: " .. Address.Group) 208 | pos = pos + 1; 209 | Address.GroupMember = buffer(pos,1); 210 | address:add(buffer(pos,1),"GroupMember: " .. Address.GroupMember) 211 | pos = pos + 1; 212 | end 213 | elseif(NPDU.AddrFmt == 3) then 214 | Address.SrcSubnet = buffer(pos,1):bitfield(0, 8); 215 | address:add(buffer(pos,1),"SrcSubnet: " .. Address.SrcSubnet) 216 | pos = pos + 1; 217 | Address.SrcNode = buffer(pos,1):bitfield(1, 7); 218 | address:add(buffer(pos,1),"SrcNode: " .. Address.SrcNode) 219 | pos = pos + 1; 220 | Address.DstSubnet = buffer(pos,1); 221 | address:add(buffer(pos,1),"DstSubnet: " .. Address.DstSubnet) 222 | pos = pos + 1; 223 | Address.NeuronID = buffer(pos,6); 224 | address:add(buffer(pos,1),"NeuronID: " .. Address.NeuronID) 225 | pos = pos + 6; 226 | end 227 | 228 | info = info .. "Src: " .. Address.SrcNode; 229 | 230 | if(NPDU.Length == 0) then 231 | NPDU.Domain = ""; 232 | elseif(NPDU.Length == 1) then 233 | NPDU.Domain = buffer(pos,1); 234 | domain:add(buffer(pos,1),"Domain: " .. NPDU.Domain .. " (8 bits)"); 235 | pos = pos + 1; 236 | elseif(NPDU.Length == 2) then 237 | NPDU.Domain = buffer(pos,3); 238 | domain:add(buffer(pos,3),"Domain: " .. NPDU.Domain .. " (24 bits)"); 239 | pos = pos + 3; 240 | elseif(NPDU.Length == 3) then 241 | NPDU.Domain = buffer(pos,6); 242 | domain:add(buffer(pos,6),"Domain: " .. NPDU.Domain .. " (48 bits)"); 243 | pos = pos + 6; 244 | end 245 | 246 | if(NPDU.PDUFmt == 0) then 247 | local tpdu = npdu:add(mes_proto,buffer(),"PDUFmt: TPDU") 248 | tpdu:add(buffer(pos),"TPDU (not implemented)"); 249 | elseif(NPDU.PDUFmt == 1) then 250 | local spdu = npdu:add(mes_proto,buffer(),"PDUFmt: SPDU") 251 | 252 | SPDU.Auth = buffer(pos,1):bitfield(0, 1); 253 | SPDU.SPDUtype = buffer(pos,1):bitfield(1, 3); 254 | SPDU.TransNo = buffer(pos,1):bitfield(4, 4); 255 | 256 | spdu:add(buffer(pos,1),"Auth: " .. SPDU.Auth); 257 | spdu:add(buffer(pos,1),"SPDUtype: " .. SPDU.SPDUtype); 258 | spdu:add(buffer(pos,1),"TransNo: " .. SPDU.TransNo); 259 | 260 | pos = pos + 1; 261 | 262 | if(SPDU.SPDUtype == 0) then 263 | spdu:add(buffer(pos,1),"SPDUtype: REQUEST"); 264 | local apdu = buffer(pos,2); 265 | info = info .. " | " .. "REQUEST"; 266 | 267 | if(apdu:bitfield(0, 2) == 0) then 268 | local remain = buffer:len() - pos - 1 - 2; 269 | local remainBuffer = buffer(pos+1,remain); 270 | local id = apdu:bitfield(2, 6); 271 | local nmType = "APDU Type: generic application message #"..id; 272 | spdu:add(buffer(pos,1),nmType); 273 | spdu:add(remainBuffer, "APDU Data: " .. remainBuffer:bytes():tohex()); 274 | info = info .. " | " .. nmType; 275 | elseif(apdu:bitfield(0, 2) == 2) then 276 | local remain = buffer:len() - pos - 2 - 2; 277 | local remainBuffer = buffer(pos+1,remain); 278 | local id = apdu:bitfield(2, 14); 279 | local nmType = "APDU Type: network variable message IN #"..id; 280 | spdu:add(buffer(pos,1),nmType); 281 | spdu:add(remainBuffer, "APDU Data: " .. remainBuffer:bytes():tohex()); 282 | info = info .. " | " .. nmType; 283 | elseif(apdu:bitfield(0, 2) == 3) then 284 | local remain = buffer:len() - pos - 2 - 2; 285 | local remainBuffer = buffer(pos+1,remain); 286 | local id = apdu:bitfield(2, 14); 287 | local nmType = "APDU Type: network variable message OUT #"..id; 288 | spdu:add(buffer(pos,1),nmType); 289 | spdu:add(remainBuffer, "APDU Data: " .. remainBuffer:bytes():tohex()); 290 | info = info .. " | " .. nmType; 291 | elseif(apdu:bitfield(0, 3) == 3) then 292 | spdu:add(buffer(pos,1),"APDU Type: NM request/command"); 293 | pos = pos + 1; 294 | 295 | local command = apdu:bitfield(3, 5); 296 | 297 | if(command == 1) then 298 | local nmType = "NM Type: Query ID"; 299 | spdu:add(buffer(pos,1),nmType); 300 | info = info .. " | " .. nmType; 301 | elseif(command == 2) then 302 | local nmType = "NM Type: Respond to query"; 303 | spdu:add(buffer(pos,1),nmType); 304 | info = info .. " | " .. nmType; 305 | elseif(command ==3) then 306 | local nmType = "NM Type: Update domain"; 307 | spdu:add(buffer(pos,1),nmType); 308 | info = info .. " | " .. nmType; 309 | elseif(command == 4) then 310 | local nmType = "NM Type: Leave domain"; 311 | spdu:add(buffer(pos,1),nmType); 312 | info = info .. " | " .. nmType; 313 | elseif(command == 4) then 314 | local nmType = "NM Type: Update key"; 315 | spdu:add(buffer(pos,1),nmType); 316 | info = info .. " | " .. nmType; 317 | elseif(command == 7) then 318 | local nmType = "NM Type: Query address"; 319 | spdu:add(buffer(pos,1),nmType); 320 | info = info .. " | " .. nmType; 321 | elseif(command == 8) then 322 | local nmType = "NM Type: Query network variable config"; 323 | spdu:add(buffer(pos,1),nmType); 324 | info = info .. " | " .. nmType; 325 | elseif(command == 9) then 326 | local nmType = "NM Type: Update group address"; 327 | spdu:add(buffer(pos,1),nmType); 328 | info = info .. " | " .. nmType; 329 | elseif(command == 10) then 330 | local nmType = "NM Type: Query Domain"; 331 | spdu:add(buffer(pos,1),nmType); 332 | info = info .. " | " .. nmType; 333 | elseif(command == 11) then 334 | local nmType = "NM Type: Update network variable config"; 335 | spdu:add(buffer(pos,1),nmType); 336 | info = info .. " | " .. nmType; 337 | elseif(command == 12) then 338 | local nmType = "NM Type: Set node mode"; 339 | spdu:add(buffer(pos,1),nmType); 340 | info = info .. " | " .. nmType; 341 | elseif(command == 13) then 342 | local nmType = "NM Type: Read memory"; 343 | spdu:add(buffer(pos,1),nmType); 344 | info = info .. " | " .. nmType; 345 | elseif(command == 14) then 346 | local nmType = "NM Type: Write memory"; 347 | spdu:add(buffer(pos,1),nmType); 348 | info = info .. " | " .. nmType; 349 | elseif(command == 15) then 350 | local nmType = "NM Type: Recalculate checksum"; 351 | spdu:add(buffer(pos,1),nmType); 352 | info = info .. " | " .. nmType; 353 | elseif(command == 16) then 354 | local nmType = "NM Type: Install"; 355 | spdu:add(buffer(pos,1),nmType); 356 | info = info .. " | " .. nmType; 357 | elseif(command == 17) then 358 | local nmType = "NM Type: Memory refresh"; 359 | spdu:add(buffer(pos,1),nmType); 360 | info = info .. " | " .. nmType; 361 | elseif(command == 18) then 362 | local nmType = "NM Type: Query standard network variable type"; 363 | spdu:add(buffer(pos,1),nmType); 364 | info = info .. " | " .. nmType; 365 | elseif(command == 19) then 366 | local nmType = "NM Type: Network variable fetch"; 367 | spdu:add(buffer(pos,1),nmType); 368 | info = info .. " | " .. nmType; 369 | 370 | local payload = "NM Index: " .. buffer(pos,1); 371 | spdu:add(buffer(pos,1),payload); 372 | info = info .. " | " .. payload; 373 | pos = pos + 1; 374 | 375 | elseif(command == 20) then 376 | local nmType = "NM Type: Router mode"; 377 | info = info .. " | " .. nmType; 378 | else 379 | local nmType = "NM Type: unknown (".. command ..")"; 380 | info = info .. " | " .. nmType; 381 | end 382 | elseif(apdu:bitfield(0, 4) == 5) then 383 | local nmType = "APDU Type: ND message"; 384 | spdu:add(buffer(pos,1),nmType); 385 | info = info .. " | " .. nmType; 386 | elseif(apdu:bitfield(0, 4) == 4) then 387 | local nmType = "APDU Type: foreign frame"; 388 | spdu:add(buffer(pos,1),nmType); 389 | info = info .. " | " .. nmType; 390 | else 391 | local nmType = "APDU Type: unknown"; 392 | spdu:add(buffer(pos,1),nmType); 393 | info = info .. " | " .. nmType; 394 | end 395 | 396 | elseif(SPDU.SPDUtype == 2) then 397 | spdu:add(buffer(pos,1),"SPDUtype: RESPONSE"); 398 | local apdu = buffer(pos,2); 399 | info = info .. " | " .. "RESPONSE"; 400 | 401 | if(apdu:bitfield(0, 2) == 0) then 402 | local remain = buffer:len() - pos - 1 - 2; 403 | local remainBuffer = buffer(pos+1,remain); 404 | local id = apdu:bitfield(2, 6); 405 | local nmType = "APDU Type: generic application message #"..id; 406 | spdu:add(buffer(pos,1),nmType); 407 | spdu:add(remainBuffer, "APDU Data: " .. remainBuffer:bytes():tohex()); 408 | info = info .. " | " .. nmType; 409 | elseif(apdu:bitfield(0, 2) == 2) then 410 | local remain = buffer:len() - pos - 2 - 2; 411 | local remainBuffer = buffer(pos+1,remain); 412 | local id = apdu:bitfield(2, 14); 413 | local nmType = "APDU Type: network variable message IN #"..id; 414 | spdu:add(buffer(pos,1),nmType); 415 | spdu:add(remainBuffer, "APDU Data: " .. remainBuffer:bytes():tohex()); 416 | info = info .. " | " .. nmType; 417 | elseif(apdu:bitfield(0, 2) == 3) then 418 | local remain = buffer:len() - pos - 2 - 2; 419 | local remainBuffer = buffer(pos+1,remain); 420 | local id = apdu:bitfield(2, 14); 421 | local nmType = "APDU Type: network variable message OUT #"..id; 422 | spdu:add(buffer(pos,1),nmType); 423 | spdu:add(remainBuffer, "APDU Data: " .. remainBuffer:bytes():tohex()); 424 | info = info .. " | " .. nmType; 425 | elseif(apdu:bitfield(0, 3) == 1) then 426 | spdu:add(buffer(pos,1),"APDU Type: NM/ND response"); 427 | pos = pos + 1; 428 | local command = apdu:bitfield(3, 5); 429 | 430 | if(command == 1) then 431 | local nmType = "NM Type: Query ID"; 432 | spdu:add(buffer(pos,1),nmType); 433 | info = info .. " | " .. nmType; 434 | elseif(command == 2) then 435 | local nmType = "NM Type: Respond to query"; 436 | spdu:add(buffer(pos,1),nmType); 437 | info = info .. " | " .. nmType; 438 | elseif(command == 3) then 439 | local nmType = "NM Type: Update domain"; 440 | spdu:add(buffer(pos,1),nmType); 441 | info = info .. " | " .. nmType; 442 | elseif(command == 4) then 443 | local nmType = "NM Type: Leave domain"; 444 | spdu:add(buffer(pos,1),nmType); 445 | info = info .. " | " .. nmType; 446 | elseif(command == 4) then 447 | local nmType = "NM Type: Update key"; 448 | spdu:add(buffer(pos,1),nmType); 449 | info = info .. " | " .. nmType; 450 | elseif(command == 7) then 451 | local nmType = "NM Type: Query address"; 452 | spdu:add(buffer(pos,1),nmType); 453 | info = info .. " | " .. nmType; 454 | elseif(command == 8) then 455 | local nmType = "NM Type: Query network variable config"; 456 | spdu:add(buffer(pos,1),nmType); 457 | 458 | local priority = buffer(pos,1):bitfield(0, 1); 459 | local direction = buffer(pos,1):bitfield(1, 1); 460 | local selector = buffer(pos,2):bitfield(2, 14); 461 | spdu:add(buffer(pos,1),"Response: "); 462 | spdu:add(buffer(pos,1)," priority: " .. priority); 463 | spdu:add(buffer(pos,1)," direction: " .. direction); 464 | spdu:add(buffer(pos,2)," selector: " .. selector); 465 | pos = pos + 1; 466 | pos = pos + 1; 467 | local turnaround = buffer(pos,1):bitfield(0, 1); 468 | local service = buffer(pos,1):bitfield(1, 2); 469 | local authenticated = buffer(pos,1):bitfield(3, 1); 470 | local index = buffer(pos,1):bitfield(4, 4); 471 | 472 | 473 | spdu:add(buffer(pos,1)," turnaround: " .. turnaround); 474 | spdu:add(buffer(pos,1)," service: " .. service); 475 | spdu:add(buffer(pos,1)," authenticated: " .. authenticated); 476 | spdu:add(buffer(pos,1)," index: " .. index); 477 | 478 | pos = pos + 1; 479 | info = info .. " | " .. nmType; 480 | elseif(command == 9) then 481 | local nmType = "NM Type: Update group address"; 482 | spdu:add(buffer(pos,1),nmType); 483 | info = info .. " | " .. nmType; 484 | elseif(command == 10) then 485 | local nmType = "NM Type: Query Domain"; 486 | spdu:add(buffer(pos,1),nmType); 487 | info = info .. " | " .. nmType; 488 | elseif(command == 11) then 489 | local nmType = "NM Type: Update network variable config"; 490 | spdu:add(buffer(pos,1),nmType); 491 | info = info .. " | " .. nmType; 492 | elseif(command == 12) then 493 | local nmType = "NM Type: Set node mode"; 494 | spdu:add(buffer(pos,1),nmType); 495 | info = info .. " | " .. nmType; 496 | elseif(command == 13) then 497 | local nmType = "NM Type: Read memory"; 498 | spdu:add(buffer(pos,1),nmType); 499 | info = info .. " | " .. nmType; 500 | elseif(command == 14) then 501 | local nmType = "NM Type: Write memory"; 502 | spdu:add(buffer(pos,1),nmType); 503 | info = info .. " | " .. nmType; 504 | elseif(command == 15) then 505 | local nmType = "NM Type: Recalculate checksum"; 506 | spdu:add(buffer(pos,1),nmType); 507 | info = info .. " | " .. nmType; 508 | elseif(command == 16) then 509 | local nmType = "NM Type: Install"; 510 | spdu:add(buffer(pos,1),nmType); 511 | info = info .. " | " .. nmType; 512 | elseif(command == 17) then 513 | local nmType = "NM Type: Memory refresh"; 514 | spdu:add(buffer(pos,1),nmType); 515 | info = info .. " | " .. nmType; 516 | elseif(command == 18) then 517 | local nmType = "NM Type: Query standard netowrk variable type"; 518 | spdu:add(buffer(pos,1),nmType); 519 | info = info .. " | " .. nmType; 520 | elseif(command == 19) then 521 | local nmType = "NM Type: Network variable fetch"; 522 | spdu:add(buffer(pos,1),nmType); 523 | info = info .. " | " .. nmType; 524 | 525 | spdu:add(buffer(pos,1),"NM Index: " .. buffer(pos,1)); 526 | pos = pos + 1; 527 | 528 | local dataLen = buffer:len() - pos - 2; 529 | local payload = "NM response: " .. buffer(pos,dataLen); 530 | spdu:add(buffer(pos,1),payload); 531 | info = info .. " | " .. payload; 532 | pos = pos + dataLen; 533 | 534 | elseif(command == 20) then 535 | local nmType = "NM Type: Router mode"; 536 | spdu:add(buffer(pos,1),nmType); 537 | info = info .. " | " .. nmType; 538 | else 539 | local nmType = "NM Type: unknown (".. command ..")"; 540 | spdu:add(buffer(pos,1),nmType); 541 | info = info .. " | " .. nmType; 542 | end 543 | 544 | elseif(apdu:bitfield(0, 4) == 5) then 545 | local nmType = "APDU Type: ND message"; 546 | spdu:add(buffer(pos,1),nmType); 547 | info = info .. " | " .. nmType; 548 | elseif(apdu:bitfield(0, 4) == 4) then 549 | local nmType = "APDU Type: foreign frame"; 550 | spdu:add(buffer(pos,1),nmType); 551 | info = info .. " | " .. nmType; 552 | elseif(apdu:bitfield(0, 3) == 0) then 553 | local nmType = "APDU Type: NM/ND response failed"; 554 | spdu:add(buffer(pos,1),nmType); 555 | info = info .. " | " .. nmType; 556 | else 557 | local nmType = "APDU Type: unknown"; 558 | spdu:add(buffer(pos,1),nmType); 559 | info = info .. " | " .. nmType; 560 | end 561 | elseif(SPDU.SPDUtype == 4) then 562 | local nmType = "SPDUtype: REMINDER"; 563 | info = info .. " | " .. "REMINDER"; 564 | spdu:add(buffer(pos,1),nmType); 565 | info = info .. " | " .. nmType; 566 | elseif(SPDU.SPDUtype == 5) then 567 | local nmType = "SPDUtype: REM/MSG"; 568 | info = info .. " | " .. "REM/MSG"; 569 | spdu:add(buffer(pos,1),nmType); 570 | info = info .. " | " .. nmType; 571 | else 572 | local nmType = "SPDUtype: (invalid)"; 573 | info = info .. " | " .. "(invalid)"; 574 | spdu:add(buffer(pos,1),nmType); 575 | info = info .. " | " .. nmType; 576 | end 577 | 578 | pinfo.cols['info'] = info; 579 | 580 | 581 | 582 | elseif(NPDU.PDUFmt == 2) then 583 | local authpdu = npdu:add(mes_proto,buffer(),"PDUFmt: AuthPDU") 584 | authpdu:add(buffer(pos),"AuthPDU (not implemented)"); 585 | elseif(NPDU.PDUFmt == 3) then 586 | local apdu = npdu:add(mes_proto,buffer(),"PDUFmt: APDU") 587 | APDU.Length = buffer:len() - pos - 2; 588 | 589 | apdu:add(buffer(pos,1),"Length: " .. APDU.Length); 590 | 591 | if(APDU.Length > 2) then 592 | APDU.DestinType = buffer(pos,1); 593 | apdu:add(buffer(pos,1),"DestinType: " .. APDU.DestinType); 594 | if(APDU.DestinType:bitfield(0, 2) == 0) then 595 | apdu:add(buffer(pos,1),"Content: Generic application message"); 596 | elseif(APDU.DestinType:bitfield(0, 1) == 1) then 597 | local nv = apdu:add(mes_proto,buffer(),"NV") 598 | 599 | if(APDU.DestinType:bitfield(1, 1) == 0) then 600 | nv:add(buffer(pos,1),"Content: NV message, incoming"); 601 | else 602 | nv:add(buffer(pos,1),"Content: NV message, outgoing"); 603 | end 604 | 605 | NV.Selector = buffer(pos,2):bitfield(2, 14); 606 | nv:add(buffer(pos,2),"Selector: "..NV.Selector); 607 | pos = pos + 2; 608 | 609 | local remain = buffer:len()-pos-2; 610 | if(remain > 0) then 611 | NV.Value = buffer(pos, remain); 612 | nv:add(buffer(pos, remain),"Value: "..NV.Value); 613 | end 614 | 615 | 616 | if(NV.Selector == 0x100) then 617 | Time = {}; 618 | Time.Day = NV.Value:bitfield(24,8); 619 | Time.Hours = NV.Value:bitfield(32,8); 620 | Time.Minutes = NV.Value:bitfield(40,8); 621 | info = info .. " | Date/Time: ".. Time.Hours .. ":" .. Time.Minutes .. " Day #" .. Time.Day; 622 | elseif(NV.Selector == 0x0) then 623 | temp = NV.Value:int(); 624 | info = info .. " | Aussen: ".. (temp/100.0) .. " C"; 625 | elseif(NV.Selector == 0x72) then 626 | temp = NV.Value:int(); 627 | info = info .. " | Warmwasser Soll: ".. (temp/100.0) .. " C"; 628 | elseif(NV.Selector == 0x10) then 629 | temp = NV.Value:int(); 630 | info = info .. " | Vorlauf Soll HK: ".. (temp/100.0) .. " C"; 631 | elseif(NV.Selector == 0x12) then 632 | temp = NV.Value:int(); 633 | info = info .. " | Vorlauf Soll WW: ".. (temp/100.0) .. " C"; 634 | elseif(NV.Selector == 0x11) then 635 | info = info .. " | 0x11: ".. NV.Value .. ""; 636 | elseif(NV.Selector == 0x13) then 637 | info = info .. " | 0x13: ".. NV.Value .. ""; 638 | elseif(NV.Selector == 0x8A) then 639 | info = info .. " | 0x8A: ".. NV.Value .. ""; 640 | elseif(NV.Selector == 0x110) then 641 | temp = NV.Value:int(); 642 | info = info .. " | Kessel: ".. (temp/100.0) .. " C"; 643 | elseif(NV.Selector == 0x101) then 644 | temp = NV.Value:uint(); 645 | info = info .. " | Fehler: ".. temp .. " | !!!!!!!!!!!!!!!!!!!!!!!!"; 646 | else 647 | info = info .. " | #### UNKNOWN ###"; 648 | end 649 | 650 | nv:add(buffer(pos, remain),info); 651 | pos = pos + remain; 652 | 653 | elseif(APDU.DestinType:bitfield(0, 3) == 3) then 654 | pos = pos + 1; 655 | local remain = buffer:len()-pos-2; 656 | apdu:add(buffer(pos,remain),"Content: network management"); 657 | if(remain > 0) then 658 | NV.Value = buffer(pos, remain); 659 | nv:add(buffer(pos, remain),"Value: "..NV.Value); 660 | end 661 | pos = pos + remain; 662 | elseif(APDU.DestinType:bitfield(0, 3) == 5) then 663 | pos = pos + 1; 664 | apdu:add(buffer(pos,remain),"Content: diagnostic message"); 665 | if(remain > 0) then 666 | NV.Value = buffer(pos, remain); 667 | nv:add(buffer(pos, remain),"Value: "..NV.Value); 668 | end 669 | pos = pos + remain; 670 | elseif(APDU.DestinType:bitfield(0, 3) == 4) then 671 | pos = pos + 1; 672 | apdu:add(buffer(pos,remain),"Content: foreign frame"); 673 | if(remain > 0) then 674 | NV.Value = buffer(pos, remain); 675 | nv:add(buffer(pos, remain),"Value: "..NV.Value); 676 | end 677 | pos = pos + remain; 678 | end 679 | end 680 | 681 | end 682 | PPDU.CRC = buffer(pos,2); 683 | ppdu:add(buffer(pos,2),"CRC: " .. PPDU.CRC) 684 | pinfo.cols['info'] = info; 685 | end 686 | end 687 | 688 | -- load the udp.port table 689 | udp_table = DissectorTable.get("udp.port") 690 | 691 | -- register our protocol to handle udp port 3333 692 | udp_table:add(3333,mes_proto) 693 | 694 | --------------------------------------------------------------------------------