having trouble returning a best possible interface from a set of routing entries - interface

so i am trying to return a best possible matching interface from routing entries. However, it is not exactly working the way i want it to. I got 5 out 6 values returned the way should be but I am pretty sure I have a million entries in a routing table my algorithm would not work.
I am using Binary Search to solve this problem. But, for example, the interface that i want to return has a ipaddress which is smaller than the ipaddress i am passing as an argument, then the binary search algorithm does not work. the structure looks like this:
struct routeEntry_t
{
uint32_t ipAddr;
uint32_t netMask;
int interface;
};
routeEntry_t routing_table[100000];
let's say the routing table looks like this:
{ 0x00000000, 0x00000000, 1 }, // [0]
{ 0x0A000000, 0xFF000000, 2 }, // [1]
{ 0x0A010000, 0xFFFF0000, 10 }, // [2]
{ 0x0D010100, 0xFFFFFF00, 4 }, // [3]
{ 0x0B100000, 0xFFFF0000, 3 }, // [4]
{ 0x0A010101, 0xFFFFFFFF, 5 }, // [5]
Example input/output:
Regular search
Input: 0x0D010101 Output: 4 (entry [3])
Input: 0x0B100505 Output: 3 (entry [4])
To find an arbitrary address, it should go to the default interface.
Input: 0x0F0F0F0F Output: 1 (entry [0])
To find an address that matches multiple entries, take the best-match.
Input: 0x0A010200 Output: 10 (entry [2])
Input: 0x0A050001 Output: 2 (entry [1])
Input: 0x0A010101 Output: 5 (entry [5])
But my output looks like 2, 3, 1, 10, 1, 5. I don't understand where I am messing things up. Could you please explain where I am doing wrong? any help would be great. Thanks in advance. However this is what my algorithm looks like (assuming the entries are sorted):
int interface(uint32_t ipAddr)
{
int start = 0;
int end = SIZE-1;
int mid = 0;
vector<int> matched_entries;
vector<int>::iterator it;
matched_entries.reserve(SIZE);
it = matched_entries.begin();
if (start > end)
return -1;
while (start <= end)
{
mid = start + ((end-start)/2);
if (routing_table[mid].ipAddr == ipAddr)
return routing_table[mid].interface;
else if (routing_table[mid].ipAddr > ipAddr)
{
uint32_t result = routing_table[mid].netMask & ipAddr;
if (result == routing_table[mid].ipAddr)
{
matched_entries.push_back(mid);
}
end = mid-1;
}
else
{
uint32_t result = routing_table[mid].netMask & ipAddr;
if (result == routing_table[mid].ipAddr)
{
matched_entries.insert(it,mid);
}
start = mid+1;
}
}
int matched_ip = matched_entries.back();
if (routing_table[matched_ip].netMask & ipAddr)
return routing_table[matched_ip].interface;
else
return routing_table[0].interface;
}

