1 //
2 // Copyright (c) 2010-2024 Antmicro
3 //
4 // This file is licensed under the MIT License.
5 // Full license text is available in 'licenses/MIT.txt'.
6 //
7 using System;
8 using System.IO;
9 using Antmicro.Renode;
10 using Antmicro.Renode.Core;
11 using Antmicro.Renode.Exceptions;
12 using Antmicro.Renode.Peripherals.Network;
13 using Antmicro.Renode.Peripherals.Wireless;
14 using Antmicro.Renode.Tools.Network;
15 using Antmicro.Renode.Utilities;
16 
17 namespace Antmicro.Renode.Plugins.WiresharkPlugin
18 {
19     public static class INetworkLogExtensions
20     {
CreateWiresharkForBLE(this Emulation emulation, string name)21         public static void CreateWiresharkForBLE(this Emulation emulation, string name)
22         {
23             CreateBLEConfiguredWireshark(emulation, name);
24         }
25 
CreateWiresharkForIEEE802_15_4(this Emulation emulation, string name)26         public static void CreateWiresharkForIEEE802_15_4(this Emulation emulation, string name)
27         {
28             CreateIEEE802_15_4ConfiguredWireshark(emulation, name);
29         }
30 
CreateWiresharkForCAN(this Emulation emulation, string name)31         public static void CreateWiresharkForCAN(this Emulation emulation, string name)
32         {
33             CreateCANConfiguredWireshark(emulation, name);
34         }
35 
CreateWiresharkForEthernet(this Emulation emulation, string name)36         public static void CreateWiresharkForEthernet(this Emulation emulation, string name)
37         {
38             CreateEthernetConfiguredWireshark(emulation, name);
39         }
40 
41         public static void LogToWireshark<T>(this Emulation emulation, INetworkLog<T> reporter, T iface) where T : INetworkInterface
42         {
43             GetConfiguredWireshark(emulation, reporter as INetworkLog<INetworkInterface>, GetName(reporter, iface)).LogToWireshark(reporter as INetworkLog<INetworkInterface>, iface);
44         }
45 
LogToWireshark(this Emulation emulation, INetworkLog<INetworkInterface> reporter)46         public static void LogToWireshark(this Emulation emulation, INetworkLog<INetworkInterface> reporter)
47         {
48             GetConfiguredWireshark(emulation, reporter, GetName(reporter)).LogToWireshark(reporter);
49         }
50 
LogBLETraffic(this Emulation emulation)51         public static void LogBLETraffic(this Emulation emulation)
52         {
53             var result = CreateBLEConfiguredWireshark(emulation, BLELogName);
54             foreach(var BLE in emulation.ExternalsManager.GetExternalsOfType<BLEMedium>())
55             {
56                 result.LogToWireshark((INetworkLog<INetworkInterface>)BLE);
57             }
58 
59             // We detach the event before reattaching it to ensure that we are connected only once.
60             // This manouver allows us not to use an additional variable, which would be difficult
61             // to reset, as it is a static class.
62             emulation.ExternalsManager.ExternalsChanged -= AddExternal;
63             emulation.ExternalsManager.ExternalsChanged += AddExternal;
64         }
65 
LogIEEE802_15_4Traffic(this Emulation emulation)66         public static void LogIEEE802_15_4Traffic(this Emulation emulation)
67         {
68             var result = CreateIEEE802_15_4ConfiguredWireshark(emulation, IEEE802_15_4LogName);
69             foreach(var IEEE802_15_4 in emulation.ExternalsManager.GetExternalsOfType<IEEE802_15_4Medium>())
70             {
71                 result.LogToWireshark((INetworkLog<INetworkInterface>)IEEE802_15_4);
72             }
73 
74             // We detach the event before reattaching it to ensure that we are connected only once.
75             // This manouver allows us not to use an additional variable, which would be difficult
76             // to reset, as it is a static class.
77             emulation.ExternalsManager.ExternalsChanged -= AddExternal;
78             emulation.ExternalsManager.ExternalsChanged += AddExternal;
79         }
80 
LogEthernetTraffic(this Emulation emulation)81         public static void LogEthernetTraffic(this Emulation emulation)
82         {
83             var result = CreateEthernetConfiguredWireshark(emulation, EthernetLogName);
84             foreach(var ethernet in emulation.ExternalsManager.GetExternalsOfType<Switch>())
85             {
86                 result.LogToWireshark((INetworkLog<INetworkInterface>)ethernet);
87             }
88 
89             // We detach the event before reattaching it to ensure that we are connected only once.
90             // This manouver allows us not to use an additional variable, which would be difficult
91             // to reset, as it is a static class.
92             emulation.ExternalsManager.ExternalsChanged -= AddExternal;
93             emulation.ExternalsManager.ExternalsChanged += AddExternal;
94         }
95 
LogCANTraffic(this Emulation emulation)96         public static void LogCANTraffic(this Emulation emulation)
97         {
98             var result = CreateCANConfiguredWireshark(emulation, CANLogName);
99             foreach(var hub in emulation.ExternalsManager.GetExternalsOfType<CANHub>())
100             {
101                 result.LogToWireshark((INetworkLog<INetworkInterface>)hub);
102             }
103 
104             // We detach the event before reattaching it to ensure that we are connected only once.
105             // This manouver allows us not to use an additional variable, which would be difficult
106             // to reset, as it is a static class.
107             emulation.ExternalsManager.ExternalsChanged -= AddExternal;
108             emulation.ExternalsManager.ExternalsChanged += AddExternal;
109         }
110 
AddExternal(ExternalsManager.ExternalsChangedEventArgs reporter)111         private static void AddExternal(ExternalsManager.ExternalsChangedEventArgs reporter)
112         {
113             var external = reporter.External;
114             var BLEResult = (Wireshark)EmulationManager.Instance.CurrentEmulation.HostMachine.TryGetByName(BLELogName, out var BLEWiresharkFound);
115             var IEEE802_15_4Result = (Wireshark)EmulationManager.Instance.CurrentEmulation.HostMachine.TryGetByName(IEEE802_15_4LogName, out var IEEE802_15_4WiresharkFound);
116             var ethernetResult = (Wireshark)EmulationManager.Instance.CurrentEmulation.HostMachine.TryGetByName(EthernetLogName, out var ethernetWiresharkFound);
117             var CANResult = (Wireshark)EmulationManager.Instance.CurrentEmulation.HostMachine.TryGetByName(CANLogName, out var CANWiresharkFound);
118 
119             if(IEEE802_15_4WiresharkFound && external is IEEE802_15_4Medium)
120             {
121                 IEEE802_15_4Result.LogToWireshark((IEEE802_15_4Medium)external);
122             }
123 
124             if(BLEWiresharkFound && external is BLEMedium)
125             {
126                 BLEResult.LogToWireshark((BLEMedium)external);
127             }
128 
129             if(ethernetWiresharkFound && external is Switch)
130             {
131                 ethernetResult.LogToWireshark((Switch)external);
132             }
133 
134             if(CANWiresharkFound && external is CANHub)
135             {
136                 CANResult.LogToWireshark((CANHub)external);
137             }
138         }
139 
GetConfiguredWireshark(Emulation emulation, INetworkLog<INetworkInterface> reporter, string hostName)140         private static Wireshark GetConfiguredWireshark(Emulation emulation, INetworkLog<INetworkInterface> reporter, string hostName)
141         {
142             if(reporter is IEEE802_15_4Medium)
143             {
144                 return CreateIEEE802_15_4ConfiguredWireshark(emulation, hostName);
145             }
146             else if(reporter is BLEMedium)
147             {
148                 return CreateBLEConfiguredWireshark(emulation, hostName);
149             }
150             else if(reporter is Switch)
151             {
152                 return CreateEthernetConfiguredWireshark(emulation, hostName);
153             }
154             else if(reporter is CANHub)
155             {
156                 return CreateCANConfiguredWireshark(emulation, hostName);
157             }
158             else
159             {
160                 throw new ArgumentException("Expected CANHub, Switch, BLEMedium or IEEE802_15_4Medium.");
161             }
162         }
163 
CreateBLEConfiguredWireshark(Emulation emulation, string name)164         private static Wireshark CreateBLEConfiguredWireshark(Emulation emulation, string name)
165         {
166             var result = (Wireshark)EmulationManager.Instance.CurrentEmulation.HostMachine.TryGetByName(name, out var BLEWiresharkFound);
167 
168             if(BLEWiresharkFound)
169             {
170                 return result;
171             }
172 
173             return CreateWireshark(emulation, name, LinkLayer.Bluetooth_LE);
174         }
175 
CreateIEEE802_15_4ConfiguredWireshark(Emulation emulation, string name)176         private static Wireshark CreateIEEE802_15_4ConfiguredWireshark(Emulation emulation, string name)
177         {
178             var result = (Wireshark)EmulationManager.Instance.CurrentEmulation.HostMachine.TryGetByName(name, out var wirelessWiresharkFound);
179 
180             if(wirelessWiresharkFound)
181             {
182                 return result;
183             }
184 
185             return CreateWireshark(emulation, name, LinkLayer.IEEE802_15_4);
186         }
187 
CreateEthernetConfiguredWireshark(Emulation emulation, string name)188         private static Wireshark CreateEthernetConfiguredWireshark(Emulation emulation, string name)
189         {
190             var result = (Wireshark)EmulationManager.Instance.CurrentEmulation.HostMachine.TryGetByName(name, out var ethernetWiresharkFound);
191 
192             if(ethernetWiresharkFound)
193             {
194                 return result;
195             }
196 
197             return CreateWireshark(emulation, name, LinkLayer.Ethernet);
198         }
199 
CreateCANConfiguredWireshark(Emulation emulation, string name)200         private static Wireshark CreateCANConfiguredWireshark(Emulation emulation, string name)
201         {
202             var result = (Wireshark)EmulationManager.Instance.CurrentEmulation.HostMachine.TryGetByName(name, out var CANWiresharkFound);
203 
204             if(CANWiresharkFound)
205             {
206                 return result;
207             }
208 
209             return CreateWireshark(emulation, name, LinkLayer.CAN);
210         }
211 
CreateWireshark(this Emulation emulation, string name, LinkLayer layer)212         private static Wireshark CreateWireshark(this Emulation emulation, string name, LinkLayer layer)
213         {
214             Wireshark result;
215             var wiresharkPath = ConfigurationManager.Instance.Get("wireshark", "wireshark-path", WiresharkPath);
216             if(File.Exists(wiresharkPath))
217             {
218                 result = new Wireshark(name, layer, wiresharkPath);
219             }
220             else
221             {
222                 throw new RecoverableException($"Wireshark is not installed or is not available in the default path. Please adjust the path in the Renode configuration file ({ConfigurationManager.Instance.FilePath}).");
223             }
224 
225             emulation.HostMachine.AddHostMachineElement(result, name);
226             return result;
227         }
228 
GetName(IEmulationElement element, IEmulationElement nextElement = null)229         private static string GetName(IEmulationElement element, IEmulationElement nextElement = null)
230         {
231             string elementName;
232             var emulation = EmulationManager.Instance.CurrentEmulation;
233             emulation.TryGetEmulationElementName(element, out elementName);
234 
235             if(nextElement != null)
236             {
237                 string nextElementName;
238                 emulation.TryGetEmulationElementName(nextElement, out nextElementName);
239                 nextElementName = nextElementName.Replace(':', '-').Replace('.', '-');
240                 return "{0}-{1}-{2}".FormatWith(WiresharkExternalPrefix, elementName, nextElementName);
241             }
242 
243             return "{0}-{1}".FormatWith(WiresharkExternalPrefix, elementName);
244         }
245 
246         private const string WiresharkExternalPrefix = "wireshark";
247         private const string BLELogName = WiresharkExternalPrefix + "-" + "allBLETraffic";
248         private const string IEEE802_15_4LogName = WiresharkExternalPrefix + "-" + "allIEEE802_15_4Traffic";
249         private const string EthernetLogName = WiresharkExternalPrefix + "-" + "allEthernetTraffic";
250         private const string CANLogName = WiresharkExternalPrefix + "-" + "allCANTraffic";
251 #if PLATFORM_WINDOWS
252         private const string WiresharkPath = @"c:\Program Files\Wireshark\Wireshark.exe";
253 #elif PLATFORM_OSX
254         private const string WiresharkPath = "/Applications/Wireshark.app/Contents/MacOS/Wireshark";
255 #else
256         private const string WiresharkPath = "/usr/bin/wireshark";
257 #endif
258     }
259 }
260