├── .gitignore ├── .vscode └── settings.json ├── LICENSE ├── README.md ├── gvg_native_dissector.lua ├── gvgnative.pcapng ├── harris_lrc_dissector.lua ├── leitch_dissector.lua ├── nevion_mrp_dissector.lua ├── np0017_dissector.lua ├── probel_swp02_dissector.lua ├── probel_swp08_dissector.lua ├── quartz_dissector.lua ├── screenshot.png ├── skeleton.lua ├── utah_rcp3a_dissector.lua └── wireshark.lua /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Lua sources 2 | luac.out 3 | 4 | # luarocks build files 5 | *.src.rock 6 | *.zip 7 | *.tar.gz 8 | 9 | # Object files 10 | *.o 11 | *.os 12 | *.ko 13 | *.obj 14 | *.elf 15 | 16 | # Precompiled Headers 17 | *.gch 18 | *.pch 19 | 20 | # Libraries 21 | *.lib 22 | *.a 23 | *.la 24 | *.lo 25 | *.def 26 | *.exp 27 | 28 | # Shared objects (inc. Windows DLLs) 29 | *.dll 30 | *.so 31 | *.so.* 32 | *.dylib 33 | 34 | # Executables 35 | *.exe 36 | *.out 37 | *.app 38 | *.i*86 39 | *.x86_64 40 | *.hex 41 | 42 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Lua.runtime.version": "Lua 5.2", 3 | "Lua.diagnostics.globals": [ 4 | "H", 5 | "bit" 6 | ] 7 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Wireshark Lua dissectors for Video Routers 2 | 3 | | Protocol | Filename | Default port | Wireshark proto | 4 | | ------------------- | ---------------------------- | ------------ | --------------- | 5 | | Grass Valley Native | `gvg_native_dissector.lua` | 12345 | GVGNative | 6 | | Harris LRC | `harris_lrc_dissector.lua` | 52116 | LRC | 7 | | Leitch Pass-Through | `leitch_dissector.lua` | 23 | Leitch | 8 | | Nevion MRP | `nevion_mrp_dissector.lua` | 4381 | Nevion | 9 | | NVision NP0017 | `np0017_dissector.lua` | 9193 | NP0017 | 10 | | Pro-Bel SW-P-08 | `probel_swp08_dissector.lua` | 2007, 2008 | SWP08 | 11 | | Pro-Bel SW-P-02 | `probel_swp02_dissector.lua` | 2006 | SWP02 | 12 | | Quartz RCP | `quartz_dissector.lua` | 4000 | Quartz | 13 | | Utah RCP3-A | `utah_rcp3a_dissector.lua` | 5001 | RCP3A | 14 | 15 | ## Using the Dissectors 16 | 17 | Either copy `xxx_dissector.lua` to your Wireshark plugins folder, or start wireshark (e.g. from Powershell) like this: 18 | `& "c:\program files\Wireshark\wireshark.exe" -X lua_script:gvg_native_dissector.lua` 19 | 20 | `& "c:\program files\Wireshark\wireshark.exe" -X lua_script:harris_lrc_dissector.lua` 21 | 22 | `& "c:\program files\Wireshark\wireshark.exe" -X lua_script:leitch_dissector.lua` 23 | 24 | `& "c:\program files\Wireshark\wireshark.exe" -X lua_script:nevion_mrp_dissector.lua` 25 | 26 | `& "c:\program files\Wireshark\wireshark.exe" -X lua_script:np0017_dissector.lua` 27 | 28 | `& "c:\program files\Wireshark\wireshark.exe" -X lua_script:probel_swp08_dissector.lua` 29 | 30 | `& "c:\program files\Wireshark\wireshark.exe" -X lua_script:probel_swp02_dissector.lua` 31 | 32 | `& "c:\program files\Wireshark\wireshark.exe" -X lua_script:quartz_dissector.lua` 33 | 34 | `& "c:\program files\Wireshark\wireshark.exe" -X lua_script:utah_rcp3a_dissector.lua` 35 | 36 | If your router is using a different TCP port you can use wireshark's "Decode As.." function to specify the port and protocol. 37 | 38 | Packet contents for the all common routing commands are decoded. 39 | 40 | ![Wireshark Screenshot](screenshot.png) 41 | -------------------------------------------------------------------------------- /gvg_native_dissector.lua: -------------------------------------------------------------------------------- 1 | -- Grass Valley Native Protocol dissector for Wireshark. 2 | -- 3 | -- Copyright (C) 2021-2022 Rascular Technology Ltd. 4 | -------------------------------------------------------------- 5 | local gvg = Proto("GVGNative", "Grass Valley Native protocol"); 6 | 7 | local f_body = ProtoField.string("GVGNative.body", "Body"); 8 | local f_stx = ProtoField.uint8("GVGNative.STX", "STX"); 9 | local f_native = ProtoField.string("GVGNative.Native", "Native"); 10 | local f_sequence = ProtoField.string("GVGNative.Sequence", "Sequence"); 11 | local f_command = ProtoField.string("GVGNative.Command", "Command"); 12 | local f_params = ProtoField.string("GVGNative.Params", "Params"); 13 | local f_param = ProtoField.string("GVGNative.Param", "Param"); 14 | 15 | local f_checksum = ProtoField.string("GVGNative.Checksum", "Checksum"); 16 | local f_eot = ProtoField.uint8("GVGNative.EOT", "EOT"); 17 | 18 | gvg.fields = { f_body, f_stx, f_native, f_sequence, f_command, f_params, f_param, f_checksum, f_eot }; 19 | 20 | 21 | local ef_bad_checksum = ProtoExpert.new("GVGNative.checksum.expert", "Bad checksum", 22 | expert.group.CHECKSUM, 23 | expert.severity.ERROR); 24 | 25 | local ef_bad_stx = ProtoExpert.new("GVGNative.stx.expert", "Bad STX", 26 | expert.group.MALFORMED, 27 | expert.severity.ERROR); 28 | 29 | local ef_bad_protocol = ProtoExpert.new("GVGNative.protocol.expert", "Bad Protocol", 30 | expert.group.MALFORMED, 31 | expert.severity.ERROR); 32 | 33 | local ef_error = ProtoExpert.new("GVGNative.error.expert", "Error Code", 34 | expert.group.RESPONSE_CODE, 35 | expert.severity.ERROR); 36 | 37 | gvg.experts = { ef_bad_checksum, ef_bad_stx, ef_bad_protocol, ef_error } 38 | 39 | local commands = { AS = "Machine Assign", 40 | BK = "Background Activities", 41 | CH = "Request Chop", 42 | CT = "Clear Tielines", 43 | DA = "Machine De-assign", 44 | NY = "Notification", 45 | PI = "Protect by Index", 46 | PR = "request Protect", 47 | QA = "Query Machine Assignment", 48 | QB = "Query Alarm Definitions", 49 | QC = "Query COmbined Destination Status", 50 | QD = "Query Destination Status", 51 | Qd = "Query Destination status", 52 | QE = "Query Error Definition", 53 | QH = "Query Alarm Status", 54 | QI = "Query Destination by Index", 55 | Qi = "Query Destination by index", 56 | QJ = "Query Destination by index", 57 | Qj = "Query Destination by index", 58 | QL = "Query Destination with Tieline Info", 59 | Ql = "Query Destination with Tieline Info", 60 | QN = "Query Names", 61 | QT = "Query Date and Time", 62 | QV = "Query Salvo Status", 63 | SB = "Subscribe", 64 | ST = "Set Date and Time", 65 | TA = "Take", 66 | TD = "Take Destination", 67 | TI = "Take Index with Level Index", 68 | TJ = "Take Index with Level Bitmap", 69 | TM = "Take Monitor Destination", 70 | TS = "Take Salvo", 71 | UI = "Unprotect by Index", 72 | UB = "Unsubscribe", 73 | UP = "Unprotect" 74 | } 75 | 76 | bk_commands = { 77 | I = "Refresh Interval", 78 | N = "Get Device Name", 79 | R = "Get Software Revision", 80 | T = "Get software Title", 81 | t = "Get Protcol", 82 | F = "Ger reset occurences", 83 | f = "Mask clear change flags", 84 | d = "Get Port Name", 85 | D = "Clear QD Flags", 86 | A = "Clear QA Flags", 87 | P = "Get port configuration parameters", 88 | E = "Get/Set Level 4 Echo", 89 | ["2"] = "Null Command" 90 | } 91 | 92 | error_codes = { 93 | [0] = "OK", 94 | [1] = "Directed Response Error", 95 | [2] = "Unknown Error Code", 96 | [3] = "System Error", 97 | [4] = "System Table Error", 98 | [5] = "Not Implemented", 99 | [6] = "Semaphore Create Error", 100 | [7] = "Semaphore Give Error", 101 | [8] = "Semaphore Take Error", 102 | [66] = "Unknown Dest Name", 103 | [67] = "Unknown Source Name", 104 | [68] = "Unknown Salvo name", 105 | [69] = "Bad Level Bit Map", 106 | [70] = "Invalid Control Level", 107 | [71] = "Panel Locked", 108 | [72] = "Chop Lock", 109 | [73] = "Salvo Lock", 110 | [74] = "No Monitor Control", 111 | [75] = "Send To MCPU Error", 112 | [76] = "Redirect CoProc Msgs Err", 113 | [77] = "Assignments Not Enabled", 114 | [78] = "New Net Detected, But Not Active", 115 | [79] = "Previously Detected Net Now Not Active", 116 | [128] = "Unknown Command", 117 | [129] = "CL-CMD Disabled", 118 | [130] = "Bad CL-CMD Syntax", 119 | [131] = "Bad Nbr of Sources", 120 | [132] = "BadError Code", 121 | [133] = "Parse EOT missing", 122 | [134] = "Parse HT missing", 123 | [135] = "Parse Bad Protect Flag", 124 | [136] = "Parse Bad Dst Name", 125 | [137] = "Parse Bad Src Name", 126 | [138] = "Too Many Sources", 127 | [139] = "Bad Parameter", 128 | [140] = "Bad Mask", 129 | [141] = "Unknown Tag For RCL2", 130 | [142] = "Chksum Lvl4 Err", 131 | [143] = "Lvl4 Embedded SOH Err", 132 | [144] = "Lvl4 Embedded EOT Err", 133 | [145] = "Bad Dst Index", 134 | [146] = "Unknown Dst Index", 135 | [147] = "Bad Src Index", 136 | [148] = "Unknown Src Index", 137 | [149] = "Bad Level Index", 138 | [150] = "Invalid Ctl Lvl Index", 139 | [151] = "Level Not In Destination", 140 | [152] = "Rooms Not Enabled", 141 | [153] = "Room Count Is Zero", 142 | [154] = "No Dest Status Exists", 143 | [155] = "Err Trying To Set Time in MCPU", 144 | [156] = "Date format error", 145 | [157] = "Time format error", 146 | [158] = "Parse Bad Salvo Name", 147 | [188] = "Unknown Alarm Type", 148 | [189] = "Invalid Alarm Id", 149 | [190] = "Invalid Alarm Range", 150 | [191] = "Invalid Dest Range", 151 | [192] = "Invalid Command format", 152 | [193] = "Salvo Excluded", 153 | [194] = "Invalid Number Of Entries", 154 | [195] = "Invalid Attribute value", 155 | [196] = "Bad Number of Entries", 156 | [197] = "Not Supported", 157 | [198] = "SNMP Disabled", 158 | [199] = "Not Supported in WIN32" 159 | } 160 | 161 | 162 | function rangeByte(range, i) 163 | local r = range:range(i, 1) 164 | return r, r:uint() 165 | end 166 | 167 | function rangeString(range, i, len) 168 | local r = range:range(i, len) 169 | return r, r:string() 170 | end 171 | 172 | function rangeChar(range, i) 173 | local r = range:range(i, 1) 174 | return r, r:string() 175 | end 176 | 177 | function processPacket(mess, root, range) 178 | local tree = root:add(range, "GVG Native") 179 | 180 | local c = mess[1] 181 | if c ~= 1 then 182 | tree:add_proto_expert_info(ef_bad_stx) 183 | end 184 | 185 | tree:add(f_stx, rangeByte(range, 0)) 186 | local f, s = rangeChar(range, 1) 187 | tree:add(f_native, f, s) 188 | if s ~= "N" then 189 | tree:add_proto_expert_info(ef_bad_protocol) 190 | end 191 | tree:add(f_sequence, rangeChar(range, 2)) 192 | 193 | f, s = rangeString(range, 3, 2) 194 | local item = tree:add(f_command, f, s) 195 | 196 | local params = {} 197 | 198 | local r, paramstr = rangeString(range, 6, #mess - 8) 199 | for token in string.gmatch(paramstr, "[^\t]+") do 200 | params[#params + 1] = token 201 | end 202 | 203 | if s == "BK" then 204 | if bk_commands[params[1]] then 205 | item:append_text(": " .. bk_commands[params[1]]) 206 | else 207 | item:append_text(": ", params[1]) 208 | end 209 | elseif s == "ER" then 210 | local code = tonumber(params[1], 16) 211 | item:append_text(": " .. error_codes[code]) 212 | if code ~= 0 then 213 | item:add_proto_expert_info(ef_error) 214 | end 215 | elseif commands[s] then 216 | item:append_text(": " .. commands[s]) 217 | end 218 | 219 | item = tree:add(f_params, r, paramstr) 220 | for i, token in ipairs(params) do 221 | item:add(f_param, token) 222 | end 223 | 224 | -- validate checksum 225 | local sum = 0 226 | for i = 2, #mess - 2 do sum = sum + mess[i] end 227 | 228 | f, s = rangeString(range, #mess - 2, 2) 229 | 230 | tree:add(f_checksum, f, s) 231 | 232 | if bit32.band(-sum, 0xff) ~= tonumber(s, 16) then 233 | tree:add_proto_expert_info(ef_bad_checksum) 234 | end 235 | 236 | tree:add(f_eot, rangeByte(range, #mess)) 237 | 238 | end 239 | 240 | function gvg.dissector(tvb, pinfo, root_tree) 241 | 242 | pinfo.cols.protocol = "GVG Native"; 243 | local p = 0 244 | while p < tvb:len() do 245 | local st, l = lookForPacket(tvb, root_tree, p) 246 | if l then 247 | p = st + l; 248 | else 249 | pinfo.desegment_offset = st 250 | pinfo.desegment_len = DESEGMENT_ONE_MORE_SEGMENT 251 | return 252 | end 253 | end 254 | end 255 | 256 | function lookForPacket(tvb, root_tree, startpos) 257 | local bytes = tvb:bytes(); 258 | local len = bytes:len() 259 | local mess = {} 260 | 261 | for p = startpos, len - 1 do 262 | local c = bytes:get_index(p) 263 | if c == 4 then -- EOT 264 | local range = tvb:range(startpos, #mess + 1) 265 | processPacket(mess, root_tree, range) 266 | return startpos, #mess + 1 267 | else 268 | mess[#mess + 1] = c 269 | end 270 | end 271 | return startpos -- end not found - keep looking 272 | end 273 | 274 | local tcp_encap_table = DissectorTable.get("tcp.port") 275 | tcp_encap_table:add(12345, gvg) 276 | -------------------------------------------------------------------------------- /gvgnative.pcapng: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roddypratt/router_dissectors/77ca6ccdda96b31e51c646cdbb55a72ca6417f26/gvgnative.pcapng -------------------------------------------------------------------------------- /harris_lrc_dissector.lua: -------------------------------------------------------------------------------- 1 | -- Harris LRC Protocol dissector for Wireshark. 2 | -- 3 | -- Copyright (C) 2021 Rascular Technology Ltd. 4 | -------------------------------------------------------------- 5 | local codes = {[0] = "COMMAND_ENABLE"} 6 | 7 | local lrc = Proto("lrc", "Harris LRC protocol"); 8 | 9 | local ops = { 10 | [string.byte('?')] = "Query", 11 | [string.byte(':')] = "Command", 12 | [string.byte('!')] = "Notification", 13 | [string.byte('%')] = "Response" 14 | } 15 | 16 | local f_operator = ProtoField.uint8("lrc.operator", "Operator", base.HEX, ops); 17 | local f_type = ProtoField.string("lrc.type", "Type"); 18 | local f_arg = ProtoField.string("lrc.arg", "Arg"); 19 | 20 | lrc.fields = {f_type, f_operator, f_arg}; 21 | 22 | local ef_malformed = ProtoExpert.new("lrc.malformed.expert", "Malformed packet", 23 | expert.group.MALFORMED, 24 | expert.severity.ERROR); 25 | 26 | lrc.experts = {ef_malformed} 27 | 28 | function rangeChar(range, i) 29 | local r = range:range(i, 1) 30 | return r, r:uint() 31 | end 32 | 33 | function rangeString(range, i, len) 34 | local r = range:range(i, len) 35 | return r, r:string() 36 | end 37 | 38 | function processPacket(mess, root, range) 39 | local tree = root:add(range, "Harris LRC") 40 | 41 | local a 42 | for p = 2, #mess do 43 | if ops[mess[p]] then 44 | print("Found op", string.char(mess[p])) 45 | 46 | tree:add(f_type, rangeString(range, 1, p - 1)) 47 | tree:add(f_operator, rangeChar(range, p)) 48 | a = p + 1 49 | break 50 | end 51 | end 52 | 53 | for p = a, #mess do 54 | if mess[p] == string.byte(';') then 55 | tree:add(f_arg, rangeString(range, a, p - a)) 56 | a = p + 1 57 | end 58 | end 59 | 60 | if #mess > a then tree:add(f_arg, rangeString(range, a, 1 + #mess - a)) end 61 | 62 | end 63 | 64 | function lrc.dissector(tvb, pinfo, root_tree) 65 | 66 | pinfo.cols.protocol = "Harris LRC"; 67 | local p = 0 68 | while p < tvb:len() do 69 | local st, l = lookForPacket(tvb, root_tree, p) 70 | if l then 71 | p = st + l; 72 | else 73 | pinfo.desegment_offset = st 74 | pinfo.desegment_len = DESEGMENT_ONE_MORE_SEGMENT 75 | return 76 | end 77 | end 78 | end 79 | 80 | function lookForPacket(tvb, root_tree, startpos) 81 | local bytes = tvb:bytes(); 82 | local len = bytes:len() 83 | local start = startpos 84 | local startFound = false 85 | local mess = {} 86 | for p = startpos, len - 1 do 87 | local c = bytes:get_index(p) 88 | if (c == string.byte('~')) then 89 | if startFound or (#mess > 0) then 90 | root_tree:add_tvb_expert_info(ef_malformed, 91 | tvb(start, p - start), 92 | "Junk before start") 93 | end 94 | start = p 95 | startFound = true 96 | mess = {} 97 | elseif c == string.byte('\\') then 98 | if startFound then 99 | local range = tvb:range(start, 1 + p - start) 100 | processPacket(mess, root_tree, range) 101 | return start, 1 + p - start 102 | else 103 | root_tree:add_tvb_expert_info(ef_malformed, 104 | tvb(start, 1 + p - start), 105 | "End without start") 106 | return start, 1 + p - start 107 | end 108 | else 109 | mess[#mess + 1] = c 110 | end 111 | end 112 | 113 | if start >= 0 then 114 | return start -- packet is incomplete 115 | else 116 | return startpos, len -- no start found, discard 117 | end 118 | end 119 | 120 | local tcp_encap_table = DissectorTable.get("tcp.port") 121 | tcp_encap_table:add(52116, lrc) 122 | 123 | -------------------------------------------------------------------------------- /leitch_dissector.lua: -------------------------------------------------------------------------------- 1 | -- Leitch Pass-Through Protocol dissector for Wireshark. 2 | -- 3 | -- Copyright (C) 2024 Rascular Technology Ltd. 4 | -------------------------------------------------------------- 5 | local leitch = Proto("Leitch", "Leitch Pass-Through protocol"); 6 | 7 | local f_command = ProtoField.string("leitch.command", "Command"); 8 | local f_response = ProtoField.string("leitch.response", "Response"); 9 | local f_body = ProtoField.string("leitch.body", "Body"); 10 | 11 | local f_name = ProtoField.string("leitch.name", "Name"); 12 | local f_levels = ProtoField.string("leitch.levels", "Levels"); 13 | local f_source = ProtoField.uint16("leitch.source", "Source"); 14 | local f_dest = ProtoField.uint16("leitch.dest", "Dest"); 15 | leitch.fields = { f_command, f_response, f_body, f_source, f_dest, f_name, f_levels }; 16 | 17 | function rangeHex(range, i, len) 18 | local r = range:range(i, len) 19 | return r, tonumber(r:string(), 16) 20 | end 21 | 22 | function rangeString(range, i, len) 23 | local r = range:range(i, len) 24 | return r, r:string() 25 | end 26 | 27 | local function starts_with(str, start) return str:sub(1, #start) == start end 28 | 29 | function checkCommand(tree, mess, range, cmd, cmdName) 30 | if starts_with(mess, cmd) then 31 | tree:add(f_command, range:range(0, #cmd), cmdName) 32 | return true 33 | end 34 | return false 35 | end 36 | 37 | function checkResponse(tree, mess, range, cmd, cmdName) 38 | if starts_with(mess, cmd) then 39 | tree:add(f_response, range:range(0, #cmd), cmdName) 40 | return true 41 | end 42 | return false 43 | end 44 | 45 | function processPacket(mess, root, range) 46 | local tree = root:add(range, "Leitch Pass-Through") 47 | 48 | 49 | if checkCommand(tree, mess, range, "@ !", "Disable Reporting") then 50 | elseif checkCommand(tree, mess, range, "@ ?", "Enable Reporting") then 51 | elseif checkCommand(tree, mess, range, "@ Z:", "Reset Levels") then 52 | elseif checkCommand(tree, mess, range, "@ X:", "Crosspoint Take") then 53 | local l, d, s = string.match(mess, "^@ X:(%x+)/(%x+),(%x+)") 54 | tree:add(f_levels, rangeString(range, 4, #l)) 55 | tree:add(f_dest, rangeHex(range, 5 + #l, #d)) 56 | tree:add(f_source, rangeHex(range, 6 + #l + #d, #s)) 57 | elseif checkCommand(tree, mess, range, "@ S?", "Crosspoint Status Request") then 58 | elseif checkCommand(tree, mess, range, "@ Z:", "Reset Levels") then 59 | elseif checkCommand(tree, mess, range, "@ P:", "Preset Crosspoint") then 60 | elseif checkCommand(tree, mess, range, "@ X?", "Crosspoint Status Request") then 61 | elseif checkCommand(tree, mess, range, "@ p?", "Preset CrosspointStatus Request") then 62 | elseif checkCommand(tree, mess, range, "@ V?", "Preset CrosspointStatus Request") then 63 | elseif checkCommand(tree, mess, range, "@ Q?/", "Alarm Status Request") then 64 | elseif checkCommand(tree, mess, range, "@ F?", "Frame Size Request") then 65 | elseif checkCommand(tree, mess, range, "@ I?", "Information Request") then 66 | elseif checkCommand(tree, mess, range, "@ W:", "Lock/Unlock Request") then 67 | elseif checkCommand(tree, mess, range, "@ B:C", "Clear Presets") then 68 | elseif checkCommand(tree, mess, range, "@ B:E", "Execute Presets") then 69 | elseif checkCommand(tree, mess, range, "@ B:R", "Reset Presets") then 70 | elseif checkCommand(tree, mess, range, "@ K?", "Router Names Request") then 71 | local sd, s = string.match(mess, "^@ K%?(%a)%a,(%x+)") 72 | if sd == 'S' then 73 | tree:add(f_source, rangeHex(range, 7, #s)) 74 | elseif sd == 'D' then 75 | tree:add(f_dest, rangeHex(range, 7, #s)) 76 | end 77 | elseif checkResponse(tree, mess, range, ">", "Prompt") then 78 | elseif checkResponse(tree, mess, range, "S:", "Crosspoint Status") then 79 | local l, d, s = string.match(mess, "^S:(%x)(%x+),(%x+)") 80 | tree:add(f_levels, rangeHex(range, 2, #l)) 81 | tree:add(f_dest, rangeHex(range, 2 + #l, #d)) 82 | tree:add(f_source, rangeHex(range, 3 + #l + #d, #s)) 83 | elseif checkResponse(tree, mess, range, "V:", "Preset Crosspoint Status") then 84 | elseif checkResponse(tree, mess, range, "F:", "Frame Size") then 85 | elseif checkResponse(tree, mess, range, "Q:", "Alarm Status") then 86 | elseif checkResponse(tree, mess, range, "W!", "Lock/Unlock Status") then 87 | elseif checkResponse(tree, mess, range, "I!", "Information") then 88 | elseif checkResponse(tree, mess, range, "K:", "Router Name") then 89 | local sd, s = string.match(mess, "^K:(%a)%a(%x+)") 90 | if sd == 'S' then 91 | tree:add(f_source, rangeHex(range, 4, #s)) 92 | elseif sd == 'D' then 93 | tree:add(f_dest, rangeHex(range, 4, #s)) 94 | end 95 | local n = string.sub(mess, 6 + #s, #mess) 96 | tree:add(f_name, range:range(5 + #s, #n), Struct.fromhex(n)) 97 | else 98 | tree:add(f_response, range, "Unknown") 99 | end 100 | 101 | tree:add(f_body, rangeString(range, 0, #mess)) 102 | end 103 | 104 | function leitch.dissector(tvb, pinfo, root_tree) 105 | pinfo.cols.protocol = "Leitch"; 106 | local p = 0 107 | while p < tvb:len() do 108 | local st, l = lookForPacket(tvb, root_tree, p) 109 | if l then 110 | p = st + l; 111 | else 112 | pinfo.desegment_offset = st 113 | pinfo.desegment_len = DESEGMENT_ONE_MORE_SEGMENT 114 | return 115 | end 116 | end 117 | end 118 | 119 | function lookForPacket(tvb, root_tree, startpos) 120 | local bytes = tvb:bytes(); 121 | local len = bytes:len() 122 | local mess = "" 123 | 124 | for p = startpos, len - 1 do 125 | local c = string.char(bytes:get_index(p)) 126 | if (c ~= '\r') and (c ~= '\n') then -- ignore CR and LF 127 | mess = mess .. c 128 | end 129 | if (c == '\r') or (c == '>') then 130 | local range = tvb:range(startpos, (p - startpos) + 1) 131 | processPacket(mess, root_tree, range) 132 | return startpos, (p - startpos) + 1 133 | end 134 | end 135 | return startpos -- end not found - keep looking 136 | end 137 | 138 | local tcp_encap_table = DissectorTable.get("tcp.port") 139 | tcp_encap_table:add(23, leitch) 140 | -------------------------------------------------------------------------------- /nevion_mrp_dissector.lua: -------------------------------------------------------------------------------- 1 | -- Nevion MRP Protocol dissector for Wireshark. 2 | -- 3 | -- Copyright (C) 2021 Rascular Technology Ltd. 4 | -------------------------------------------------------------- 5 | local nevion = Proto("nevion", "Nevion MRP protocol"); 6 | 7 | local f_command = ProtoField.string("nevion.command", "Command"); 8 | local f_response = ProtoField.string("nevion.response", "Response"); 9 | local f_status = ProtoField.string("nevion.status", "Status"); 10 | local f_body = ProtoField.string("nevion.body", "Body"); 11 | 12 | nevion.fields = {f_command, f_status, f_response, f_body}; 13 | 14 | -- local ef_checkum = ProtoExpert.new("nevion.checksum.expert", 15 | -- "Bad checksum", expert.group.MALFORMED, 16 | -- expert.severity.ERROR); 17 | 18 | -- nevion.experts = {ef_checkum} 19 | 20 | function rangeChar(range, i) 21 | local r = range:range(i, 1) 22 | return r, r:uint() 23 | end 24 | 25 | function rangeString(range, i, len) 26 | local r = range:range(i, len) 27 | return r, r:string() 28 | end 29 | 30 | function processPacket(mess, root, range) 31 | local tree = root:add(range, "Nevion MRP") 32 | 33 | local c = mess:sub(1, 1) 34 | local eol = string.find(mess, "\n") 35 | if c == "?" then 36 | tree:add(f_response, rangeString(range, 0, eol - 1)) 37 | elseif c == "%" then 38 | tree:add(f_status, rangeString(range, 0, eol - 1)) 39 | else 40 | tree:add(f_command, rangeString(range, 0, eol - 1)) 41 | end 42 | if eol and eol < #mess then 43 | tree:add(f_body, rangeString(range, eol, #mess - eol)) 44 | end 45 | end 46 | 47 | function nevion.dissector(tvb, pinfo, root_tree) 48 | 49 | pinfo.cols.protocol = "Nevion MRP"; 50 | local p = 0 51 | while p < tvb:len() do 52 | local st, l = lookForPacket(tvb, root_tree, p) 53 | if l then 54 | p = st + l; 55 | else 56 | pinfo.desegment_offset = st 57 | pinfo.desegment_len = DESEGMENT_ONE_MORE_SEGMENT 58 | return 59 | end 60 | end 61 | end 62 | 63 | function lookForPacket(tvb, root_tree, startpos) 64 | local bytes = tvb:bytes(); 65 | local len = bytes:len() 66 | local mess = "" 67 | 68 | for p = startpos, len - 2 do 69 | local c = string.char(bytes:get_index(p)) 70 | if (c == '\n') and (string.char(bytes:get_index(p + 1)) == '\n') then 71 | local range = tvb:range(startpos, #mess + 2) 72 | processPacket(mess .. "\n", root_tree, range) 73 | return startpos, #mess + 2 74 | else 75 | mess = mess .. c 76 | end 77 | end 78 | return startpos -- end not found - keep looking 79 | end 80 | 81 | local tcp_encap_table = DissectorTable.get("tcp.port") 82 | tcp_encap_table:add(4381, nevion) 83 | 84 | -------------------------------------------------------------------------------- /np0017_dissector.lua: -------------------------------------------------------------------------------- 1 | -- Nevion MRP Protocol dissector for Wireshark. 2 | -- 3 | -- Copyright (C) 2023 Rascular Technology Ltd. 4 | -------------------------------------------------------------- 5 | local np0017 = Proto("np0017", "NVision NP-0017 protocol"); 6 | 7 | local TAKE = 0x3000 8 | local TAKEPORT = 0x3001 9 | local LOCK = 0x3002 10 | local LOCKPORT = 0x3003 11 | local REGISTER = 0x3004 12 | local REGISTERPORT = 0x3005 13 | local GETSTATUS = 0x3006 14 | local GETSTATUSPORT = 0x3007 15 | local LOCKSTATUS = 0x3008 16 | local LOCKSTATUSPORT = 0x3009 17 | local FIRESALVO = 0x300A 18 | local STATUSCHANGED = 0x300B 19 | local STATUSCHANGEDPORT = 0x300C 20 | local TAKEFREESOURCE = 0x300D 21 | local GETPREVIOUSSOURCE = 0x3011 22 | local GETMNEMONICS = 0x3012 23 | local FINDMNEMONICS = 0x3013 24 | local GETDIMENSIONS = 0x3014 25 | local GETMNEMONICSPORT = 0x3015 26 | local ALLLEVELESTAKE = 0x3016 27 | local GETEXTENDEDDIMENSIONS = 0x301F 28 | local GETCROSSPOINTSTATUS = 0x3020 29 | local GETEXTMNEMONICS = 0x3022 30 | local FINDEXTMNEMONICS = 0x3033 31 | local GETEXTMNEMONICSPORT = 0x3025 32 | local ERRORRESPONSE = 0x80000000 33 | 34 | local commands = { 35 | [TAKE] = "TAKE DEVICE", 36 | [TAKEPORT] = "TAKE PORT", 37 | [LOCK] = "LOCK/PROTECT DEVICE", 38 | [LOCKPORT] = "LOCK/PROTECT PORT", 39 | [REGISTER] = "REGISTER FOR CHANGES", 40 | [REGISTERPORT] = "REGISTER FOR PORT CHANGES", 41 | [GETSTATUS] = "GET DEVICE SFTATUS", 42 | [GETSTATUSPORT] = "GET PORT STATUS", 43 | [LOCKSTATUS] = "GET DEVICE LOCK STATUS", 44 | [LOCKSTATUSPORT] = "GET PORT LOCK STATUS", 45 | [FIRESALVO] = "FIRE SALVO", 46 | [STATUSCHANGED] = "DEVICE STATUS CHANGED", 47 | [STATUSCHANGEDPORT] = "PORT STATUS CHANGED", 48 | [TAKEFREESOURCE] = "TAKE FREE SOURCE", 49 | [GETPREVIOUSSOURCE] = "GET PREVIOUS SOURCE", 50 | [GETMNEMONICS] = "GET DEVICE MNEMONICS", 51 | [FINDMNEMONICS] = "FIND DEVICE MNEMONIC", 52 | [GETDIMENSIONS] = "GET DIMENSIONS", 53 | [GETMNEMONICSPORT] = "GET PORT MNEMONICS", 54 | [ALLLEVELESTAKE] = "DEVICE TAKE - ALL LEVELS", 55 | [GETEXTENDEDDIMENSIONS] = "GET EXTENDED DIMENSIONS", 56 | [GETCROSSPOINTSTATUS] = "GET CROSSPOINT STATUS", 57 | [GETEXTMNEMONICS] = "GET EXTENDED DEVICE MNEMONICS", 58 | [FINDEXTMNEMONICS] = "FIND EXTENDED DEVICE MNEMONICS", 59 | [GETEXTMNEMONICSPORT] = "GET EXTENDED PORT MNEMONICS", 60 | [ERRORRESPONSE] = "ERROR RESPONSE" 61 | } 62 | 63 | 64 | local lockops = { 65 | [0] = "Lock Output", 66 | [1] = "Lock Input", 67 | [2] = "Protect Output", 68 | [3] = "Protect Input", 69 | [4] = "Release Output", 70 | [5] = "Release Input", 71 | [6] = "Force Release Output", 72 | [7] = "Force Release Input" 73 | } 74 | 75 | local mnemonictype = { 76 | [0] = "Device", 77 | [1] = "Virtual Level", 78 | [2] = "Sources", 79 | [3] = "Destinations", 80 | [4] = "Categories", 81 | [5] = "Salvos", 82 | [6] = "Source Categories", 83 | [7] = "Destination Categories" 84 | } 85 | 86 | local changetype = { 87 | [0] = "Crosspoint change", 88 | [1] = "Output Locked", 89 | [2] = "Output Protected", 90 | [3] = "Output Released", 91 | [4] = "Input Locked", 92 | [5] = "Input Protected", 93 | [6] = "Input Released" 94 | } 95 | 96 | local charset = { [0] = "ASCII", [1] = "UCS-16" } 97 | 98 | local f_command = ProtoField.uint32("np0017.command", "Command", base.HEX, commands); 99 | local f_charset = ProtoField.uint32("np0017.charset", "Char Set", base.HEX, charset); 100 | local f_length = ProtoField.int32("np0017.length", "Length"); 101 | local f_sequence = ProtoField.uint32("np0017.sequence", "Sequence"); 102 | local f_osequence = ProtoField.uint32("np0017.osequence", "Originating Sequence"); 103 | local f_cmdreply = ProtoField.uint32("np0017.cmdreply", "Cmd/Reply", base.HEX, 104 | { [0] = "Command", [0x80000000] = "Reply" }); 105 | local f_protocol = ProtoField.uint32("np0017.protocol", "Protocol", base.HEX); 106 | local f_input = ProtoField.int32("np0017.input", "Input"); 107 | local f_offset = ProtoField.int32("np0017.offset", "Offset"); 108 | local f_level = ProtoField.int32("np0017.level", "Level"); 109 | local f_direction = ProtoField.uint32("np0017.direction", "Direction", base.HEX, { [0] = "Output", [1] = "Input" }); 110 | 111 | local f_output = ProtoField.int32("np0017.output", "Output"); 112 | local f_userid = ProtoField.int32("np0017.userid", "User ID"); 113 | local f_status = ProtoField.uint32("np0017.status", "Status", base.HEX, 114 | { 115 | [0] = "Success", 116 | [1] = "Invalid Data", 117 | [2] = "Unknown Error", 118 | [3] = "Invalid Source", 119 | [4] = "Invalid Dest", 120 | [5] = "Invalid Level" 121 | }); 122 | local f_operationflag = ProtoField.uint32("np0017.opflag", "Operation", base.HEX, 123 | { 124 | [0] = "Crosspoint", 125 | [1] = "Output Lock", 126 | [2] = "Input Lock", 127 | [3] = "Input Crosspoint", 128 | [4] = "Drop input", 129 | [5] = "Drop output" 130 | }); 131 | local f_numentries = ProtoField.int32("np0017.entries", "Entries"); 132 | local f_lockop = ProtoField.uint32("np0017.lockop", "Lock Operation", base.HEX, lockops); 133 | local f_mnemonic = ProtoField.string("np0017.mnemonic", "Mnemonic"); 134 | local f_changetype = ProtoField.uint32("np0017.changetype", "Change Type", base.HEX, changetype); 135 | local f_lockstatus = ProtoField.uint32("np0017.lockstatus", "Lock Status", base.HEX, changetype); 136 | local f_mnemonictype = ProtoField.uint32("np0017.mnemomictype", "Mnemonic Type", base.HEX, mnemonictype); 137 | np0017.fields = { f_command, f_length, f_sequence, f_protocol, f_cmdreply, f_input, f_output, f_level, f_userid, 138 | f_numentries, f_lockop, f_mnemonictype, f_mnemonic, f_changetype, f_offset, f_charset, f_status, f_operationflag, 139 | f_osequence, f_direction, f_lockstatus }; 140 | 141 | 142 | local ef_malformed = ProtoExpert.new("np0017.malformed.expert", "Malformed packet", 143 | expert.group.MALFORMED, 144 | expert.severity.ERROR); 145 | 146 | local ef_badstatus = ProtoExpert.new("np0017.badstatus.expert", "Bad Status", 147 | expert.group.RESPONSE_CODE, 148 | expert.severity.WARN); 149 | 150 | np0017.experts = { ef_malformed, ef_badstatus } 151 | 152 | function rangeLong(rr, i) 153 | local r = rr:range(i, 4) 154 | return r, r:uint() 155 | end 156 | 157 | function rangeString(range, i, len) 158 | local r = range:range(i, len) 159 | return r, r:string() 160 | end 161 | 162 | function rangeUString(range, i, len) 163 | local r = range:range(i, len) 164 | return r, r:ustring() 165 | end 166 | 167 | function add_int(tree, range, base, name) 168 | local r, v = rangeLong(range, base) 169 | tree:add(r, name, v) 170 | end 171 | 172 | function add_takeport(tree, range) 173 | tree:add(f_userid, rangeLong(range, 16)) 174 | 175 | local f, n = rangeLong(range, 20) 176 | tree:add(f_numentries, f, n) 177 | 178 | for i = 1, n do 179 | local base = 24 + (i - 1) * 16 180 | local sub = tree:add(range:range(base, 16), "Entry " .. i) 181 | sub:add(f_input, rangeLong(range, base)) 182 | sub:add(f_level, rangeLong(range, base + 4)) 183 | sub:add(f_output, rangeLong(range, base + 8)) 184 | end 185 | end 186 | 187 | function add_takeport_reply(tree, range) 188 | tree:add(f_osequence, rangeLong(range, 16)) 189 | local f, n = rangeLong(range, 20) 190 | tree:add(f_numentries, f, n) 191 | 192 | local base = 24 193 | for i = 1, n do 194 | addStatus(tree, range, base) 195 | base = base + 4 196 | end 197 | end 198 | 199 | function addStatus(tree, range, base) 200 | local f, n = rangeLong(range, base) 201 | tree:add(f_status, f, n) 202 | if n ~= 0 then 203 | tree:add_tvb_expert_info(ef_badstatus, f, "Bad Status") 204 | end 205 | end 206 | 207 | function add_lockport(tree, range) 208 | tree:add(f_userid, rangeLong(range, 16)) 209 | 210 | local f, n = rangeLong(range, 20) 211 | tree:add(f_numentries, f, n) 212 | 213 | for i = 1, n do 214 | local base = 24 + (i - 1) * 12 215 | local sub = tree:add(range:range(base, 12), "Entry " .. i) 216 | sub:add(f_lockop, rangeLong(range, base)) 217 | sub:add(f_level, rangeLong(range, base + 4)) 218 | sub:add(f_output, rangeLong(range, base + 8)) 219 | end 220 | end 221 | 222 | function add_lockportreply(tree, range) 223 | tree:add(f_osequence, rangeLong(range, 16)) 224 | local f, n = rangeLong(range, 20) 225 | tree:add(f_numentries, f, n) 226 | 227 | for i = 1, n do 228 | local base = 24 + (i - 1) * 4 229 | local sub = tree:add(range:range(base, 4), "Entry " .. i) 230 | addStatus(tree, range, base) 231 | end 232 | end 233 | 234 | function add_dimensions(tree, range) 235 | tree:add(f_osequence, rangeLong(range, 16)) 236 | local f, n = rangeLong(range, 20) 237 | tree:add(f_numentries, f, n) 238 | 239 | for i = 1, n do 240 | local base = 24 + (i - 1) * 24 241 | local sub = tree:add(range:range(base, 16), "Entry " .. i) 242 | sub:add(f_level, rangeLong(range, base)) 243 | add_int(sub, range, base + 4, "Level Type") 244 | add_int(sub, range, base + 8, "Input Start") 245 | add_int(sub, range, base + 12, "Input End") 246 | add_int(sub, range, base + 16, "Output Start") 247 | add_int(sub, range, base + 20, "Output End") 248 | end 249 | end 250 | 251 | function add_getextmnemonics(tree, range) 252 | tree:add(f_mnemonictype, rangeLong(range, 16)) 253 | local f, n = rangeLong(range, 20) 254 | tree:add(f_numentries, f, n) 255 | 256 | for i = 1, n do 257 | local base = 24 + (i - 1) * 12 258 | local sub = tree:add(range:range(base, 12), "Entry " .. i) 259 | sub:add(f_level, rangeLong(range, base)) 260 | local r, v = rangeLong(range, base + 8) 261 | if v == 0 then 262 | sub:add(f_output, rangeLong(range, base + 4)) 263 | else 264 | sub:add(f_input, rangeLong(range, base + 4)) 265 | end 266 | end 267 | end 268 | 269 | function add_getdevmnemonics(tree, range) 270 | tree:add(f_mnemonictype, rangeLong(range, 16)) 271 | tree:add(f_charset, rangeLong(range, 20)) 272 | tree:add(f_numentries, rangeLong(range, 24)) 273 | tree:add(f_offset, rangeLong(range, 28)) 274 | end 275 | 276 | function add_getdevmnemonics_reply(tree, range) 277 | tree:add(f_osequence, rangeLong(range, 16)) 278 | local f, n = rangeLong(range, 20) 279 | tree:add(f_numentries, f, n) 280 | -- assume we're decoding unicode for now 281 | local base = 24 282 | for i = 1, n do 283 | local sub = tree:add(range:range(base, 24), "Entry " .. i) 284 | sub:add(f_input, rangeLong(range, base + 4)) 285 | sub:add(f_mnemonic, rangeUString(range, base + 8, 16)) 286 | base = base + 24 287 | end 288 | end 289 | 290 | function add_registerport(tree, range) 291 | local f, n = rangeLong(range, 16) 292 | tree:add(f_numentries, f, n) 293 | local base = 20 294 | for i = 1, n do 295 | local sub = tree:add(range:range(base, 12), "Entry " .. i) 296 | sub:add(f_operationflag, rangeLong(range, base)) 297 | sub:add(f_level, rangeLong(range, base + 4)) 298 | sub:add(f_output, rangeLong(range, base + 8)) 299 | base = base + 12 300 | end 301 | end 302 | 303 | function add_registerport_reply(tree, range) 304 | tree:add(f_osequence, rangeLong(range, 16)) 305 | local f, n = rangeLong(range, 20) 306 | tree:add(f_numentries, f, n) 307 | local base = 24 308 | for i = 1, n do 309 | local sub = tree:add(range:range(base, 4), "Entry " .. i) 310 | addStatus(sub, range, base) 311 | base = base + 4 312 | end 313 | end 314 | 315 | function add_getextmnemonics_reply(tree, range) 316 | tree:add(f_osequence, rangeLong(range, 16)) 317 | tree:add(f_mnemonictype, rangeLong(range, 20)) 318 | local f, n = rangeLong(range, 24) 319 | tree:add(f_numentries, f, n) 320 | 321 | local base = 28 322 | for i = 1, n do 323 | local lenr, lenv = rangeLong(range, base + 16) 324 | local sub = tree:add(range:range(base, 20 + lenv), "Entry " .. i) 325 | sub:add(f_level, rangeLong(range, base)) 326 | local r, v = rangeLong(range, base + 8) 327 | if v == 0 then 328 | sub:add(f_output, rangeLong(range, base + 4)) 329 | else 330 | sub:add(f_input, rangeLong(range, base + 4)) 331 | end 332 | 333 | sub:add(f_mnemonic, rangeString(range, base + 20, lenv)) 334 | base = base + 20 + lenv 335 | end 336 | end 337 | 338 | function add_portchanged(tree, range) 339 | local f, n = rangeLong(range, 16) 340 | tree:add(f_numentries, f, n) 341 | 342 | local base = 20 343 | for i = 1, n do 344 | local sub = tree:add(range:range(base, 24), "Entry " .. i) 345 | sub:add(f_changetype, rangeLong(range, base)) 346 | 347 | sub:add(f_level, rangeLong(range, base + 4)) 348 | sub:add(f_output, rangeLong(range, base + 8)) 349 | sub:add(f_input, rangeLong(range, base + 12)) 350 | sub:add(f_userid, rangeLong(range, base + 16)) 351 | addStatus(sub, range, base + 20) 352 | 353 | base = base + 24 354 | end 355 | end 356 | 357 | function add_portstatus(tree, range) 358 | local f, n = rangeLong(range, 16) 359 | tree:add(f_numentries, f, n) 360 | 361 | local base = 20 362 | for i = 1, n do 363 | local sub = tree:add(range:range(base, 8), "Entry " .. i) 364 | sub:add(f_level, rangeLong(range, base)) 365 | sub:add(f_output, rangeLong(range, base + 4)) 366 | base = base + 8 367 | end 368 | end 369 | 370 | function add_portstatusreply(tree, range) 371 | tree:add(f_osequence, rangeLong(range, 16)) 372 | local f, n = rangeLong(range, 20) 373 | tree:add(f_numentries, f, n) 374 | 375 | local base = 24 376 | for i = 1, n do 377 | local sub = tree:add(range:range(base, 8), "Entry " .. i) 378 | sub:add(f_level, rangeLong(range, base)) 379 | sub:add(f_output, rangeLong(range, base + 4)) 380 | sub:add(f_input, rangeLong(range, base + 8)) 381 | 382 | base = base + 16 383 | end 384 | end 385 | 386 | function add_portlockstatus(tree, range) 387 | local f, n = rangeLong(range, 16) 388 | tree:add(f_numentries, f, n) 389 | 390 | local base = 20 391 | for i = 1, n do 392 | local sub = tree:add(range:range(base, 12), "Entry " .. i) 393 | sub:add(f_level, rangeLong(range, base)) 394 | sub:add(f_output, rangeLong(range, base + 4)) 395 | sub:add(f_direction, rangeLong(range, base + 8)) 396 | 397 | base = base + 12 398 | end 399 | end 400 | 401 | function add_portlockstatusreply(tree, range) 402 | tree:add(f_osequence, rangeLong(range, 16)) 403 | local f, n = rangeLong(range, 20) 404 | tree:add(f_numentries, f, n) 405 | 406 | local base = 24 407 | for i = 1, n do 408 | local sub = tree:add(range:range(base, 16), "Entry " .. i) 409 | sub:add(f_level, rangeLong(range, base)) 410 | sub:add(f_output, rangeLong(range, base + 4)) 411 | sub:add(f_lockstatus, rangeLong(range, base + 8)) 412 | sub:add(f_userid, rangeLong(range, base + 12)) 413 | base = base + 16 414 | end 415 | end 416 | 417 | function add_extdimensions(tree, range) 418 | tree:add(f_osequence, rangeLong(range, 16)) 419 | local f, n = rangeLong(range, 20) 420 | tree:add(f_numentries, f, n) 421 | local base = 24 422 | for i = 1, n do 423 | local lenr, lenv = rangeLong(range, base + 12) 424 | local sub = tree:add(range:range(base, lenv + 36), "Entry " .. i) 425 | add_int(sub, range, base, "Router ID") 426 | add_int(sub, range, base + 4, "Level ID") 427 | add_int(sub, range, base + 8, "Level Number") 428 | sub:add(f_mnemonic, rangeString(range, base + 16, lenv)) 429 | base = base + 16 + lenv 430 | add_int(sub, range, base, "Level Type") 431 | add_int(sub, range, base + 4, "Input Start") 432 | add_int(sub, range, base + 8, "Input End") 433 | add_int(sub, range, base + 12, "Output Start") 434 | add_int(sub, range, base + 16, "Output End") 435 | end 436 | end 437 | 438 | function add_errorresponse(tree, range) 439 | tree:add(f_osequence, rangeLong(range, 16)) 440 | addStatus(tree, range, 20) 441 | end 442 | 443 | function processPacket(root, range) 444 | local tree = root:add(range, "NP0017") 445 | 446 | tree:add(f_protocol, rangeLong(range, 0)) 447 | tree:add(f_sequence, rangeLong(range, 4)) 448 | tree:add(f_length, rangeLong(range, 8)) 449 | local r, c = rangeLong(range, 12) 450 | tree:add(f_command, r, bit.band(c, 0x0000FFFF)) 451 | tree:add(f_cmdreply, r, bit.band(c, 0x80000000)) 452 | 453 | if c == TAKEPORT then 454 | add_takeport(tree, range) 455 | elseif c == (TAKEPORT + 0x80000000) then 456 | add_takeport_reply(tree, range) 457 | elseif c == LOCKPORT then 458 | add_lockport(tree, range) 459 | elseif c == (LOCKPORT + 0x80000000) then 460 | add_lockportreply(tree, range) 461 | elseif c == (GETDIMENSIONS + 0x80000000) then 462 | add_dimensions(tree, range) 463 | elseif c == GETMNEMONICS then 464 | add_getdevmnemonics(tree, range) 465 | elseif c == (GETMNEMONICS + 0x80000000) then 466 | add_getdevmnemonics_reply(tree, range) 467 | elseif c == GETEXTMNEMONICSPORT then 468 | add_getextmnemonics(tree, range) 469 | elseif (c == GETEXTMNEMONICSPORT + 0x80000000) then 470 | add_getextmnemonics_reply(tree, range) 471 | elseif c == STATUSCHANGEDPORT then 472 | add_portchanged(tree, range) 473 | elseif c == GETSTATUSPORT then 474 | add_portstatus(tree, range) 475 | elseif c == GETSTATUSPORT + 0x80000000 then 476 | add_portstatusreply(tree, range) 477 | elseif c == LOCKSTATUSPORT then 478 | add_portlockstatus(tree, range) 479 | elseif c == LOCKSTATUSPORT + 0x80000000 then 480 | add_portlockstatusreply(tree, range) 481 | elseif c == REGISTERPORT then 482 | add_registerport(tree, range) 483 | elseif (c == REGISTERPORT + 0x80000000) then 484 | add_registerport_reply(tree, range) 485 | elseif c == (GETEXTENDEDDIMENSIONS + 0x80000000) then 486 | add_extdimensions(tree, range) 487 | elseif c == ERRORRESPONSE then 488 | add_errorresponse(tree, range) 489 | end 490 | end 491 | 492 | function np0017.dissector(tvb, pinfo, root_tree) 493 | pinfo.cols.protocol = "NVision NP0017"; 494 | local p = 0 495 | while p < tvb:len() do 496 | local st, l = lookForPacket(tvb, root_tree, p) 497 | if l then 498 | p = st + l; 499 | else 500 | pinfo.desegment_offset = st 501 | pinfo.desegment_len = DESEGMENT_ONE_MORE_SEGMENT 502 | return 503 | end 504 | end 505 | end 506 | 507 | function lookForPacket(tvb, root_tree, startpos) 508 | local bytes = tvb:bytes(); 509 | local len = bytes:len() 510 | 511 | if (len < 16) then return startpos end -- 16 byte header 512 | 513 | if (bytes:int(startpos, 4) ~= 0x0e) then 514 | root_tree:add_tvb_expert_info(ef_malformed, tvb(startpos, 4), "invalid protocol") 515 | return startpos + 4 516 | end 517 | 518 | local plen = bytes:int(startpos + 8, 4) 519 | 520 | if plen < 16 or plen > 8192 then 521 | root_tree:add_tvb_expert_info(ef_malformed, tvb(startpos, 4), "invalid length") 522 | return startpos + 12 523 | end 524 | 525 | 526 | if (len >= plen) then 527 | processPacket(root_tree, tvb:range(startpos, plen)) 528 | return startpos, plen 529 | else 530 | return startpos -- end not found - keep looking 531 | end 532 | end 533 | 534 | local tcp_encap_table = DissectorTable.get("tcp.port") 535 | tcp_encap_table:add(9193, np0017) 536 | tcp_encap_table:add(9194, np0017) 537 | -------------------------------------------------------------------------------- /probel_swp02_dissector.lua: -------------------------------------------------------------------------------- 1 | -- ProBel SW-P-02 Protocol dissector for Wireshark. 2 | -- 3 | -- Copyright (C) 2021 Rascular Technology Ltd. 4 | -------------------------------------------------------------- 5 | local INTERROGATE = 1 6 | local CONNECT = 2 7 | local TALLY = 3 8 | local CONNECTED = 4 9 | local CONNECT_ON_GO = 5 10 | local GO = 6 11 | local STATUS_REQUEST = 7 12 | local STATUS_RESPONSE_1 = 8 13 | local STATUS_RESPONSE_2 = 9 14 | local STATUS_RESPONSE_3 = 10 15 | local CONNECT_ON_GO_ACK = 12 16 | local GO_DONE_ACK = 13 17 | 18 | local EXTENDED_INTERROGATE = 65 19 | local EXTENDED_CONNECT = 66 20 | local EXTENDED_TALLY = 67 21 | local EXTENDED_CONNECTED = 68 22 | local EXTENDED_CONNECT_ON_GO = 69 23 | local EXTENDED_CONNECT_ON_GO_ACK = 70 24 | 25 | local ROUTER_CONFIGURATION_REQUEST = 75 26 | local ROUTER_CONFIGURATION_RESPONSE_1 = 76 27 | local ROUTER_CONFIGURATION_RESPONSE_2 = 77 28 | 29 | local codes = { 30 | [0] = "DATABASE CHECKSUM", 31 | [INTERROGATE] = "INTERROGATE", 32 | [CONNECT] = "CONNECT", 33 | [TALLY] = "TALLY", 34 | [CONNECTED] = "CONNECTED", 35 | [CONNECT_ON_GO] = "CONNECT_ON_GO", 36 | [GO] = "GO", 37 | [STATUS_REQUEST] = "STATUS_REQUEST", 38 | [STATUS_RESPONSE_1] = "STATUS_RESPONSE_1", 39 | [STATUS_RESPONSE_2] = "STATUS_RESPONSE_2", 40 | [STATUS_RESPONSE_3] = "STATUS_RESPONSE_3", 41 | 42 | [CONNECT_ON_GO_ACK] = "CONNECT_ON_GO_ACK", 43 | [GO_DONE_ACK] = "GO_DONE_ACK", 44 | [EXTENDED_INTERROGATE] = "EXTENDED_INTERROGATE", 45 | [EXTENDED_CONNECT] = "EXTENDED_CONNECT", 46 | [EXTENDED_TALLY] = "EXTENDED_TALLY", 47 | [EXTENDED_CONNECTED] = "EXTENDED_CONNECTED", 48 | [EXTENDED_CONNECT_ON_GO] = "EXTENDED_CONNECT_ON_GO", 49 | [EXTENDED_CONNECT_ON_GO_ACK] = "EXTENDED_CONNECT_ON_GO_ACK", 50 | [ROUTER_CONFIGURATION_REQUEST] = "ROUTER_CONFIGURATION_REQUEST", 51 | [ROUTER_CONFIGURATION_RESPONSE_1] = "ROUTER_CONFIGURATION_RESPONSE_1", 52 | [ROUTER_CONFIGURATION_RESPONSE_2] = "ROUTER_CONFIGURATION_RESPONSE_2" 53 | 54 | } 55 | 56 | local lengths = { 57 | [INTERROGATE] = 2, 58 | [CONNECT] = 3, 59 | [TALLY] = 3, 60 | [CONNECTED] = 3, 61 | [CONNECT_ON_GO] = 3, 62 | [CONNECT_ON_GO_ACK] = 3, 63 | 64 | [GO] = 1, 65 | [GO_DONE_ACK] = 1, 66 | 67 | [STATUS_REQUEST] = 1, 68 | 69 | [STATUS_RESPONSE_1] = 3, 70 | [STATUS_RESPONSE_2] = 1, 71 | [STATUS_RESPONSE_3] = 3, 72 | 73 | [EXTENDED_INTERROGATE] = 2, 74 | [EXTENDED_CONNECT] = 4, 75 | [EXTENDED_TALLY] = 5, 76 | [EXTENDED_CONNECTED] = 5, 77 | 78 | [EXTENDED_CONNECT_ON_GO] = 4, 79 | [EXTENDED_CONNECT_ON_GO_ACK] = 4, 80 | 81 | [ROUTER_CONFIGURATION_REQUEST] = 0, 82 | [ROUTER_CONFIGURATION_RESPONSE_1] = 8, 83 | [ROUTER_CONFIGURATION_RESPONSE_2] = 14 84 | } 85 | 86 | local p_swp02 = Proto("swp02", "Pro-Bel SW-P-02 protocol"); 87 | local f_opcode = ProtoField.uint16("swp.op", "OpCode", base.HEX, codes); 88 | 89 | local f_name = ProtoField.string("swp.name", "Name"); 90 | 91 | local f_source = ProtoField.uint16("swp.source", "Source"); 92 | local f_dest = ProtoField.uint16("swp.dest", "Dest"); 93 | 94 | local f_sources = ProtoField.uint16("swp.sources", "Sources"); 95 | local f_dests = ProtoField.uint16("swp.dests", "Dests"); 96 | 97 | local f_start = ProtoField.uint16("swp.start", "Start"); 98 | local f_device = ProtoField.uint16("swp.device", "Device"); 99 | local f_checksum = ProtoField.uint8("swp.checksum", "Checksum"); 100 | local f_status = ProtoField.uint8("swp.status", "Status"); 101 | 102 | local f_go = ProtoField.uint8("swp.go", "Go", base.HEX, 103 | { "Set", "Clear", "None Selected" }) 104 | local f_count = ProtoField.uint8("swp.count", "Count"); 105 | 106 | p_swp02.fields = { 107 | f_opcode, f_source, f_dest, f_device, f_checksum, f_sources, f_dests, 108 | f_start, f_name, f_count, f_go, f_status 109 | }; 110 | 111 | local ef_bad_checksum = ProtoExpert.new("swp.checksum.expert", "Bad checksum", 112 | expert.group.MALFORMED, 113 | expert.severity.ERROR); 114 | 115 | p_swp02.experts = { ef_bad_checksum } 116 | 117 | local SOM = 0xFF 118 | 119 | function rangeByte(range, i) 120 | local r = range:range(i, 1) 121 | return r, r:uint() 122 | end 123 | 124 | function rangeWord14(range, i) 125 | local r = range:range(i, 2) 126 | local buff = r:bytes() 127 | return r, bit.lshift(buff:get_index(0), 7) + buff:get_index(1) 128 | end 129 | 130 | function rangeDest10(range, i) 131 | local r = range:range(i, 2) 132 | local buff = r:bytes() 133 | return r, bit.lshift(bit.band(buff:get_index(0), 0x70), 3) + 134 | buff:get_index(1) 135 | end 136 | 137 | function rangeSrc10(range, i) 138 | local r = range:range(i, 3) 139 | local buff = r:bytes() 140 | return r, bit.lshift(bit.band(buff:get_index(0), 0x7), 7) + 141 | buff:get_index(2) 142 | end 143 | 144 | function processPacket(root, range) 145 | local tree = root:add(range, "SW-P-02") 146 | local r, op = rangeByte(range, 1) 147 | 148 | tree:add(f_opcode, r, op) 149 | 150 | if op == INTERROGATE then 151 | tree:add(f_dest, rangeDest10(range, 2)) 152 | elseif op == EXTENDED_INTERROGATE then 153 | tree:add(f_dest, rangeWord14(range, 2)) 154 | elseif op == EXTENDED_CONNECT then 155 | tree:add(f_dest, rangeWord14(range, 2)) 156 | tree:add(f_source, rangeWord14(range, 4)) 157 | elseif op == EXTENDED_CONNECTED or op == EXTENDED_TALLY then 158 | tree:add(f_dest, rangeWord14(range, 2)) 159 | tree:add(f_source, rangeWord14(range, 4)) 160 | tree:add(f_status, rangeByte(range, 6)) 161 | elseif (op == CONNECT) or (op == TALLY) or (op == CONNECTED) or 162 | (op == CONNECT_ON_GO) or (op == CONNECT_ON_GO_ACK) then 163 | tree:add(f_dest, rangeDest10(range, 2)) 164 | tree:add(f_source, rangeSrc10(range, 2)) 165 | elseif op == GO or op == GO_DONE_ACK then 166 | tree:add(f_go, rangeByte(range, 2)) 167 | elseif op == ROUTER_CONFIGURATION_RESPONSE_1 then 168 | tree:add(f_dests, rangeWord14(range, 6)) 169 | tree:add(f_sources, rangeWord14(range, 8)) 170 | end 171 | 172 | -- validate checksum 173 | local mess = range:bytes() 174 | local sum = 0 175 | for i = 1, mess:len() - 2 do sum = sum + mess:get_index(i) end 176 | 177 | if bit.band(-sum, 0x7f) ~= mess:get_index(mess:len() - 1) then 178 | tree:add_proto_expert_info(ef_bad_checksum) 179 | end 180 | tree:add(f_checksum, rangeByte(range, mess:len() - 1)) 181 | end 182 | 183 | function p_swp02.dissector(tvb, pinfo, root_tree) 184 | pinfo.cols.protocol = "SW-P-02"; 185 | local p = 0 186 | while p < tvb:len() do 187 | local st, l = lookForPacket(tvb, root_tree, p) 188 | 189 | if l then 190 | p = st + l; 191 | else 192 | pinfo.desegment_offset = st 193 | pinfo.desegment_len = DESEGMENT_ONE_MORE_SEGMENT 194 | return 195 | end 196 | end 197 | end 198 | 199 | function lookForPacket(tvb, root_tree, startpos) 200 | local bytes = tvb:bytes(); 201 | local len = bytes:len() 202 | local p = startpos 203 | local start = 0 204 | 205 | while p < (len - 1) do 206 | if (bytes:get_index(p) == SOM) and ((p + 1) < len) then 207 | start = p 208 | 209 | local cmd = bytes:get_index(p + 1) -- command byte found 210 | if lengths[cmd] and ((p + 2 + lengths[cmd]) < len) then 211 | local range = tvb:range(start, 3 + lengths[cmd]) 212 | processPacket(root_tree, range) 213 | return start, range:len() 214 | end 215 | end 216 | p = p + 1 217 | end 218 | 219 | return p -- packet is segmented or no start found. 220 | end 221 | 222 | local tcp_encap_table = DissectorTable.get("tcp.port") 223 | tcp_encap_table:add(2006, p_swp02) 224 | -------------------------------------------------------------------------------- /probel_swp08_dissector.lua: -------------------------------------------------------------------------------- 1 | -- ProBel SW-P-08 Protocol dissector for Wireshark. 2 | -- 3 | -- Copyright (C) 2021 Rascular Technology Ltd. 4 | -------------------------------------------------------------- 5 | local CROSSPOINT_INTERROGATE = 1 6 | local CROSSPOINT_CONNECT = 2 7 | local CROSSPOINT_TALLY = 3 8 | local CROSSPOINT_CONNECTED = 4 9 | local PROTECT_INTERROGATE = 10 10 | local PROTECT_TALLY = 11 11 | local PROTECT_CONNECT = 12 12 | local PROTECT_CONNECTED = 13; 13 | local PROTECT_DISCONNECT = 14 14 | local PROTECT_DISCONNECTED = 15 15 | 16 | local PROTECT_TALLY_DUMP_REQUEST = 19 17 | local PROTECT_TALLY_DUMP_RESPONSE = 20 18 | 19 | local CROSSPOINT_TALLY_DUMP_REQUEST = 21 20 | local CROSSPOINT_TALLY_DUMP_RESPONSE_BYTE = 22 21 | local CROSSPOINT_TALLY_DUMP_RESPONSE_WORD = 23 22 | 23 | local ALL_SOURCE_NAMES = 100 24 | local ALL_DESTINATION_NAMES = 102 25 | local SOURCE_NAMES_RESPONSE = 106 26 | local DESTINATION_NAMES_RESPONSE = 107 27 | 28 | local EXT_CROSSPOINT_INTERROGATE = CROSSPOINT_INTERROGATE + 0x80; 29 | local EXT_CROSSPOINT_CONNECT = CROSSPOINT_CONNECT + 0x80; 30 | local EXT_CROSSPOINT_TALLY = CROSSPOINT_TALLY + 0x80; 31 | local EXT_CROSSPOINT_CONNECTED = CROSSPOINT_CONNECTED + 0x80; 32 | 33 | local EXT_PROTECT_INTERROGATE = PROTECT_INTERROGATE + 0x80; 34 | local EXT_PROTECT_TALLY = PROTECT_TALLY + 0x80; 35 | local EXT_PROTECT_CONNECT = PROTECT_CONNECT + 0x80; 36 | local EXT_PROTECT_CONNECTED = PROTECT_CONNECTED + 0x80; 37 | local EXT_PROTECT_DISCONNECT = PROTECT_DISCONNECT + 0x80; 38 | local EXT_PROTECT_DISCONNECTED = PROTECT_DISCONNECTED + 0x80; 39 | 40 | local EXT_CROSSPOINT_TALLY_DUMP_REQUEST = CROSSPOINT_TALLY_DUMP_REQUEST + 0x80 41 | local EXT_CROSSPOINT_TALLY_DUMP_RESPONSE = 42 | CROSSPOINT_TALLY_DUMP_RESPONSE_WORD + 0x80 43 | 44 | local codes = { 45 | [0] = "COMMAND_ENABLE", 46 | [CROSSPOINT_INTERROGATE] = "CROSSPOINT_INTERROGATE", 47 | [CROSSPOINT_CONNECT] = "CROSSPOINT_CONNECT", 48 | [CROSSPOINT_TALLY] = "CROSSPOINT_TALLY", 49 | [CROSSPOINT_CONNECTED] = "CROSSPOINT_CONNECTED", 50 | [7] = "MAINTENANCE", 51 | [8] = "DUAL_CONTROLLER_STATUS", 52 | [9] = "DUAL_CONTROLLER_STATUS_RESPONSE", 53 | [PROTECT_INTERROGATE] = "PROTECT_INTERROGATE", 54 | [PROTECT_TALLY] = "PROTECT_TALLY", 55 | [PROTECT_CONNECT] = "PROTECT_CONNECT", 56 | [PROTECT_CONNECTED] = "PROTECT_CONNECTED", 57 | [PROTECT_DISCONNECT] = "PROTECT_DISCONNECT", 58 | [PROTECT_DISCONNECTED] = "PROTECT_DISCONNECTED", 59 | [17] = "PROTECT_DEVICE_NAME_REQUEST", 60 | [18] = "PROTECT_DEVICE_NAME_RESONSE", 61 | [PROTECT_TALLY_DUMP_REQUEST] = "PROTECT_TALLY_DUMP_REQUEST", 62 | [PROTECT_TALLY_DUMP_RESPONSE] = "PROTECT_TALLY_DUMP_RESPONSE", 63 | [CROSSPOINT_TALLY_DUMP_REQUEST] = "CROSSPOINT_TALLY_DUMP_REQUEST", 64 | [CROSSPOINT_TALLY_DUMP_RESPONSE_BYTE] = "CROSSPOINT_TALLY_DUMP_RESPONSE_BYTE", 65 | [CROSSPOINT_TALLY_DUMP_RESPONSE_WORD] = "CROSSPOINT_TALLY_DUMP_RESPONSE_WORD", 66 | 67 | [25] = "ROUTER_IO_PARAMETERS_INTERROGATE", 68 | [26] = "ROUTER_IO_PARAMETERS_TALLY", 69 | [27] = "ROUTER_IO_PARAMETERS_CONNECT", 70 | [28] = "ROUTER_IO_PARAMETERS_CONNECTED", 71 | [29] = "MASTER_PROTECT_CONNECT", 72 | [30] = "NAMES_UPDATED", 73 | 74 | [41] = "DIAGNOSTIC", 75 | [43] = "DIAGNOSTIC_RESPONSE", 76 | [44] = "LOG_MESSAGE", 77 | 78 | [76] = "STATUS_CONFIGURATION", 79 | [77] = "STATUS_CONFIGURATION_TALLY", 80 | [78] = "LOGGING_STRINGS", 81 | [79] = "ERROR_STATUS_REQUEST", 82 | 83 | [87] = "SOFT_KEY_TALLY_REQUEST", 84 | [88] = "SOFT_KEY_TALLY_RESPONSE", 85 | [89] = "SOFT_KEY_ASSIGNEMENT_SET_REQUEST", 86 | [90] = "SOFT_KEY_ASSIGNEMENT_SET_RESPONSE", 87 | 88 | [ALL_SOURCE_NAMES] = "ALL_SOURCE_NAMES", 89 | [101] = "SINGLE_SOURCE_NAME", 90 | [ALL_DESTINATION_NAMES] = "ALL_DESTINATION_NAMES", 91 | [103] = "SINGLE_DESTINATION_NAME", 92 | [104] = "ALL_UMD_LABELS", 93 | [105] = "SINGLE_UMD_LABEL", 94 | [SOURCE_NAMES_RESPONSE] = "SOURCE_NAMES_RESONSE", 95 | [DESTINATION_NAMES_RESPONSE] = "DESTINATION_NAMES_RESPONSE", 96 | [108] = "UMD_LABELS_RESPONSE", 97 | 98 | [114] = "ALL_SOURCE_ASSOCIATION_NAMES", 99 | [115] = "SINGLE_SOURCE_ASSOCIATION_NAMES", 100 | [116] = "SOURCE_ASSOCIATION_NAMES_RESPONSE", 101 | [117] = "UPDATE_NAME", 102 | 103 | [111] = "CROSSPOINT_TIE_LINE_CONNECT", 104 | [112] = "CROSSPOINT_TIE_LINE_INTERROGATE", 105 | [113] = "CROSSPOINT_TIE_LINE_TALLY", 106 | 107 | [120] = "CROSSPOINT_CONNECT_ON_GO_GROUP_SALVO", 108 | [121] = "CROSSPOINT_GO_GROUP_SALVO", 109 | [122] = "CROSSPOINT_CONNECT_ON_GO_GROUP_SALVO_ACK", 110 | [123] = "CROSSPOINT_GO_DONE_GROUP_SALVO", 111 | [124] = "CROSSPOINT_SALVO_GROUP_INTERROGATE", 112 | [125] = "CROSSPOINT_GROUP_SALVO_TALLY", 113 | 114 | [EXT_CROSSPOINT_INTERROGATE] = "EXT_CROSSPOINT_INTERROGATE", 115 | [EXT_CROSSPOINT_CONNECT] = "EXT_CROSSPOINT_CONNECT", 116 | [EXT_CROSSPOINT_TALLY] = "EXT_CROSSPOINT_TALLY", 117 | [EXT_CROSSPOINT_CONNECTED] = "EXT_CROSSPOINT_CONNECTED", 118 | [EXT_PROTECT_INTERROGATE] = "EXT_PROTECT_INTERROGATE", 119 | [EXT_PROTECT_TALLY] = "EXT_PROTECT_TALLY", 120 | [EXT_PROTECT_CONNECT] = "EXT_PROTECT_CONNECT", 121 | [EXT_PROTECT_CONNECTED] = "EXT_PROTECT_CONNECTED", 122 | [EXT_PROTECT_DISCONNECT] = "EXT_PROTECT_DISCONNECT", 123 | [EXT_PROTECT_DISCONNECTED] = "EXT_PROTECT_DISCONNECTED", 124 | [EXT_CROSSPOINT_TALLY_DUMP_REQUEST] = "EXT_CROSSPOINT_TALLY_DUMP_REQUEST", 125 | [EXT_CROSSPOINT_TALLY_DUMP_RESPONSE] = "EXT_CROSSPOINT_TALLY_DUMP_RESPONSE", 126 | 127 | [0x1006] = "ACK", 128 | [0x1015] = "NAK" 129 | } 130 | 131 | local protcodes = { 132 | [0] = "Unlocked", 133 | [1] = "Pro-Bel protect", 134 | [2] = "Override protect", 135 | [3] = "OEM Protect" 136 | } 137 | 138 | 139 | local namelengths = { [0] = 4, [1] = 8, [2] = 12, [3] = 16, [4] = 32 } 140 | 141 | local p_swp08 = Proto("swp08", "Pro-Bel SW-P-08 protocol"); 142 | local f_opcode = ProtoField.uint16("swp.op", "OpCode", base.HEX, codes); 143 | local f_matrix4 = ProtoField.uint8("swp.matrix", "Matrix", base.HEX, nil, 0xF0); 144 | local f_matrix8 = ProtoField.uint8("swp.matrix", "Matrix"); 145 | 146 | local f_level4 = ProtoField.uint8("swp.level", "Level", base.HEX, nil, 0xF); 147 | local f_level8 = ProtoField.uint8("swp.level", "Level"); 148 | 149 | local f_name = ProtoField.string("swp.name", "Name"); 150 | 151 | local f_source16 = ProtoField.uint16("swp.source", "Source"); 152 | 153 | local f_dest16 = ProtoField.uint16("swp.dest", "Dest"); 154 | local f_start = ProtoField.uint16("swp.start", "Start"); 155 | local f_device = ProtoField.uint16("swp.device", "Device"); 156 | local f_checksum = ProtoField.uint8("swp.checksum", "Checksum"); 157 | local f_length = ProtoField.uint8("swp.length", "Length"); 158 | local f_count = ProtoField.uint8("swp.count", "Count"); 159 | 160 | local f_namelength = ProtoField.uint8("swp.namelength", "NameLength", base.HEX, 161 | namelengths); 162 | local f_protect = 163 | ProtoField.uint8("swp.protect", "Protect", base.HEX, protcodes); 164 | 165 | p_swp08.fields = { 166 | f_opcode, f_matrix8, f_level8, f_source16, f_dest16, f_device, f_checksum, 167 | f_protect, f_length, f_namelength, f_level4, f_matrix4, f_start, f_name, 168 | f_count 169 | }; 170 | 171 | local ef_bad_length = ProtoExpert.new("swp.length.expert", "Bad length", 172 | expert.group.MALFORMED, 173 | expert.severity.ERROR); 174 | 175 | local ef_bad_checksum = ProtoExpert.new("swp.checksum.expert", "Bad checksum", 176 | expert.group.MALFORMED, 177 | expert.severity.ERROR); 178 | local ef_bad_dle = ProtoExpert.new("swp.baddle.expert", "Bad DLE sequence", 179 | expert.group.MALFORMED, expert.severity.ERROR); 180 | 181 | p_swp08.experts = { ef_bad_length, ef_bad_checksum, ef_bad_dle } 182 | 183 | local DLE = 0x10 184 | local STX = 2 185 | local ETX = 3 186 | local ACK = 6 187 | local NAK = 0x15 188 | 189 | function dLen(s, start, l) 190 | local dl = l 191 | local ds = 0 192 | for i = 1, start - 1 do if s[i] == DLE then ds = ds + 1 end end 193 | for i = 0, l - 1 do if s[i + start] == DLE then dl = dl + 1 end end 194 | return start + ds + 2 - 1, dl 195 | end 196 | 197 | function rangeByte(range, mess, i) return range:range(dLen(mess, i, 1)), mess[i] end 198 | 199 | function rangeWord(range, mess, i) 200 | return range:range(dLen(mess, i, 2)), mess[i] * 256 + mess[i + 1] 201 | end 202 | 203 | function rangeString(range, mess, i, len) 204 | local r = range:range(dLen(mess, i, len)) 205 | return r, "\"" .. r:string() .. "\"" 206 | end 207 | 208 | function rangeDest12(range, mess, i) 209 | return range:range(dLen(mess, i, 2)), bit.lshift( 210 | bit.band(0x7, bit.rshift(mess[i], 4)), 7) + mess[i + 1] 211 | end 212 | 213 | function rangeSrc12(range, mess, i) 214 | return range:range(dLen(mess, i, 3)), 215 | bit.lshift(bit.band(mess[i], 0xf), 7) + mess[i + 2] 216 | end 217 | 218 | function processPacket(mess, root, range) 219 | local tree = root:add(range, "SW-P-08") 220 | local op = mess[1] 221 | 222 | tree:add(f_opcode, rangeByte(range, mess, 1)) 223 | 224 | if op == CROSSPOINT_INTERROGATE or op == PROTECT_INTERROGATE then 225 | tree:add(f_matrix4, rangeByte(range, mess, 2)) 226 | tree:add(f_level4, rangeByte(range, mess, 2)) 227 | tree:add(f_dest16, rangeDest12(range, mess, 3)) 228 | elseif op == CROSSPOINT_CONNECT or op == CROSSPOINT_CONNECTED or op == 229 | CROSSPOINT_TALLY then 230 | tree:add(f_matrix4, rangeByte(range, mess, 2)) 231 | tree:add(f_level4, rangeByte(range, mess, 2)) 232 | tree:add(f_dest16, rangeDest12(range, mess, 3)) 233 | tree:add(f_source16, rangeSrc12(range, mess, 3)) 234 | elseif op == PROTECT_CONNECT or op == PROTECT_DISCONNECT then 235 | tree:add(f_matrix4, rangeByte(range, mess, 2)) 236 | tree:add(f_level4, rangeByte(range, mess, 2)) 237 | tree:add(f_device, rangeByte(range, mess, 5)) 238 | elseif op == EXT_CROSSPOINT_INTERROGATE or op == EXT_PROTECT_INTERROGATE then 239 | tree:add(f_matrix8, rangeByte(range, mess, 2)) 240 | tree:add(f_level8, rangeByte(range, mess, 3)) 241 | tree:add(f_dest16, rangeWord(range, mess, 4)) 242 | elseif op == PROTECT_TALLY or op == PROTECT_DISCONNECTED or op == 243 | PROTECT_CONNECTED then 244 | tree:add(f_matrix4, rangeByte(range, mess, 2)) 245 | tree:add(f_level4, rangeByte(range, mess, 2)) 246 | tree:add(f_protect, rangeByte(range, mess, 3)) 247 | tree:add(f_dest16, rangeDest12(range, mess, 4)) 248 | tree:add(f_device, rangeSrc12(range, mess, 4)) 249 | elseif op == EXT_CROSSPOINT_CONNECT or op == EXT_CROSSPOINT_CONNECTED or op == 250 | EXT_CROSSPOINT_TALLY then 251 | tree:add(f_matrix8, rangeByte(range, mess, 2)) 252 | tree:add(f_level8, rangeByte(range, mess, 3)) 253 | tree:add(f_dest16, rangeWord(range, mess, 4)) 254 | tree:add(f_source16, rangeWord(range, mess, 6)) 255 | elseif op == EXT_PROTECT_CONNECT or op == EXT_PROTECT_DISCONNECT then 256 | tree:add(f_matrix8, rangeByte(range, mess, 2)) 257 | tree:add(f_level8, rangeByte(range, mess, 3)) 258 | tree:add(f_dest16, rangeWord(range, mess, 4)) 259 | tree:add(f_device, rangeWord(range, mess, 6)) 260 | elseif op == EXT_PROTECT_TALLY or op == EXT_PROTECT_DISCONNECTED or op == 261 | EXT_PROTECT_CONNECTED then 262 | tree:add(f_matrix8, rangeByte(range, mess, 2)) 263 | tree:add(f_level8, rangeByte(range, mess, 3)) 264 | tree:add(f_protect, rangeByte(range, mess, 4)) 265 | tree:add(f_dest16, rangeWord(range, mess, 5)) 266 | tree:add(f_device, rangeWord(range, mess, 7)) 267 | elseif op == SOURCE_NAMES_RESPONSE or op == DESTINATION_NAMES_RESPONSE then 268 | tree:add(f_matrix8, rangeByte(range, mess, 2)) 269 | tree:add(f_namelength, rangeByte(range, mess, 3)) 270 | tree:add(f_start, rangeWord(range, mess, 4)) 271 | tree:add(f_count, rangeByte(range, mess, 6)) 272 | 273 | local len = namelengths[mess[3]]; 274 | 275 | for i = 0, mess[6] - 1 do 276 | tree:add(f_name, rangeString(range, mess, 7 + (i * len), len)) 277 | end 278 | elseif op == ALL_SOURCE_NAMES or op == ALL_DESTINATION_NAMES then 279 | tree:add(f_matrix4, rangeByte(range, mess, 2)) 280 | tree:add(f_namelength, rangeByte(range, mess, 3)) 281 | elseif op == PROTECT_TALLY_DUMP_REQUEST then 282 | tree:add(f_matrix4, rangeByte(range, mess, 2)) 283 | tree:add(f_level4, rangeByte(range, mess, 2)) 284 | tree:add(f_dest16, rangeWord(range, mess, 3)) 285 | elseif op == PROTECT_TALLY_DUMP_RESPONSE then 286 | tree:add(f_matrix4, rangeByte(range, mess, 2)) 287 | tree:add(f_level4, rangeByte(range, mess, 2)) 288 | tree:add(f_dest16, rangeWord(range, mess, 3)) 289 | for i = 0, 16 do 290 | local r, v = rangeByte(range, mess, 4 + 2 * i) 291 | tree:add(f_protect, r, bit.rshift(v, 4)) 292 | end 293 | elseif op == CROSSPOINT_TALLY_DUMP_REQUEST then 294 | tree:add(f_matrix4, rangeByte(range, mess, 2)) 295 | tree:add(f_level4, rangeByte(range, mess, 2)) 296 | elseif op == CROSSPOINT_TALLY_DUMP_RESPONSE_WORD then 297 | tree:add(f_matrix4, rangeByte(range, mess, 2)) 298 | tree:add(f_level4, rangeByte(range, mess, 2)) 299 | tree:add(f_count, rangeByte(range, mess, 3)) 300 | tree:add(f_dest16, rangeWord(range, mess, 4)) 301 | local count = mess[3] 302 | for i = 0, count - 1 do 303 | tree:add(f_source16, rangeWord(range, mess, 6 + i * 2)) 304 | end 305 | elseif op == CROSSPOINT_TALLY_DUMP_RESPONSE_BYTE then 306 | tree:add(f_matrix4, rangeByte(range, mess, 2)) 307 | tree:add(f_level4, rangeByte(range, mess, 2)) 308 | tree:add(f_count, rangeByte(range, mess, 3)) 309 | tree:add(f_dest16, rangeByte(range, mess, 4)) 310 | local count = mess[3] 311 | for i = 0, count - 1 do 312 | tree:add(f_source16, rangeByte(range, mess, 5 + i)) 313 | end 314 | elseif op == EXT_CROSSPOINT_TALLY_DUMP_REQUEST then 315 | tree:add(f_matrix8, rangeByte(range, mess, 2)) 316 | tree:add(f_level8, rangeByte(range, mess, 3)) 317 | elseif op == EXT_CROSSPOINT_TALLY_DUMP_RESPONSE then 318 | tree:add(f_matrix8, rangeByte(range, mess, 2)) 319 | tree:add(f_level8, rangeByte(range, mess, 3)) 320 | tree:add(f_count, rangeByte(range, mess, 4)) 321 | tree:add(f_dest16, rangeWord(range, mess, 5)) 322 | local count = mess[3] 323 | for i = 0, count - 1 do 324 | tree:add(f_source16, rangeWord(range, mess, 7 + i * 2)) 325 | end 326 | end 327 | 328 | tree:add(f_length, rangeByte(range, mess, #mess - 1)) 329 | if (#mess - 2) ~= mess[#mess - 1] then 330 | tree:add_proto_expert_info(ef_bad_length) 331 | end 332 | 333 | -- validate checksum 334 | local sum = 0 335 | for i = 1, #mess - 1, 1 do sum = sum + mess[i] end 336 | 337 | if bit.band(-sum, 0xff) ~= mess[#mess] then 338 | tree:add_proto_expert_info(ef_bad_checksum) 339 | end 340 | 341 | tree:add(f_checksum, rangeByte(range, mess, #mess)) 342 | end 343 | 344 | function processACK(root, range) root:add(f_opcode, range) end 345 | 346 | function processNAK(root, range) root:add(f_opcode, range) end 347 | 348 | function p_swp08.dissector(tvb, pinfo, root_tree) 349 | pinfo.cols.protocol = "SW-P-08"; 350 | local p = 0 351 | while p < tvb:len() do 352 | local st, l = lookForPacket(tvb, root_tree, p) 353 | if l then 354 | p = st + l; 355 | else 356 | pinfo.desegment_offset = st 357 | pinfo.desegment_len = DESEGMENT_ONE_MORE_SEGMENT 358 | return 359 | end 360 | end 361 | end 362 | 363 | function lookForPacket(tvb, root_tree, startpos) 364 | local bytes = tvb:bytes(); 365 | local len = bytes:len() 366 | 367 | if len < 2 then return startpos end 368 | 369 | local p = startpos 370 | 371 | if (bytes:get_index(p) == DLE) and (bytes:get_index(p + 1) == ACK) then 372 | processACK(root_tree, tvb:range(p, 2)) 373 | -- print("Processed Ack", p) 374 | return p, 2; 375 | elseif (bytes:get_index(p) == DLE) and (bytes:get_index(p + 1) == NAK) then 376 | processNAK(root_tree, tvb:range(p, 2)) 377 | -- print("Processed NAK", p) 378 | return p, 2; 379 | elseif (bytes:get_index(p) == DLE) and (bytes:get_index(p + 1) == STX) then 380 | local start = p 381 | -- print("Found start ", start) 382 | p = p + 2 383 | local mess = {} 384 | while p < len do 385 | local c = bytes:get_index(p) 386 | p = p + 1 387 | if c ~= DLE then 388 | mess[#mess + 1] = c 389 | else 390 | if p < len then 391 | c = bytes:get_index(p) 392 | p = p + 1 393 | if c == DLE then 394 | mess[#mess + 1] = c 395 | elseif c == ETX then 396 | local range = tvb:range(start, p - start) 397 | processPacket(mess, root_tree, range) 398 | -- print("Processed ", start, p - start) 399 | return start, p - start 400 | else 401 | root_tree:add_proto_expert_info(ef_bad_dle) 402 | print("Bad DLE, Returning ", p) 403 | return start, p - start 404 | end 405 | end 406 | end 407 | end 408 | else 409 | return p, 1 410 | end 411 | 412 | return startpos -- packet is segmented or no start found. 413 | end 414 | 415 | local tcp_encap_table = DissectorTable.get("tcp.port") 416 | tcp_encap_table:add(2007, p_swp08) 417 | tcp_encap_table:add(2008, p_swp08) 418 | -------------------------------------------------------------------------------- /quartz_dissector.lua: -------------------------------------------------------------------------------- 1 | -- Evertz/Quartz Protocol dissector for Wireshark. 2 | -- 3 | -- Copyright (C) 2021 Rascular Technology Ltd. 4 | -------------------------------------------------------------- 5 | local quartz = Proto("quartz", "Quartz Type 1 RCP protocol"); 6 | 7 | local f_command = ProtoField.string("quartz.command", "Command"); 8 | local f_response = ProtoField.string("quartz.response", "Response"); 9 | local f_status = ProtoField.string("quartz.status", "Status"); 10 | local f_body = ProtoField.string("quartz.body", "Body"); 11 | 12 | quartz.fields = { f_command, f_status, f_response, f_body }; 13 | 14 | 15 | local ef_error = ProtoExpert.new("quartz.error.expert", "Error Response", 16 | expert.group.RESPONSE_CODE, 17 | expert.severity.ERROR); 18 | 19 | quartz.experts = { ef_error } 20 | function rangeChar(range, i) 21 | local r = range:range(i, 1) 22 | return r, r:uint() 23 | end 24 | 25 | function rangeString(range, i, len) 26 | local r = range:range(i, len) 27 | return r, r:string() 28 | end 29 | 30 | local function starts_with(str, start) return str:sub(1, #start) == start end 31 | 32 | function processPacket(mess, root, range) 33 | local tree = root:add(range, "Quartz RCP") 34 | 35 | if starts_with(mess, ".S") then 36 | tree:add(f_command, range:range(0, 2), "SET") 37 | elseif starts_with(mess, ".A") then 38 | tree:add(f_command, range:range(0, 2), "ACK") 39 | elseif starts_with(mess, ".U") then 40 | tree:add(f_command, range:range(0, 2), "UPDATE") 41 | elseif starts_with(mess, ".L") then 42 | tree:add(f_command, range:range(0, 2), "LIST ROUTES") 43 | elseif starts_with(mess, ".I") then 44 | tree:add(f_command, range:range(0, 2), "INTERROGATE") 45 | elseif starts_with(mess, ".M") then 46 | tree:add(f_command, range:range(0, 2), "SET MULTI") 47 | elseif starts_with(mess, ".F") then 48 | tree:add(f_command, range:range(0, 2), "FIRE SALVO") 49 | elseif starts_with(mess, ".P") then 50 | tree:add(f_command, range:range(0, 2), "POWER UP") 51 | elseif starts_with(mess, ".BL") then 52 | tree:add(f_command, range:range(0, 3), "LOCK") 53 | elseif starts_with(mess, ".BU") then 54 | tree:add(f_command, range:range(0, 3), "UNLOCK") 55 | elseif starts_with(mess, ".BI") then 56 | tree:add(f_command, range:range(0, 3), "INTERROGATE LOCK") 57 | elseif starts_with(mess, ".BA") then 58 | tree:add(f_command, range:range(0, 3), "LOCK STATUS") 59 | elseif starts_with(mess, ".I") then 60 | tree:add(f_command, range:range(0, 2), "POWER UP") 61 | elseif starts_with(mess, ".#01") then 62 | tree:add(f_command, range:range(0, 4), "PING") 63 | elseif starts_with(mess, ".RD") then 64 | tree:add(f_command, range:range(0, 3), "READ DEST MNEM") 65 | elseif starts_with(mess, ".RS") then 66 | tree:add(f_command, range:range(0, 3), "READ SRC MNEM") 67 | elseif starts_with(mess, ".RL") then 68 | tree:add(f_command, range:range(0, 3), "READ LVL MNEM") 69 | elseif starts_with(mess, ".RAD") then 70 | tree:add(f_command, range:range(0, 4), "DEST MNEM") 71 | elseif starts_with(mess, ".RAS") then 72 | tree:add(f_command, range:range(0, 4), "SRC MNEM") 73 | elseif starts_with(mess, ".RAL") then 74 | tree:add(f_command, range:range(0, 4), "LVL MNEM") 75 | elseif starts_with(mess, ".E") then 76 | tree:add_proto_expert_info(ef_error) 77 | tree:add(f_command, range:range(0, 2), "ERROR") 78 | end 79 | 80 | tree:add(f_body, rangeString(range, 0, #mess)) 81 | end 82 | 83 | function quartz.dissector(tvb, pinfo, root_tree) 84 | pinfo.cols.protocol = "Quartz"; 85 | local p = 0 86 | while p < tvb:len() do 87 | local st, l = lookForPacket(tvb, root_tree, p) 88 | if l then 89 | p = st + l; 90 | else 91 | pinfo.desegment_offset = st 92 | pinfo.desegment_len = DESEGMENT_ONE_MORE_SEGMENT 93 | return 94 | end 95 | end 96 | end 97 | 98 | function lookForPacket(tvb, root_tree, startpos) 99 | local bytes = tvb:bytes(); 100 | local len = bytes:len() 101 | local mess = "" 102 | 103 | for p = startpos, len - 1 do 104 | local c = string.char(bytes:get_index(p)) 105 | if (c == '\r') then 106 | local range = tvb:range(startpos, #mess) 107 | processPacket(mess, root_tree, range) 108 | return startpos, #mess + 1 109 | else 110 | mess = mess .. c 111 | end 112 | end 113 | return startpos -- end not found - keep looking 114 | end 115 | 116 | local tcp_encap_table = DissectorTable.get("tcp.port") 117 | tcp_encap_table:add(4000, quartz) 118 | -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roddypratt/router_dissectors/77ca6ccdda96b31e51c646cdbb55a72ca6417f26/screenshot.png -------------------------------------------------------------------------------- /skeleton.lua: -------------------------------------------------------------------------------- 1 | local test = Proto("Test", "Test dissector"); 2 | 3 | local f_test = ProtoField.char("Test.Sequence", "Sequence"); 4 | 5 | test.fields = { f_test }; 6 | 7 | function test.dissector(tvb, pinfo, root_tree) 8 | local range = tvb:range(1, 1) 9 | 10 | root_tree:add(f_test, range, range:string()) 11 | end 12 | 13 | local tcp_encap_table = DissectorTable.get("tcp.port") 14 | tcp_encap_table:add(12345, test) 15 | -------------------------------------------------------------------------------- /utah_rcp3a_dissector.lua: -------------------------------------------------------------------------------- 1 | -- Utah RCP-3A Protocol dissector for Wireshark. 2 | -- 3 | -- Copyright (C) 2021 Rascular Technology Ltd. 4 | -------------------------------------------------------------- 5 | local PING = 0x03FE 6 | local PING_REPLY = 0x03FD 7 | local VERBOSITY = 0x0400 8 | local VERBOSITY_REPLY = 0x0401 9 | 10 | local TAKE = 0x1200 11 | local TAKE_REPLY = 0x1201 12 | local TAKE_STATUS = 0x125F 13 | local TAKE_WITH_NODE_ID = 0x1255 14 | 15 | local ATTRIBUTE = 0x1202 16 | local ATTRIBUTE_REPLY = 0x1203 17 | 18 | local MONITOR_TAKE = 0x1204 19 | local MONITOR_TAKE_REPLY = 0x1205 20 | local DISCONNECT = 0x1206 21 | local DISCONNECT_REPLY = 0x1207 22 | 23 | local SALVO = 0x1208 24 | local SALVO_REPLY = 0x1209 25 | 26 | local STATUS = 0x120E 27 | local STATUS_REPLY = 0x120F 28 | 29 | local GET_MATRIX = 0x1216 30 | local GET_MATRIX_REPLY = 0x1217 31 | 32 | local GET_MATRIX_ATTRIBUTES = 0x121A 33 | local GET_MATRIX_ATTRIBUTES_REPLY = 0x121B 34 | 35 | local GET_MONITOR_MATRIX = 0x121E 36 | local GET_MONITOR_MATRIX_REPLY = 0x121F 37 | 38 | local SET_LOCK = 0x122E 39 | local SET_LOCK_REPLY = 0x122F 40 | local GET_LOCK = 0x1230 41 | local GET_LOCK_REPLY = 0x1231 42 | local CLEAR_LOCK = 0x1232 43 | local CLEAR_LOCK_REPLY = 0x1233 44 | 45 | local DEVICE_TABLE = 0x800D 46 | local DEVICE_TABLE_REPLY = 0x800E 47 | 48 | local codes = { 49 | [PING] = "PING", 50 | [PING_REPLY] = "PING_REPLY", 51 | 52 | [VERBOSITY] = "VERBOSITY", 53 | [VERBOSITY_REPLY] = "VERBOSITY_REPLY", 54 | [TAKE] = "TAKE", 55 | [TAKE_REPLY] = "TAKE_REPLY", 56 | [TAKE_STATUS] = "TAKE_STATUS", 57 | [TAKE_WITH_NODE_ID] = "TAKE_WITH_NODE_ID", 58 | 59 | [ATTRIBUTE] = "ATTRIBUTE", 60 | [ATTRIBUTE_REPLY] = "ATTRIBUTE_REPLY", 61 | [MONITOR_TAKE] = "MONITOR_TAKE", 62 | [MONITOR_TAKE_REPLY] = "MONITOR_TAKE_REPLY", 63 | [DISCONNECT] = "DISCONNECT", 64 | [DISCONNECT_REPLY] = "DISCONNECT_REPLY", 65 | [SALVO] = "SALVO", 66 | [SALVO_REPLY] = "SALVO_REPLY", 67 | [STATUS] = "STATUS", 68 | [STATUS_REPLY] = "STATUS_REPLY", 69 | 70 | [GET_MATRIX] = "GET_MATRIX", 71 | [GET_MATRIX_REPLY] = "GET_MATRIX_REPLY", 72 | [GET_MATRIX_ATTRIBUTES] = "GET_MATRIX_ATTRIBUTES", 73 | [GET_MATRIX_ATTRIBUTES_REPLY] = "GET_MATRIX_ATTRIBUTES_REPLY", 74 | [GET_MONITOR_MATRIX] = "GET_MONITOR_MATRIX", 75 | [GET_MONITOR_MATRIX_REPLY] = "GET_MONITOR_MATRIX_REPLY", 76 | 77 | [SET_LOCK] = "SET_LOCK", 78 | [SET_LOCK_REPLY] = "SET_LOCK_REPLY", 79 | [GET_LOCK] = "GET_LOCK", 80 | [GET_LOCK_REPLY] = "GET_LOCK_REPLY", 81 | [CLEAR_LOCK] = "CLEAR_LOCK", 82 | [CLEAR_LOCK_REPLY] = "CLEAR_LOCK_REPLY", 83 | 84 | [DEVICE_TABLE] = "DEVICE_TABLE", 85 | [DEVICE_TABLE_REPLY] = "DEVICE_TABLE_REPLY" 86 | } 87 | 88 | local r_rcp3a = Proto("rcp3a", "Utah RCP-3A protocol"); 89 | 90 | local f_opcode = ProtoField.uint16("rcp3a.op", "OpCode", base.HEX, codes); 91 | local f_nametype = ProtoField.uint8("rcp3a.nametype", "Name Type", base.HEX, 92 | { [0] = "Sources", [1] = "Destinations" }); 93 | 94 | local f_name = ProtoField.string("rcp3a.name", "Name"); 95 | 96 | local f_source = ProtoField.uint16("rcp3a.source", "Source"); 97 | local f_dest = ProtoField.uint16("rcp3a.dest", "Dest"); 98 | local f_salvo = ProtoField.uint16("rcp3a.salvo", "Salvo"); 99 | 100 | local f_index = ProtoField.uint16("rcp3a.index", "Index"); 101 | 102 | local f_levelmap = ProtoField.uint32("rcp3a.levelmap", "Level Bits"); 103 | local f_lockmap = ProtoField.uint32("rcp3a.lockmap", "Lock Bits"); 104 | local f_verbosity = ProtoField.uint16("rcp3a.verbosity", "Verbosity"); 105 | 106 | local f_sources = ProtoField.uint16("rcp3a.sources", "Sources"); 107 | local f_dests = ProtoField.uint16("rcp3a.dests", "Dests"); 108 | 109 | local f_interface = ProtoField.uint8("rcp3a.interface", "Interface"); 110 | local f_length = ProtoField.uint16("rcp3a.length", "Length"); 111 | local f_checksum = ProtoField.uint8("rcp3a.checksum", "Checksum"); 112 | 113 | local f_status = ProtoField.uint8("rcp3a.status", "Status"); 114 | 115 | local f_count = ProtoField.uint16("rcp3a.count", "Count"); 116 | local f_panel = ProtoField.uint16("rcp3a.panel", "Panel"); 117 | local f_clear = ProtoField.uint16("rcp3a.clear", "Clear"); 118 | 119 | r_rcp3a.fields = { 120 | f_opcode, f_source, f_dest, f_verbosity, f_interface, f_checksum, f_sources, 121 | f_clear, f_dests, f_length, f_name, f_count, f_status, f_salvo, f_nametype, 122 | f_index, f_lockmap, f_panel 123 | }; 124 | 125 | local ef_bad_checksum = ProtoExpert.new("rcp3a.checksum.expert", "Bad checksum", 126 | expert.group.MALFORMED, 127 | expert.severity.ERROR); 128 | 129 | r_rcp3a.experts = { ef_bad_checksum } 130 | 131 | function rangeByte(range, i) 132 | local r = range:range(i, 1) 133 | return r, r:uint() 134 | end 135 | 136 | function rangeWord(range, i) 137 | local r = range:range(i, 2) 138 | return r, r:uint() 139 | end 140 | 141 | function rangeLong(range, i) 142 | local r = range:range(i, 4) 143 | return r, r:uint() 144 | end 145 | 146 | function rangeString(range, i, len) 147 | local r = range:range(i, len) 148 | return r, "\"" .. r:stringz() .. "\"" 149 | end 150 | 151 | function processPacket(root, range) 152 | local tree = root:add(range, "RCP-3A") 153 | 154 | tree:add(f_interface, rangeByte(range, 0)) 155 | local r, op = rangeWord(range, 0) 156 | tree:add(f_opcode, r, op) 157 | tree:add(f_checksum, rangeByte(range, 2)) 158 | 159 | tree:add(f_length, rangeWord(range, 4)) 160 | 161 | local r, op = rangeWord(range, 0) 162 | 163 | if op == VERBOSITY_REPLY or op == VERBOSITY then 164 | tree:add(f_verbosity, rangeWord(range, 6)) 165 | elseif op == TAKE or op == TAKE_REPLY or op == TAKE_WITH_NODE_ID then 166 | tree:add(f_source, rangeWord(range, 6)) 167 | tree:add(f_dest, rangeWord(range, 8)) 168 | tree:add(f_levelmap, rangeLong(range, 10)) 169 | elseif op == TAKE_STATUS then 170 | tree:add(f_dest, rangeWord(range, 8)) 171 | tree:add(f_levelmap, rangeLong(range, 10)) 172 | tree:add(f_source, rangeWord(range, 14)) 173 | elseif op == DISCONNECT or op == DISCONNECT_REPLY then 174 | tree:add(f_dest, rangeWord(range, 6)) 175 | tree:add(f_levelmap, rangeLong(range, 8)) 176 | elseif op == SALVO or op == SALVO_REPLY then 177 | tree:add(f_salvo, rangeWord(range, 6)) 178 | elseif op == SET_LOCK or op == CLEAR_LOCK then 179 | tree:add(f_lockmap, rangeLong(range, 6)) 180 | tree:add(f_levelmap, rangeLong(range, 10)) 181 | tree:add(f_dest, rangeWord(range, 14)) 182 | tree:add(f_panel, rangeWord(range, 16)) 183 | elseif op == SET_LOCK_REPLY or op == CLEAR_LOCK_REPLY then 184 | tree:add(f_panel, rangeWord(range, 8)) 185 | tree:add(f_dest, rangeWord(range, 10)) 186 | tree:add(f_clear, rangeWord(range, 12)) 187 | tree:add(f_levelmap, rangeLong(range, 14)) 188 | tree:add(f_lockmap, rangeLong(range, 18)) 189 | elseif op == STATUS_REPLY then 190 | tree:add(f_sources, rangeWord(range, 6)) 191 | tree:add(f_dests, rangeWord(range, 8)) 192 | elseif op == DEVICE_TABLE then 193 | tree:add(f_nametype, rangeByte(range, 6)) 194 | elseif op == DEVICE_TABLE_REPLY then 195 | tree:add(f_nametype, rangeWord(range, 6)) 196 | tree:add(f_index, rangeWord(range, 8)) 197 | tree:add(f_name, rangeString(range, 10, 8)) 198 | elseif op == GET_MATRIX or op == GET_LOCK then 199 | tree:add(f_dest, rangeWord(range, 6)) 200 | tree:add(f_count, rangeWord(range, 8)) 201 | elseif op == GET_MATRIX_REPLY then 202 | tree:add(f_dest, rangeWord(range, 6)) 203 | tree:add(f_count, rangeWord(range, 8)) 204 | end 205 | end 206 | 207 | function r_rcp3a.dissector(tvb, pinfo, root_tree) 208 | pinfo.cols.protocol = "RCP-3A"; 209 | local p = 0 210 | while p < tvb:len() do 211 | local st, l = lookForPacket(tvb, root_tree, p) 212 | 213 | if l then 214 | p = st + l; 215 | else 216 | pinfo.desegment_offset = st 217 | pinfo.desegment_len = DESEGMENT_ONE_MORE_SEGMENT 218 | return 219 | end 220 | end 221 | end 222 | 223 | function lookForPacket(tvb, root_tree, startpos) 224 | local bytes = tvb:bytes(); 225 | local len = bytes:len() 226 | 227 | if startpos > (len - 6) then return startpos end 228 | 229 | local pktlen = bytes:get_index(startpos + 4) * 256 + 230 | bytes:get_index(startpos + 5) 231 | 232 | if startpos > (len - (6 + pktlen)) then return startpos end 233 | 234 | local range = tvb:range(startpos, 6 + pktlen) 235 | processPacket(root_tree, range) 236 | return startpos, range:len() 237 | end 238 | 239 | local tcp_encap_table = DissectorTable.get("tcp.port") 240 | tcp_encap_table:add(5001, r_rcp3a) 241 | -------------------------------------------------------------------------------- /wireshark.lua: -------------------------------------------------------------------------------- 1 | --- @module Wireshark 2 | --- Base Wireshark proto definitions. 3 | -- Annotations are EmmyLua format, as used by the Sumneko VSCode extension. 4 | -- https://emmylua.github.io/ 5 | -- https://github.com/sumneko/lua-language-server 6 | -- Ideally, we'd auto-create this file from the C++ sources in Wireshark 7 | DESEGMENT_ONE_MORE_SEGMENT = 1 8 | 9 | --- @class Proto 10 | --- A new protocol in Wireshark. Protocols have several uses. The main one is to dissect a protocol, but they can also be dummies used to register preferences for other purposes 11 | Proto = {} 12 | 13 | --- @param name string The name of the protocol. 14 | --- @param desc string A Long Text description of the protocol (usually lowercase). 15 | --- @return proto The newly created Proto object. 16 | function Proto.new(name, desc) end 17 | 18 | --- @class proto 19 | 20 | proto = {} 21 | 22 | --- The protocol’s dissector, a function you define. 23 | --- @param tree TreeItem 24 | function proto.dissector(tvb, pinfo, tree) end 25 | 26 | --- @param name string The name of the protocol. 27 | --- @param desc string A Long Text description of the protocol (usually lowercase). 28 | function proto:__call(name, desc) end 29 | 30 | ProtoField = {} 31 | ProtoExpert = {} 32 | 33 | --- @class base 34 | base = { NONE = 1, DEC = 2, HEX = 3, OCT = 4, DEC_HEX = 5, HEX_DEC = 6 } 35 | 36 | ftypes = { UINT8 = 1, UINT16 = 2, UINT24 = 3, UINT32 = 4, STRING = 5 } 37 | 38 | --- @class Tvb 39 | Tvb = {} 40 | 41 | --- @class TreeItem 42 | --- @class Pinfo 43 | 44 | --- @class dissectortable @returned by DissectorTable.get 45 | dissectortable = {} 46 | 47 | --- A refererence to a dissector, used to call a dissector against a packet or a part of it. 48 | Dissector = {} 49 | Struct = {} 50 | 51 | --- Obtains a dissector reference by name. 52 | --- @param name string name of dissector 53 | --- @return dissector @The Dissector reference if found, otherwise nil 54 | function Dissector.get(name) end 55 | 56 | --- Gets a Lua array table of all registered Dissector names. 57 | --- @return string[] The array table of registered dissector names. 58 | function Dissector.list() end 59 | 60 | --- @return string[] s converted from hex 61 | function Struct.fromhex(s) end 62 | 63 | --- @class dissector 64 | dissector = {} 65 | 66 | --- Calls a dissector against a given packet (or part of it). 67 | ---@param tvb Tvb The buffer to dissect 68 | ---@param pinfo Pinfo The packet info 69 | ---@param tree TreeItem The tree on which to add the protocol items. 70 | ---@return number Number of bytes dissected. Note that some dissectors always return number of bytes in incoming buffer, so be aware. 71 | function dissector:call(tvb, pinfo, tree) end 72 | 73 | --- Calls a dissector against a given packet (or part of it). 74 | ---@param tvb Tvb The buffer to dissect 75 | ---@param pinfo Pinfo The packet info 76 | ---@param tree TreeItem The tree on which to add the protocol items. 77 | function dissector:__call(tvb, pinfo, tree) end 78 | 79 | ---Gets the Dissector’s protocol short name. 80 | ---@return string @A string of the protocol’s short name. 81 | function dissector:__tostring() end 82 | 83 | --- A table of subdissectors of a particular protocol 84 | DissectorTable = {} 85 | 86 | ---Creates a new DissectorTable for your dissector’s use. 87 | --- @param tablename string The short name of the table. Use lower-case alphanumeric, dot, and/or underscores (e.g., "ansi_map.tele_id" or "udp.port"). 88 | --- @param uiname string optional: The name of the table in the user interface. Defaults to the name given in tablename, but can be any string. 89 | --- @param type number One of ftypes.UINT8, ftypes.UINT16, ftypes.UINT24, ftypes.UINT32, or ftypes.STRING. Defaults to ftypes.UINT32 90 | --- @param base number One of base.NONE, base.DEC, base.HEX, base.OCT, base.DEC_HEX or base.HEX_DEC. Defaults to base.DEC. 91 | --- @param proto Proto The Proto object that uses this dissector table. 92 | --- @return dissectortable @The newly created DissectorTable. 93 | function DissectorTable.new(tablename, uiname, type, base, proto) end 94 | 95 | --- Gets a Lua array table of all DissectorTable names - i.e., the string names you can use for the first argument to DissectorTable.get() 96 | --- @return string[] @The array table of registered DissectorTable names 97 | function DissectorTable.list() end 98 | 99 | --- Gets a Lua array table of all heuristic list names - i.e., the string names you can use for the first argument in Proto:register_heuristic() 100 | --- @return string[] @The array table of registered heuristic list names 101 | function DissectorTable.heuristic_list() end 102 | 103 | ---Try all the dissectors in a given heuristic dissector table 104 | ---@param listname string The name of the heuristic dissector. 105 | ---@param tvb Tvb The buffer to dissect 106 | ---@param pinfo Pinfo The packet info 107 | ---@param tree TreeItem The tree on which to add the protocol items 108 | function DissectorTable.try_heuristics(listname, tvb, pinfo, tree) end 109 | 110 | --- Obtain a reference to an existing dissector table. 111 | --- @param tablename string The short name of the table 112 | --- @return dissectortable @The DissectorTable reference if found, otherwise nil. 113 | function DissectorTable.get(tablename) end 114 | 115 | --- Add a Proto with a dissector function or a Dissector object to the dissector table. 116 | --- @param pattern number|string The pattern to match (either an integer, a integer range or a string depending on the table’s type) 117 | --- @param dissector Proto|dissector The dissector to add (either a Proto or a Dissector) 118 | function dissectortable:add(pattern, dissector) end 119 | 120 | --- Clear all existing dissectors from a table and add a new dissector or a range of new dissectors. 121 | --- @param pattern number|string The pattern to match (either an integer, a integer range or a string depending on the table’s type) 122 | --- @param dissector Proto|dissector The dissector to add (either a Proto or a Dissector) 123 | function dissectortable:set(pattern, dissector) end 124 | 125 | --- Remove a dissector or a range of dissectors from a table. 126 | --- @param pattern number|string The pattern to match (either an integer, a integer range or a string depending on the table’s type) 127 | --- @param dissector Proto|dissector The dissector to remove (either a Proto or a Dissector). 128 | function dissectortable:remove(pattern, dissector) end 129 | 130 | ---Remove all dissectors from a table. 131 | function dissectortable:remove_all() end 132 | 133 | --- Try to call a dissector from a table. 134 | --- @param pattern string|number The pattern to be matched (either an integer or a string depending on the table’s type) 135 | --- @param tvb Tvb The Tvb to dissect 136 | --- @param pinfo Pinfo The packet info 137 | --- @param tree TreeItem The tree on which to add the protocol items 138 | --- @return number Number of bytes dissected. Note that some dissectors always return number of bytes in incoming buffer, so be aware 139 | function dissectortable:try(pattern, tvb, pinfo, tree) end 140 | 141 | --- Try to obtain a dissector from a table 142 | --- @param pattern number|string The pattern to match (either an integer, a integer range or a string depending on the table’s type) 143 | --- @return dissector The Dissector handle if found, otherwise nil 144 | function dissectortable:get_dissector(pattern) end 145 | 146 | ---Gets some debug information about the DissectorTable. 147 | ---@return string A string of debug information about the DissectorTable. 148 | function dissectortable:__tostring() end 149 | 150 | expert = {} 151 | 152 | --- Add a directory to the head of the package search path 153 | --- @param path string directory to add 154 | function package.prepend_path(path) end 155 | --------------------------------------------------------------------------------