1 /*---------------------------------------------------------------------------*
2 
3   Copyright (C) Nintendo.  All rights reserved.
4 
5   These coded instructions, statements, and computer programs contain
6   proprietary information of Nintendo of America Inc. and/or Nintendo
7   Company Ltd., and are protected by Federal copyright law.  They may
8   not be disclosed to third parties or copied or duplicated in any form,
9   in whole or in part, without the prior written consent of Nintendo.
10 
11  *---------------------------------------------------------------------------*/
12 using System;
13 using System.Collections.Generic;
14 using System.IO;
15 using System.Net;
16 using System.Net.Sockets;
17 using System.Net.NetworkInformation;
18 using System.Text;
19 
20 
21 namespace Nintendo.SDSG
22 {
23     public class NetworkInterfaceExplorer
24     {
25         public string ComputerName { get; private set; }
26         public string DomainName { get; private set; }
27         public IList<NetworkInterface> ActiveNICs { get; private set; }
28         public bool ConnectedToTheEther { get; private set; }
29 
30 
ToString()31         public override string ToString()
32         {
33             StringBuilder sb = new StringBuilder();
34             foreach (NetworkInterface nic in ActiveNICs)
35             {
36                 sb.AppendLine( GetIPv4Address(nic).ToString() );
37             }
38             return sb.ToString();
39         }
40 
NetworkInterfaceExplorer()41         public NetworkInterfaceExplorer()
42         {
43             ReScan();
44         }
45 
ReScan()46         public void ReScan()
47         {
48             IPGlobalProperties overall_props = IPGlobalProperties.GetIPGlobalProperties();
49             ComputerName = overall_props.HostName;
50             DomainName = overall_props.DomainName;
51 
52             ConnectedToTheEther = NetworkInterface.GetIsNetworkAvailable();
53             ActiveNICs = _get_active_ethernet_adapters();
54         }
55 
56 
GetIPv4Address(NetworkInterface nic)57         public IPAddress GetIPv4Address(NetworkInterface nic)
58         {
59             foreach (var single_point_address in nic.GetIPProperties().UnicastAddresses)
60             {
61                 if (single_point_address.Address.AddressFamily == AddressFamily.InterNetwork)
62                 {
63                     return single_point_address.Address;
64                 }
65             }
66             return IPAddress.None;
67         }
68 
_get_active_ethernet_adapters()69         private IList<NetworkInterface> _get_active_ethernet_adapters()
70         {
71             List<NetworkInterface> rc = new List<NetworkInterface>();
72 
73             NetworkInterface[] all_network_cards = NetworkInterface.GetAllNetworkInterfaces();
74             foreach (var network_card in all_network_cards)
75             {
76 
77                 if (network_card.OperationalStatus != OperationalStatus.Up)
78                 {
79                     continue;
80                 }
81 
82 
83                 if (network_card.NetworkInterfaceType == NetworkInterfaceType.Loopback) continue;
84                 rc.Add(network_card);
85             }
86 
87             return rc;
88         }
89 
GetPrettyMAC(byte[] mac_address)90         public static string GetPrettyMAC(byte[] mac_address)
91         {
92             return GetPrettyMAC(mac_address, 0);
93         }
94 
GetPrettyMAC(byte[] mac_address, int starting_index_in_buffer)95         public static string GetPrettyMAC(byte[] mac_address, int starting_index_in_buffer)
96         {
97             StringBuilder sb = new StringBuilder();
98             sb.AppendFormat("{0:x2}:{0:x2}:{0:x2}:{0:x2}:{0:x2}:{0:x2}",
99                 mac_address[starting_index_in_buffer+0],
100                 mac_address[starting_index_in_buffer+1],
101                 mac_address[starting_index_in_buffer+2],
102                 mac_address[starting_index_in_buffer+3],
103                 mac_address[starting_index_in_buffer+4],
104                 mac_address[starting_index_in_buffer+5]);
105             return sb.ToString();
106         }
107 
108     }
109 
110     public class MionIdentifier
111     {
112         public string Name {get; private set; }
113         public string FieldProgrammableGateArrayVersion { get; private set; }
114         public string FirmwareVersion { get; private set; }
115         public string MACAddress { get; private set; }
116         public byte Flags { get; private set; }
117         public IPEndPoint NetworkAddress;
118 
119 
120         private const int k_flags_idx = 0;
121         private const int k_mac_addr_idx = 1;
122         private const int k_name_len_idx = 7;
123         private const int k_fpga_idx = 8;
124         private const int k_fw_ver_idx = 12;
125         private const int k_machine_name_idx = 16;
126 
TryCreate(byte[] broadcast_reciept, IPEndPoint location)127         internal static MionIdentifier TryCreate(byte[] broadcast_reciept, IPEndPoint location)
128         {
129             /*
130             BYTE bFlags;								// 0
131             BYTE MACAddr[6];							// 1
132             BYTE bMachineNameLength;					// 7
133             BYTE FPGAVersion1;							// 8
134             BYTE FPGAVersion2;							// 9
135             BYTE FPGAVersion3;							// 10
136             BYTE FPGAVersion4;							// 11
137             BYTE FWVersion1;							// 12
138             BYTE FWVersion2;							// 13
139             BYTE FWVersion3;							// 14
140             BYTE FWVersion4;							// 15
141             char szMachineName[MAX_PATH];				// 16
142             */
143 
144 
145             if (broadcast_reciept[0] == (byte)MionUdp.MionCmdByte.Acknowledge)
146             {
147                 return new MionIdentifier(broadcast_reciept, location);
148             }
149 
150             return null;
151 
152         }
153 
154 
MionIdentifier(byte[] broadcast_reciept, IPEndPoint location)155         private  MionIdentifier(byte[] broadcast_reciept, IPEndPoint location)
156         {
157             Flags = broadcast_reciept[k_flags_idx];
158             MACAddress = NetworkInterfaceExplorer.GetPrettyMAC(broadcast_reciept, k_mac_addr_idx);
159             Name = ASCIIEncoding.ASCII.GetString(broadcast_reciept, k_machine_name_idx, broadcast_reciept[k_name_len_idx]);
160             NetworkAddress = location;
161 
162             FieldProgrammableGateArrayVersion = String.Format("{0}.{1}.{2}.{3}", broadcast_reciept[k_fpga_idx + 0],
163                 broadcast_reciept[k_fpga_idx + 1], broadcast_reciept[k_fpga_idx + 2], broadcast_reciept[k_fpga_idx + 3]);
164 
165             FirmwareVersion = String.Format("{0}.{1}.{2}.{3}", broadcast_reciept[k_fw_ver_idx + 0],
166                 broadcast_reciept[k_fw_ver_idx + 1], broadcast_reciept[k_fw_ver_idx + 2], broadcast_reciept[k_fw_ver_idx + 3]);
167         }
168 
169 
ToString()170         public override string ToString()
171         {
172             StringBuilder sb = new StringBuilder();
173             sb.AppendFormat("{0,-16}: {3,-25} - FW {1} - FPGA {2}", NetworkAddress.Address, FirmwareVersion, FieldProgrammableGateArrayVersion, Name);
174             return sb.ToString();
175         }
176 
177     }
178 
179 
180     public class LocatedMions
181     {
LocatedMions()182         internal LocatedMions() { }
183 
184         public NetworkInterfaceExplorer NetInfo { get; internal set; }
185         public IList<MionIdentifier> Mions { get; internal set; }
186     }
187 
188 
189     public class NetworkTuple
190     {
191         public byte[] Item1;
192         public IPEndPoint Item2;
193 
NetworkTuple(byte[] bytes, IPEndPoint endpoint)194         public NetworkTuple(byte[] bytes, IPEndPoint endpoint)
195         {
196             Item1 = bytes;
197             Item2 = endpoint;
198         }
199     }
200 
201     public class MionUdp
202     {
203         const string k_mion_string = "MULTI_I/O_NETWORK_BOARD";
204         const ushort k_mion_ctrl_port = 7974;
205         const ushort k_mion_char_port = 7975;
206         const ushort k_mion_bulk_port = 7976;
207 
208         internal enum MionCmdByte
209         {
210             //Search = 0x3f,
211             //Broadcast = 0x21
212             AnnounceYourselves = 0x2a,
213             Acknowledge = 0x20,
214         }
215 
216 
_create_buffer_for_announce_yourselves()217         private static byte[] _create_buffer_for_announce_yourselves()
218         {
219             byte[] rc = new byte[25];
220             rc[0] = (byte)MionCmdByte.AnnounceYourselves;
221 
222             System.Text.ASCIIEncoding.ASCII.GetBytes(k_mion_string, 0, k_mion_string.Length, rc, 1);
223             return (rc);
224         }
225 
226 
227 
ScanLocalSubnetForMIONs()228         public static LocatedMions ScanLocalSubnetForMIONs()
229         {
230             NetworkInterfaceExplorer looker = new NetworkInterfaceExplorer();
231 
232             LocatedMions rc = new LocatedMions();
233             rc.NetInfo = looker;
234 
235             if (looker.ConnectedToTheEther == false)
236             {
237                 return rc;
238             }
239 
240             IPAddress local_address = looker.GetIPv4Address(looker.ActiveNICs[0]);
241             IPAddress broadcast_address;
242 
243             {
244                 string str_local_address = local_address.ToString();
245                 string str_chopped_broadcast = str_local_address.Remove(str_local_address.LastIndexOf('.'));
246                 string str_final_broadcast = str_chopped_broadcast + ".255";
247                 broadcast_address = IPAddress.Parse(str_final_broadcast);
248             }
249 
250 
251             IPEndPoint my_local_portcombo = new IPEndPoint(local_address, k_mion_ctrl_port);
252             IPEndPoint target_destination_portcombo = new IPEndPoint(broadcast_address, k_mion_ctrl_port);
253 
254             byte[] msg_to_broadcast = _create_buffer_for_announce_yourselves();
255 
256             Socket skBroadcaster = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
257 
258             skBroadcaster.Bind(my_local_portcombo);
259             skBroadcaster.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true);
260 
261             rc.Mions = new List<MionIdentifier>();
262 
263             DateTime current_time = DateTime.Now;
264             DateTime target_time = current_time.AddMilliseconds(10);
265 
266             skBroadcaster.SendTo(msg_to_broadcast, target_destination_portcombo);
267 
268             List<NetworkTuple> replies = new List<NetworkTuple>();
269 
270             while (DateTime.Now < target_time)
271             {
272                 int avail = skBroadcaster.Available;
273                 if (avail > 0)
274                 {
275                     EndPoint mion_portcombo = new IPEndPoint(IPAddress.Any, 0);
276 
277                     byte[] mion_incoming_message = new byte[avail];
278                     skBroadcaster.ReceiveFrom(mion_incoming_message, ref mion_portcombo);
279 
280                     replies.Add(new NetworkTuple(mion_incoming_message, (IPEndPoint)mion_portcombo));
281                 }
282 
283             }
284 
285             for (int i = 0; i < replies.Count; i++)
286             {
287                 MionIdentifier a_mion = MionIdentifier.TryCreate(replies[i].Item1, replies[i].Item2);
288                 if (a_mion != null)
289                     rc.Mions.Add(a_mion);
290             }
291 
292             skBroadcaster.Close();
293             return rc;
294         }
295 
296     }
297 
298 
299 
300 
301 /*
302 #pragma once
303 #include <windows.h>
304 
305 #define MION_CONTROL_PORT       7974
306 
307 #define MION_KEYWORD            "MULTI_I/O_NETWORK_BOARD"
308 #define MION_SEARCH             (BYTE)0x3f
309 #define MION_ENUMERATE          (BYTE)0x2a
310 #define MION_ACK                (BYTE)0x20
311 #define MION_BCAST              (BYTE)0x21
312 #define MION_SEARCH_TIMEOUT     20000
313 
314 #define FIRST_BYTE(n)           (UINT32)(n&0x000000FF)
315 #define SECOND_BYTE(n)          (UINT32)((n&0x0000FF00) >> 8)
316 
317 #pragma pack(push, 1)
318 typedef struct _mionsearchbridgeRequest
319 {
320     BYTE bFlags;
321     char keyword[24];
322     BYTE bMachineNameLength;
323     char szMachineName[MAX_PATH];
324 }MION_SEARCH_REQUEST, *PMION_SEARCH_REQUEST;
325 
326 typedef struct _mionglobalsearchbridgeRequest
327 {
328     BYTE bFlags;
329     char keyword[24];
330 }MION_GLOBAL_SEARCH_REQUEST, *PMION_GLOBAL_SEARCH_REQUEST;
331 
332 typedef struct _mionsearchbridgeReply
333 {
334     BYTE bFlags;
335     BYTE MACAddr[6];
336     BYTE bMachineNameLength;
337     BYTE FPGAVersion1;
338     BYTE FPGAVersion2;
339     BYTE FPGAVersion3;
340     BYTE FPGAVersion4;
341     BYTE FWVersion1;
342     BYTE FWVersion2;
343     BYTE FWVersion3;
344     BYTE FWVersion4;
345     char szMachineName[MAX_PATH];
346 }MION_SEARCH_REPLY, *PMION_SEARCH_REPLY;
347 #pragma pack(pop)
348 
349 */
350 
351 
352     /*
353     Table 4-25 List of Settings
354     Item Name
355         Description
356     Machine Name
357         Name consisting of ASCII characters.
358         (Up to 256 characters, including the terminator.)
359     MAC Address
360         MAC address allocated to MION.
361         (Reference only.)
362     Language Setting
363         Specify Automatic, Japanese, or English.
364         If you specify Automatic, it references the header information in the browser.
365     Settings for automatically getting IP address
366         Toggle use of DHCP / Auto IP UPnP [1]
367     IP Address
368         Manually-set IP address.
369     Subnet Mask
370         Manually-set subnet mask.
371     Default Gateway
372         Manually-set IP address of default gateway.
373     Settings to automatically get DNS server address
374         Toggle use of DHCP.
375     Primary DNS Server
376         Manually-set IP address of primary DNS server.
377     Secondary DNS Server
378         Manually-set IP address of secondary DNS server.
379     Ethernet Frame Size
380         Select from 1500 bytes, 3000 bytes, 4000 bytes, 5000 bytes, 6000 bytes, 7000 bytes, 8000 bytes, and 9700 bytes.[2]
381     Default Host PC IP Address
382         IP address of PC that serves as ATAPI emulator host.
383     ATAPI Emulator Port Number
384         Sets port number to use for communication with ATAPI Emulator interface.
385         (Default: 7974)
386     FIFO1 Port Number
387         Sets port number to use for communication with FIFO1.
388         (Default: 7975)
389     FIFO2 Port Number
390         Sets port number to use for communication with FIFO2.
391         (Default: 7976)
392     Size of Buffer for FIFO1 Interface
393         Select from 4KB, 32KB, 128KB, 256KB, 512KB, 1MB, 2MB, and 4MB.
394         (Default: 4KB)
395     Size of Buffer for FIFO2 Interface
396         Select from 128KB, 256KB, 512KB, 1MB, 2MB, 4MB, 8MB, and 16MB.
397         (Default: 128KB)
398     Hard Disk Bank Size Setting
399         Select from 2GB, 5GB, 10GB, 12GB, 15GB, 18GB, 21GB, and 25GB.
400         (Default: 25GB)
401     Current Bank Number of Hard Disk
402         Bank number of image used in H-reader mode.
403         Bank 0 uses the host PC's hard disk image.
404     Driver Parameters in H-Reader Mode
405         Product revision level.
406         Header code
407         Device code
408         Release date
409     Communication Channel Setting
410         Setting that allocates the various communication channels to the CAFE interface(s).
411     Driver Timing Emulation Setting
412         Toggles use of driver timing emulation.
413     */
414 
415 }
416 
417