The "right" interface is the entry with the most specific netmask whose IP address is on the same subnet as your input.
Let's look at what netmasks are, and how they work, in more detail.
Notation
Although netmasks are usually written in dotted-decimal or hex notation, the binary representation of an IPv4 netmask is always 32 bits; that is, it's exactly the same length as an IP address. The netmask always starts with zero or more 1 bits and is padded with 0 bits to complete its 32-bit length. When a netmask is applied to an IP address, they're "lined up" bit by bit. The bits in the IP address that correspond to the 1 bits in the netmask determine the network number of the IP address; those corresponding to the 0 bits in the netmask determine the device number.
Purpose
Netmasks are used to divide an address space into smaller subnets. Devices on the same subnet can communicate with each other directly using the TCP/IP protocol stack. Devices on different subnets must use one or more routers to forward data between them. Because they isolate subnets from each other, netmasks are a natural way to create logical groupings of devices. For example, each location or department within a company may have its own subnet, or each type of device (printers, PCs, etc.) may have its own subnet.
Example netmasks:
255.255.255.128 → FF FF FF 10 → 1111 1111 1111 1111 1111 1111 1000 0000
This netmask specifies that the first 25 bits of an IP address determine the network number; the final 7 bits determine the device number. This means there can be 225 different subnets, each with 27 = 128 devices.*
255.255.255.0 → FF FF FF 00 → 1111 1111 1111 1111 1111 1111 0000 0000
This netmask specifies an address space with 224 subnets, each with 28 = 256 individual addresses. This is a very common configuration—so common that it's known simply as a "Class C" network.
255.255.192.0 → FF FF FC 00 → 1111 1111 1111 1111 1111 1100 0000 0000
This netmask specifies 222 subnets, each with 210 = 1024 addresses. It might be used inside a large corporation, where each department has several hundred devices that should be logically grouped together.
An invalid netmask (note the internal zeroes):
255.128.255.0 → FF 80 FF 00 → 1111 1111 1000 0000 1111 1111 0000 0000
Calculations
Here are a few examples that show how a netmask determines the network number and the device number of an IP address.
IP Address: 192.168.0.1 → C0 A8 00 01
Netmask: 255.255.255.0 → FF FF FF 00
This device is on the subnet 192.168.0.0. It can communicate directly with other devices whose IP addresses are of the form 192.168.0.x
IP Address: 192.168.0.1 → C0 A8 00 01
IP Address: 192.168.0.130 → C0 A8 00 82
Netmask: 255.255.255.128 → FF FF FF 80
These two devices are on different subnets and cannot communicate with each other without a router.
IP Address: 10.10.195.27 → 0A 0A C3 1B
Netmask: 255.255.0.0 → FF FF 00 00
This is an address on a "Class B" network that can communicate with the 216 addresses on the 10.10.0.0 network.
You can see that the more 1 bits at the beginning of a netmask, the more specific it is. That is, more 1 bits create a "smaller" subnet that consists of fewer devices.
Putting it all together
A routing table, like yours, contains triplets of netmasks, IP addresses, and interfaces. (It may also contain a "cost' metric, which indicates which of several interfaces is the "cheapest" to use, if they are both capable of routing data to a particular destination. For example, one may use an expensive dedicated line.)
In order to route a packet, the router finds the interface with the most specific match for the packet's destination. An entry with an address addr and a netmask mask matches a destination IP address dest if (addr & netmask) == (dest & netmask), where & indicates a bitwise AND operation. In English, we want the smallest subnet that is common to both addresses.
Why? Suppose you and a colleague are in a hotel that's part of a huge chain with both a corporate wired network and a wireless network. You've also connected to your company's VPN. Your routing table might look something like this:
Destination Netmask Interface Notes
----------- -------- --------- -----
Company email FFFFFF00 VPN Route ALL company traffic thru VPN
Wired network FFFF0000 Wired Traffic to other hotel addresses worldwide
Default 00000000 Wireless All other traffic
The most specific rule will route your company email safely through the VPN, even if the address happens to match the wired network also. All traffic to other addresses within the hotel chain will be routed through the wired network. And everything else will be sent through the wireless network.
* Actually, in every subnet, 2 of the addresses—the highest and the lowest—are reserved. The all-ones address is the broadcast address: this address sends data to every device on the subnet. And the all-zeroes address is used by a device to refer to itself when it doesn't yet have it's own IP address. I've ignored those for simplicity.
So the algorithm would be something like this:
initialize:
Sort routing table by netmask from most-specific to least specific.
Within each netmask, sort by IP address.
search:
foreach netmask {
Search IP addresses for (input & netmask) == (IP address & netmask)
Return corresponding interface if found
}
Return default interface

Ok so I this is what my structure and algorithm looks like now. It works and gives me the results that I want, however I still don't know how to sort ip addresses within netmasks. I used STL sort to sort the netmasks.
struct routeEntry_t
{
uint32_t ipAddr;
uint32_t netMask;
int interface;
bool operator<(const routeEntry_t& lhs) const
{
return lhs.netMask < netMask;
}
};
const int SIZE = 6;
routeEntry_t routing_table[SIZE];
void sorting()
{
//using STL sort from lib: algorithm
sort(routing_table, routing_table+SIZE);
}
int interface(uint32_t ipAddr)
{
for (int i = 0; i < SIZE; ++i)
{
if ((routing_table[i].ipAddr & routing_table[i].netMask) == (ipAddr & routing_table[i].netMask))
return routing_table[i].interface;
}
return routing_table[SIZE-1].interface;
}

Related

How swift know value of memory is address or actual value that I assigned

struct ValueType {
var member: Int
}
class ReferenceType {
var member: Int
init(member: Int) {
self.member = member
}
}
var valueTypeObject = ValueType(member: 3)
var referenceTypeObject = ReferenceType(member: 4)
withUnsafePointer(to: &referenceTypeObject) {
print("referenceTypeObject address: \($0)")
}
withUnsafePointer(to: &valueTypeObject) {
print("valueTypeObject address: \($0)")
}
When executing the above code, the address of each object appears like this.
valueTypeObject address: 0x0000000100008218
referenceTypeObject address: 0x0000000100008220
First, if I view memory of valueTypeObject address (0x0000000100008218), I can check the 03 value within 64 bits that I actually allocated (03 00 00 00 00 00 00 00 00 00 00 00 00 00. Maybe data is stored as little endian.)
Next, if I view memory of referenceTypeObject address (0x0000000100008220), I can check 0x000000010172f8b0 is stored in 64bit. (I don't know why right side of ..r..... is also highlighted, and what it is 🤔)
I know that the referenceTypeObject is reference type, so the actual value is in the heap area. So I can guess 0x000000010172f8b0 is an address that stores the actual value that I assigned (in this case, 4.)
But how does Swift know that this is the address that points to heap area instead of 0x000000010172f8b0 value that can be assied by me?
In addition, if I view memory of address 0x000000010172f8b0 where the actual value is stored, there are some 32 bytes values in front of the value that I allocated (in this case, 4). What are those?

Minimalmodbus: read multiple slaves on same serial port

I have a setup with 2 SDM120 kWh energy meters daisy chained on the same serial port (in the future I want to add a SDM630). I found "Using multiple instruments" in the MinimalModbus communication. I succeed in reading registers on the SDM120 on address 1, but I get an error on reading address 2. The error: minimalmodbus.NoResponseError: No communication with the instrument (no answer).
I can work around it by adding time.sleep(0.1), but I would think that RS485 allows to immediately read the registers of a second address after the first one is completed. I also tried lower values, but eg. time.sleep(0.01) also gave a NoResponseError.
I personally thought the setting instrument.serial.timeout = 1 already would have had the desired effect, but apparently I really need the time.sleep. Is the time.sleep(0.1) the correct way of doing? If so: how can I know the lowest value, so that I don't have a NoResponseError? Trial and error? Could my script be optimized? Especially when timing is important, eg. to avoid injection in the grid (pv diverter, ...). Thanks in advance!
The script:
#!/usr/bin/env python3
import minimalmodbus
import time
instrumentA = minimalmodbus.Instrument('/dev/ttyUSB0', 1, debug = True) # port name, slave address (in decimal)
instrumentA.serial.baudrate = 9600
instrumentA.serial.timeout = 1 # seconds
instrumentA.serial.bytesize = 8
instrumentA.serial.parity = minimalmodbus.serial.PARITY_NONE
instrumentA.serial.stopbits = 1
instrumentA.mode = minimalmodbus.MODE_RTU
instrumentB = minimalmodbus.Instrument('/dev/ttyUSB0', 2, debug = True)
instrumentB.mode = minimalmodbus.MODE_RTU
print ("====== SDM120 instrumentA on addres 1 ======")
print (instrumentA)
P = instrumentA.read_float(12, 4, 2)
print ("Active Power in Watts:", P)
#time.sleep(0.1) #workaround to avoid NoResponseError
print ("====== SDM120 instrumentB on addres 2 ======")
print (instrumentB)
P = instrumentB.read_float(12, 4, 2)
print ("Active Power in Watts:", P)
Output without the time.sleep(0.1):
MinimalModbus debug mode. Create serial port /dev/ttyUSB0
MinimalModbus debug mode. Serial port /dev/ttyUSB0 already exists
====== SDM120 instrumentA on addres 1 ======
minimalmodbus.Instrument<id=0x7f36e3dc0df0, address=1, mode=rtu, close_port_after_each_call=False, precalculate_read_size=True, clear_buffers_before_each_transaction=True, handle_local_echo=False, debug=True, serial=Serial<id=0x7f36e3dd90d0, open=True>(port='/dev/ttyUSB0', baudrate=9600, bytesize=8, parity='N', stopbits=1, timeout=1, xonxoff=False, rtscts=False, dsrdtr=False)>
MinimalModbus debug mode. Will write to instrument (expecting 9 bytes back): '\x01\x04\x00\x0c\x00\x02±È' (01 04 00 0C 00 02 B1 C8)
MinimalModbus debug mode. Clearing serial buffers for port /dev/ttyUSB0
MinimalModbus debug mode. No sleep required before write. Time since previous read: 190954.73 ms, minimum silent period: 4.01 ms.
MinimalModbus debug mode. Response from instrument: '\x01\x04\x04\x00\x00\x00\x00û\x84' (01 04 04 00 00 00 00 FB 84) (9 bytes), roundtrip time: 53.3 ms. Timeout for reading: 1000.0 ms.
Active Power in Watts: 0.0
====== SDM120 instrumentB on addres 2 ======
minimalmodbus.Instrument<id=0x7f36e3c55940, address=2, mode=rtu, close_port_after_each_call=False, precalculate_read_size=True, clear_buffers_before_each_transaction=True, handle_local_echo=False, debug=True, serial=Serial<id=0x7f36e3dd90d0, open=True>(port='/dev/ttyUSB0', baudrate=9600, bytesize=8, parity='N', stopbits=1, timeout=1, xonxoff=False, rtscts=False, dsrdtr=False)>
MinimalModbus debug mode. Will write to instrument (expecting 9 bytes back): '\x02\x04\x00\x0c\x00\x02±û' (02 04 00 0C 00 02 B1 FB)
MinimalModbus debug mode. Clearing serial buffers for port /dev/ttyUSB0
MinimalModbus debug mode. Sleeping 2.31 ms before sending. Minimum silent period: 4.01 ms, time since read: 1.70 ms.
MinimalModbus debug mode. Response from instrument: '' () (0 bytes), roundtrip time: 1001.3 ms. Timeout for reading: 1000.0 ms.
Traceback (most recent call last):
File "./sdm120-daisychain_v3.py", line 25, in <module>
P = instrumentB.read_float(12, 4, 2)
File "/home/mattias/.local/lib/python3.8/site-packages/minimalmodbus.py", line 662, in read_float
return self._generic_command(
File "/home/mattias/.local/lib/python3.8/site-packages/minimalmodbus.py", line 1170, in _generic_command
payload_from_slave = self._perform_command(functioncode, payload_to_slave)
File "/home/mattias/.local/lib/python3.8/site-packages/minimalmodbus.py", line 1240, in _perform_command
response = self._communicate(request, number_of_bytes_to_read)
File "/home/mattias/.local/lib/python3.8/site-packages/minimalmodbus.py", line 1406, in _communicate
raise NoResponseError("No communication with the instrument (no answer)")
minimalmodbus.NoResponseError: No communication with the instrument (no answer)
Output with the time.sleep(0.1):
MinimalModbus debug mode. Create serial port /dev/ttyUSB0
MinimalModbus debug mode. Serial port /dev/ttyUSB0 already exists
====== SDM120 instrumentA on addres 1 ======
minimalmodbus.Instrument<id=0x7f91feddcdf0, address=1, mode=rtu, close_port_after_each_call=False, precalculate_read_size=True, clear_buffers_before_each_transaction=True, handle_local_echo=False, debug=True, serial=Serial<id=0x7f91fedf50d0, open=True>(port='/dev/ttyUSB0', baudrate=9600, bytesize=8, parity='N', stopbits=1, timeout=1, xonxoff=False, rtscts=False, dsrdtr=False)>
MinimalModbus debug mode. Will write to instrument (expecting 9 bytes back): '\x01\x04\x00\x0c\x00\x02±È' (01 04 00 0C 00 02 B1 C8)
MinimalModbus debug mode. Clearing serial buffers for port /dev/ttyUSB0
MinimalModbus debug mode. No sleep required before write. Time since previous read: 176619.62 ms, minimum silent period: 4.01 ms.
MinimalModbus debug mode. Response from instrument: '\x01\x04\x04\x00\x00\x00\x00û\x84' (01 04 04 00 00 00 00 FB 84) (9 bytes), roundtrip time: 53.3 ms. Timeout for reading: 1000.0 ms.
Active Power in Watts: 0.0
====== SDM120 instrumentB on addres 2 ======
minimalmodbus.Instrument<id=0x7f91fec70940, address=2, mode=rtu, close_port_after_each_call=False, precalculate_read_size=True, clear_buffers_before_each_transaction=True, handle_local_echo=False, debug=True, serial=Serial<id=0x7f91fedf50d0, open=True>(port='/dev/ttyUSB0', baudrate=9600, bytesize=8, parity='N', stopbits=1, timeout=1, xonxoff=False, rtscts=False, dsrdtr=False)>
MinimalModbus debug mode. Will write to instrument (expecting 9 bytes back): '\x02\x04\x00\x0c\x00\x02±û' (02 04 00 0C 00 02 B1 FB)
MinimalModbus debug mode. Clearing serial buffers for port /dev/ttyUSB0
MinimalModbus debug mode. No sleep required before write. Time since previous read: 102.09 ms, minimum silent period: 4.01 ms.
MinimalModbus debug mode. Response from instrument: '\x02\x04\x04\x00\x00\x00\x00È\x84' (02 04 04 00 00 00 00 C8 84) (9 bytes), roundtrip time: 52.8 ms. Timeout for reading: 1000.0 ms.
Active Power in Watts: 0.0
There seems to be nothing wrong with your code or the library you are using (minimalmodbus).
As you probably know, Modbus works in a query-response mode over a half-duplex link. In plain English: you first send a query and the device that query is addressed to answers with the data you asked for.
Both parts of the transaction (queries and responses) travel over the same bus. But the bus is a shared medium and only one device is allowed to take control of the bus (to talk) at any time.
When you have a single master and one or multiple slaves this process works with no issues as long as you guarantee a short silent period after any device writes to the bus. The Modbus specification established this value at 3.5 characters (the time it takes to send 3 and a half characters serially on the bus at the baud rate you are using).
Unfortunately, some manufacturers do not stick to this rule. So some of those devices just take longer than 3.5 characters time to release control of the bus.
This seems to be the case at least with one of your devices. This manual can give you some clues:
My bet is out of your two devices one of them takes significantly less than the other to release the bus, but that's something you will have to confirm with the debug details. It might even be that the device takes longer to release the bus if you query 20 or 40 registers instead of 4 or 8...
What can you do about it? Well, from the device side, not much, it is what it is. On your software you can do many different things. As I said in the comments above you should not feel bad about using time.sleep() considering that's the way minimalmodbus tries to cope with the bus contention problem.
To make your code more robust you can add try: ... except:. This approach is explained in the documentation. You can keep retrying to read within a loop for a number of attempts or add a small delay to the except chunk. Maybe something like this.
The answer of Marcos G. (answered Apr 13 at 9:24) includes some background details. In short:
With some trial and error, one can have a value for time.sleep so that minimalmodbus can cope with the bus contention problem.
You can have more robust code with try: ... except:. It might be a good idea to only try a number of times, to avoid a infinite loop.
I include two scripts which use those approaches to my posted problem. Compared to my original question a for loop and an array for the addresses is used.
The first one is with time.sleep
#!/usr/bin/env python3
import minimalmodbus
import time
addr = 1
instrument = minimalmodbus.Instrument('/dev/ttyUSB0', addr) # port name, slave address (in decimal)
instrument.serial.baudrate = 9600 # Baud
instrument.serial.bytesize = 8
instrument.serial.parity = minimalmodbus.serial.PARITY_NONE
instrument.serial.stopbits = 1
instrument.serial.timeout = 1 # seconds
instrument.mode = minimalmodbus.MODE_RTU # rtu or ascii mode
addresses = [1,2]
registers = [ 0, 6, 12, 18, 24, 30, 70, 72, 74, 76, 78, 84, 86, 88, 90, 92, 94, 258, 264, 342, 344]
names = ["V","I","P","S", "Q","PF","f","IAE","EAE", "IRE", "ERE","TSP","MSP","ISP","MIP","ESP","MEP","ID","MID","TAE", "TRE"]
units = ["V","A","W","VA","var", "","Hz","kWh","kWh","kvarh","kvarh", "W", "W", "W", "W", "W", "W", "A", "A","kWh","kvarh"]
info = [
"(V for Voltage in volt)",
"(I for Current in ampere)",
"(P for Active Power in watt)",
"(S for Apparent power in volt-ampere)",
"(Q for Reactive power in volt-ampere reactive)",
"(PF for Power Factor)",
"(f for Frequency in hertz)",
"(IAE for Import active energy in kilowatt-hour)",
"(EAE for Export active energy in kilowatt-hour)",
"(IRE for Import reactive energy in kilovolt-ampere reactive hours)",
"(ERE for Export reactive energy in kilovolt-ampere reactive hours)",
"(TSP for Total system power demand in watt)",
"(MSP for Maximum total system power demand in watt)",
"(ISP for Import system power demand in watt)",
"(MIP for Maximum import system power demand in watt)",
"(ESP for Export system power demand in watt)",
"(MEP for MaximumExport system power demand in watt)",
"(ID for current demand in ampere)",
"(MID for Maximum current demand in ampere)",
"(TAE for Total active energy in kilowatt-hour)",
"(TRE for Total reactive energy in kilovolt-ampere reactive hours)",
]
for addr in addresses:
instrument.address = addr
print ("=== General info about address", addr, "===")
print (instrument)
print ("=== The registers for address", addr, "===")
for i in range(len(registers)):
value = instrument.read_float(registers[i], 4, 2)
print (str(registers[i]).rjust(3), str(value).rjust(20), units[i].ljust(5), info[i])
time.sleep(0.1) # To avoid minimalmodbus.NoResponseError
print ("")
The second one with try: ... except:
#!/usr/bin/env python3
import minimalmodbus
# This alternative script `sdm120-daisy-alt.py` will try to reread a device an extra 9 times before giving up and continuing with the other addresses in the array.
addr = 1
instrument = minimalmodbus.Instrument('/dev/ttyUSB0', addr) # port name, slave address (in decimal)
instrument.serial.baudrate = 9600 # Baud
instrument.serial.bytesize = 8
instrument.serial.parity = minimalmodbus.serial.PARITY_NONE
instrument.serial.stopbits = 1
instrument.serial.timeout = 1 # seconds
instrument.mode = minimalmodbus.MODE_RTU # rtu or ascii mode
addresses = [1,2]
registers = [ 0, 6, 12, 18, 24, 30, 70, 72, 74, 76, 78, 84, 86, 88, 90, 92, 94, 258, 264, 342, 344]
names = ["V","I","P","S", "Q","PF","f","IAE","EAE", "IRE", "ERE","TSP","MSP","ISP","MIP","ESP","MEP","ID","MID","TAE", "TRE"]
units = ["V","A","W","VA","var", "","Hz","kWh","kWh","kvarh","kvarh", "W", "W", "W", "W", "W", "W", "A", "A","kWh","kvarh"]
info = [
"(V for Voltage in volt)",
"(I for Current in ampere)",
"(P for Active Power in watt)",
"(S for Apparent power in volt-ampere)",
"(Q for Reactive power in volt-ampere reactive)",
"(PF for Power Factor)",
"(f for Frequency in hertz)",
"(IAE for Import active energy in kilowatt-hour)",
"(EAE for Export active energy in kilowatt-hour)",
"(IRE for Import reactive energy in kilovolt-ampere reactive hours)",
"(ERE for Export reactive energy in kilovolt-ampere reactive hours)",
"(TSP for Total system power demand in watt)",
"(MSP for Maximum total system power demand in watt)",
"(ISP for Import system power demand in watt)",
"(MIP for Maximum import system power demand in watt)",
"(ESP for Export system power demand in watt)",
"(MEP for MaximumExport system power demand in watt)",
"(ID for current demand in ampere)",
"(MID for Maximum current demand in ampere)",
"(TAE for Total active energy in kilowatt-hour)",
"(TRE for Total reactive energy in kilovolt-ampere reactive hours)",
]
for addr in addresses:
instrument.address = addr
print ("=== General info about address", addr, "===")
print (instrument)
print ("=== The registers for address", addr, "===")
for attempt in range(10):
try:
for i in range(len(registers)):
value = instrument.read_float(registers[i], 4, 2)
print (str(registers[i]).rjust(3), str(value).rjust(20), units[i].ljust(5), info[i])
except minimalmodbus.NoResponseError:
print("NoResponseError: did't work on attempt ", attempt+1, "I will retry")
else:
print ("Succeeded on attempt", attempt+1)
break
print ("")

Reading MLDv2 queries using an IPv6 socket

I have mrd6 installed on my raspberry pi. It registers with a local interface (tun0) and periodically transmits MLDv2 queries over it.
According to [RFC3810], MLDv2 message types are a subset of ICMPv6 messages, and are identified in IPv6 packets by a preceding Next Header value of 58 (0x3a). They are sent with a link-local IPv6 Source Address, an IPv6 Hop Limit of 1, and an IPv6 Router Alert option [RFC2711] in a Hop-by-Hop Options header.
I can confirm that I'm seeing these packets periodically over tun0:
pi#machine:~ $ sudo tcpdump -i tun0 ip6 -vv -XX
01:22:52.125915 IP6 (flowlabel 0x71df6, hlim 1, next-header Options (0)
payload length: 36)
fe80::69bf:be2d:e087:9921 > ip6-allnodes: HBH (rtalert: 0x0000) (padn)
[icmp6 sum ok] ICMP6, multicast listener query v2 [max resp delay=10000]
[gaddr :: robustness=2 qqi=125]
0x0000: 6007 1df6 0024 0001 fe80 0000 0000 0000 `....$..........
0x0010: 69bf be2d e087 9921 ff02 0000 0000 0000 i..-...!........
0x0020: 0000 0000 0000 0001 3a00 0502 0000 0100 ........:.......
0x0030: 8200 b500 2710 0000 0000 0000 0000 0000 ....'...........
0x0040: 0000 0000 0000 0000 027d 0000 .........}..
I have a socket set up in my application on tun0 as follows, since I expect these to be ICMP packets:
int fd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); // ICMP
// ... bind this socket to tun0
int interfaceIndex = // tun0 interface Index
int mcastTTL = 10;
int loopBack = 1;
if (setsockopt(listener->socket,
IPPROTO_IPV6,
IPV6_MULTICAST_IF,
&interfaceIndex,
sizeof(interfaceIndex))
< 0) {
perror("setsockopt:: IPV6_MULTICAST_IF:: ");
}
if (setsockopt(listener->socket,
IPPROTO_IPV6,
IPV6_MULTICAST_LOOP,
&loopBack,
sizeof(loopBack))
< 0) {
perror("setsockopt:: IPV6_MULTICAST_LOOP:: ");
}
if (setsockopt(listener->socket,
IPPROTO_IPV6,
IPV6_MULTICAST_HOPS,
&mcastTTL,
sizeof(mcastTTL))
< 0) {
perror("setsockopt:: IPV6_MULTICAST_HOPS:: ");
}
struct ipv6_mreq mreq6 = {{{{0}}}};
MEMCOPY(&mreq6.ipv6mr_multiaddr.s6_addr, sourceAddress, 16);
mreq6.ipv6mr_interface = interfaceIndex;
if (setsockopt(listener->socket,
IPPROTO_IPV6,
IPV6_JOIN_GROUP,
&mreq6,
sizeof(mreq6))
< 0) {
perror("setsockopt:: IPV6_JOIN_GROUP:: ");
}
Setting up the socket this way, I can receive ICMP echo requests, replies to my own address, and multicasts sent using the link-local multicast address. However, I don't see any MLDv2 queries.
Here's my receive loop:
uint8_t received[1000] = { 0 };
struct sockaddr_storage peerAddress = { 0 };
socklen_t addressLength = sizeof(peerAddress);
socklen_t addressLength = sizeof(peerAddress);
int receivedLength = recvfrom(sockfd,
received,
sizeof(received),
0,
(struct sockaddr *)&peerAddress,
&addressLength);
if (receivedLength > 0) {
// Never get here for MLDv2 queries.
}
Researching this a bit further, I discovered the IPV6_ROUTER_ALERT socket option, which the man page describes as follows:
IPV6_ROUTER_ALERT
Pass forwarded packets containing a router alert hop-by-hop option to this socket.
Only allowed for SOCK_RAW sockets. The tapped packets are not forwarded by the
kernel, it is the user's responsibility to send them out again. Argument is a
pointer to an integer. A positive integer indicates a router alert option value
to intercept. Packets carrying a router alert option with a value field
containing this integer will be delivered to the socket. A negative integer
disables delivery of packets with router alert options to this socket.
So I figured I was missing this option, and tried setting it as follows. [RFC2710] 0 means Multicast Listener Discovery message.
int routerAlertOption = 0;
if (setsockopt(listener->socket,
IPPROTO_IPV6,
IPV6_ROUTER_ALERT,
&routerAlertOption,
sizeof(routerAlertOption))
< 0) {
perror("setsockopt:: IPV6_ROUTER_ALERT:: ");
}
However, this gives me the ENOPROTOOPT error (errno 92). Some more Googling (http://www.atm.tut.fi/list-archive/usagi-users-2005/msg00317.html) led me to the fact that you can't set the IPV6_ROUTER_ALERT option with the IPPROTO_ICMPV6 protocol. It needs a socket defined using the IPPROTO_RAW protocol.
However, defining my socket as:
int fd = socket(AF_INET6, SOCK_RAW, IPPROTO_RAW);
means I'm not able to receive any ICMP packets in my recvfrom anymore.
TL;DR: How do I read MLDv2 queries using an IPv6 socket?
edit (answer):
It appears conventional implementations of Linux will drop MLDv2 packets when passing them to an ICMPV6 socket. Why this is, I'm not sure. (Could be because of the next-header option.)
I followed the accepted answer below and went with an approach of reading raw packets on the tun0 interface. I followed the ping6_ll.c example here: http://www.pdbuchan.com/rawsock/rawsock.html.
It uses a socket with (SOCK_RAW, ETH_P_ALL). You can also set some SOL_PACKET options to filter on specific multicast rules on your interface.
From a quick look at RFCs things aren't looking good. Per RFC4443 (ICMPv6) 2.4:
2.4. Message Processing Rules
Implementations MUST observe the following rules when processing
ICMPv6 messages (from [RFC-1122]):
(b) If an ICMPv6 informational message of unknown type is received,
it MUST be silently discarded.
According to MLDv2 spec it makes use of types 130, 143, perhaps something else (not seeing more diagrams in the RFC), while valid ICMPv6 types are 1, 2, 3, 4, 101, 107, 127, 128, 129, 200, 201, 255.
It looks like the implementation (kernel) must drop MLDv2 packets if they are to be passed to an ICMPv6 socket. Personally I don't see much sense in making MLDv2 look like ICMPv6 if conventional implementations will drop the packet anyways, but I didn't see anything that contradicts this claim.
You can surely go deeper and use a raw socket, especially given that your stack doesn't recognize MLDv2 (perhaps there's a kernel patch to fix that?). But you'll have to parse IP and ICMP headers on your own then.

Car OBDII WLAN protocol

I am currently searching for the specification of the WLAN protocoll to get OBDII data. There are some ELM327 similar adapter on the market which enables iPhone to connect to a OBDII interface with WLAN. This because Bluetooth serial port is scrambled because of the accessories interface. Other programs like Torque for android can also use this communication protocol. However I did not find the specs for creating a network client.
Any help is welcomed,
Thanks
Ok, after some more research, I found two sources:
Michael Gile has an open source library for iOS devices, meant for communicating with OBDII WiFi as well as Bluetooth devices.
PLX devices (creators of the KiWi) have a description how to communicate with the KiWi. The description is too large to include here, but it boils down to:
Connect using WiFi (sockets)
Wait until the device returns >
Issue command and await response
Requesting information can be done by sending a command in this format (ASCII characters):
MM PP\r
where MM is the test mode, PP is the PID, and \r is a carriage return (hex: 0x0d). All whitespace characters are ignored by the Kiwi. *Test modes 03 and 04 do not require a PID value.
The 'test modes' that are spoken of, are the ten diagnostic modes as defined in the SAE J1979 standard:
Test mode Description
01 Show current data
02 Show freeze frame data
03 Show diagnostic trouble codes
04 Clear trouble codes and stored values
05 Test results, oxygen sensors
06 Test results, non-continuously monitored
07 Show 'pending' trouble codes
08 Special control mode
09 Request vehicle information
0A Request permanent trouble codes
The PID values are the codes for the sensors in the car. A (non-exhaustive)list of possible PID values is on Wikipedia.
here what i do in C and socket:
int sockfd = 0, n = 0;
char recvBuff[1024];
struct sockaddr_in serv_addr;
char *ip = "192.168.0.10";
char str [128];
int i;
memset(recvBuff, '0',sizeof(recvBuff));
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
printf("\n Error : Could not create socket \n");
return 1;
}
memset(&serv_addr, '0', sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(35000);
if(inet_pton(AF_INET, ip, &serv_addr.sin_addr)<=0)
{
printf("\n inet_pton error occured\n");
return 1;
}
if( connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
{
printf("\n Error : Connect Failed \n");
return 1;
}
printf ("reading...\n");
strcpy (str,"AT Z\x0d");
sleep(2);
write (sockfd, str, strlen (str));
while ( (n = read(sockfd, recvBuff, sizeof(recvBuff)-1)) > 0)
{
recvBuff[n] = 0;
printf ("received: ");
if(fputs(recvBuff, stdout) == EOF)
{
printf("\n Error : Fputs error\n");
}
printf ("\r\ntype: ");
fgets (str, sizeof (str), stdin);
i = strlen (str);
if (str [i-1] == 0x0a)
str [i-1] = 0;
strcat (str, "\x0d");
write (sockfd, str, strlen (str));
printf ("\r\n");
}
type 1 or 2 enter, you should see the prompt: ELM327
then after that, type whatever you want, for ex.: AT RV (will show voltage)
then use this pdf for all code:
https://www.obd-2.de/carcode/dl/ELM327DS.pdf
Have a look at ELM327 datasheet
Wifi dongles transparently bind the ELM327 RS232 port to a TCP server.
There's not really a WIFI protocol. You can use the ELM327 protocol via a raw TCP connection instead.
You can sent AT commands and OBD2 commands known as PID's with the telnet command:
telnet 192.168.0.1 35000
On succesful connection you can try to send:
AT Z
and the server should respond with "ELM327" and a version number.

T-Sql: check if IP matches netmask

My SQL-Server db stores IP netmasks as binary.
I need a way to match these with a given IP
For example,
is 192.168.21.5 part of a netmask which is stored in the DB?
The binary representation of 192.168.21.5:
11000000.10101000.00010101.00000101 (without the dots)
The netmask stored in the DB is: binary(4) and a tinyint field:
11000000.10101000.00010101.00000000 / 24
(which would be: 192.168.21.0 /24) so, the first 24 bits of 192.168.21.5 have to match a record in the database.
How would I only check the first n bits of a binary field (similar to LEFT(text, 24))?
Is there any clever way to do this, maybe with bitwise AND?
declare #address binary(4) -- goal is to check if this address
declare #network binary(4) -- is in this network
declare #netmask tinyint -- with this netmask in /NN format
set #address = 0xC0A81505 -- 192.168.21.5
set #network = 0xC0A81500 -- 192.168.21.0
set #netmask = 24
select
'address matches network/netmask'
where
0 = (
cast(#address as int) ^ cast(#network as int))
&
~(power(2, 32 - #netmask) - 1)
)
#netmask must be between 2 and 32.
192.168.21.5 XOR netmask (192.168.21.0) AND 255.255.255.0 (you want only first 24 bits) should be all 0 on the "matching" IP.
This condition does it:
(0xffffffff - POWER(2, 32 - bits) + 1) & CAST(ip AS int) = CAST(netmask AS int)
If you want it work with mask 0 or 1 bit then you need change power(2, 32 - #netmask) to
power(cast(2 as bigint), 32 - #netmask)
Bye