join igmp_group not working in lightwight IP (lwip) - multicast

I'm new to lwip, and I want to create a multicast receiver with lwip. My steps are as follow:
1. Enable LWIP_IGMP;
2. Set NETIF_FLAG_IGMP in low_level_init();
3. Join multicast group, create and bind pcb;
4. udp_connect to remote_ip (or multicast IP address? Both are tried but failed)
Joining group returns success, and everything looks fine when program executing this. However the multicast receiver doesn't work, no multicast data comes into network interface. Seems I don't actually join my receiver to the igmp group, although the joining process looks fine. Does any one know what I'm missing?
I found "netif->igmp_mac_filter != NULL" in igmp_joingroup(), but this callback is set as NULL and not implemented. Do I need to implement it by myself to set the MAC filter or it is OK just leave it as NULL?
Thanks a lot for your help!
Ryan

When you join a multicast group the netif->igmp_mac_filter callback is typically called to configure a MAC filter in your Ethernet controller to accept packets with the multicast MAC address corresponding to the group. So, depending on the Ethernet H/W that you are using you may need to implement the callback.

The hardware needs to be configured to receive multcast MAC frames, otherwise it will simply discard all frames with multicast destination address. There is probably an option to accept all incoming multicast frames. Enable that in low_level_init() and you should be able to see the incoming multicast frames. You shouldn't need to implement any filter.

I had the same problem. I solved it removing the ETH Multicast Frame filter in the init of the MAC interface.
To test, you can also set the interface in promiscuous mode, check if the multicast packet are received an then remove the promiscuous mode and set an appropriate Multicast Frame Filtering mode according to your needs.

I set the code for Multicast Frame Filter as follows:
/* USER CODE BEGIN PHY_PRE_CONFIG */
ETH_MACFilterConfigTypeDef FilterConfig;
FilterConfig.PromiscuousMode = 1;
FilterConfig.PassAllMulticast = 1;
HAL_ETH_SetMACFilterConfig(&heth, &FilterConfig);
/* USER CODE END PHY_PRE_CONFIG */

Related

Bluetooth LE: scanning with whitelist?

I'm checking this source for scanning BT LE advertisement messages with BlueZ:
https://github.com/edrosten/libblepp/blob/master/src/lescan.cc
Mainly it does this (pseudo):
hci_fd=hci_open_dev(dev)
hci_le_set_scan_parameters(hci_fd, static_cast<int>(scan_type), interval, window,
own_type, filter_policy, 10000);
struct hci_filter nf;
hci_filter_clear(&nf);
hci_filter_set_ptype(HCI_EVENT_PKT, &nf);
hci_filter_set_event(EVT_LE_META_EVENT, &nf);
setsockopt(hci_fd, SOL_HCI, HCI_FILTER, &nf, sizeof(nf)
hci_le_set_scan_enable(hci_fd, 0x01, filter_dup, 10000);
In case I set hardware filter (by setting filter_dup to 1, I'm not getting my desired messages immediately. They come only at a low-frequency (1/min). That's fine, as the hardware filtering disables the duplicates, and I guess there is a timeout after which it let's them in again. (This seems to be exactly 1 minute in my case).
Turning off the filtering causes a huge traffic arriving in, from which I would only need all messages from a specific mac-addressed device. Can I somehow add a whitelist to the scanning command?
Then it can give me all the packets from my desired device, and leave out all the rest.
How can I do this with BlueZ over HCI?
I think your best option is to filter the messages within your code. I don't know of anything in the API to have it filter messages on the hardware level like you describe.
There is a "whitelist" function in BLE, but that's related to specifying a list of addresses that you want to connect to and then you let the hardware automatically connect to just those addresses. (sounds like you actually want just the ad packets and not actually connect, though)
EDIT:
I think I was wrong... Look at the filter_policy to hci_le_set_scan_parameters. If it's 0x1 then I think it filters based on the whitelist. I don't know how to set the whitelist, though.
I found it very useful looking at the source code for hcitool and gatttool when trying to understand the bluez library C calls. https://github.com/bluez/bluez/blob/master/tools/hcitool.c has reference to an "acceptlist" which seems to be what you want.

Where and how does ethernet header get added/deleted in Linux stack?

I had two question relating to code implementation in the Linux networking stack:
I see that "struct eth_header_ops" is used to add ethernet header to a IP packet. But I am unable to find how the functions inside it are invoked, and which function is supposed to do what. What is the code flow for this?
Similarly, when does the ethernet header get removed on an incoming frame? Could you show the path from the NIC driver to the place where the header is actually removed?
thank you.
I think this is done as part of ip_finish_output2(). But I would really like some experts to throw more light into the flow for TX and RX wrt ethernet header manipulation.

Socat pseudo terminal: Can you make use of data lines (DTR, RTS etc)?

I'm creating a virtual serial port using socat.
socat -d -d pty,echo=0,raw pty,echo=0,raw
That works as expected so far. Using echo/cat I can send/receice text etc.
But what about signal lines like DTR or RTS? How would I get / set the state of these lines with a pty? Is that even possible? I couldn't find any mentions about it anywhere.
socat is a pipe handler, basically lets you tap in the Tx and Rx "lines" without you having to care about signaling when data is ready/received.
The RTS/CTS/DSR/DTR are actual pins in a serial connector that control what is going on on the Tx/Rx lines.
Off the top of my head, I haven't used socat nor tried to do anything similar, lowest possible level I got was the EMV interface and protocol and sometimes I also netcat stuff real quick between machines when I'm too lazy to cp to a directory within httpd home... anyway, if you are trying to connect two entities with socat (separate machines, or applications on the same machine) you'll either use the same pipe and specify some control characters so they end up talking at the same time (got to make a note of this and try to implement it somehow with my wife), or use two separate pipes, one for Rx and one for Tx: Tx of entity 1 goes into Rx of entity 2, Tx of entity 2 goes into Rx of entity 1.
From your comment, it sounds like you want to control RTS/CTS independent of your data stream. You will have to write an application to interact with the serial port using ioctls.
I found this helpful forum post (with an example application)
https://www.linuxquestions.org/questions/programming-9/manually-controlling-rts-cts-326590/
You can use hardware flow control lines (RTS/CTS):
socat stdio file:/dev/ttyAMA0,crtscts=1,b9600
Nowadays, this is mostly useful when talking to an RS485 transceiver, since that's the most common example of half-duplex serial line that is still in use. On some commonly used transceivers, such as the 75HVD12, the DE (drive enable) pin is connected to the host's RTS. There's also an active-low /RE (receive enable) pin that is connected to either RTS or CTS.
If you have access to GPIO, such as on a Raspberry Pi, you might be able to assign DTR and DSR to an output and input pin respectively. Alternatively, an USB adapter such as FTDI232 will assert DTR if it is connected to a computer.

Can I intercept network packets with a raw socket (not only sniff)?

This is my first time using raw sockets (yes, I need to use them as I must modify a field inside a network header) and all the documentation or tutorials I read describe a solution to sniff packets but that is not exactly what I need. I need to create a script which intercepts the packet, process it and sends it further to the destination, i.e. the packets should not reach the destination unless my script decides to.
In order to learn, I created a small prototype which detects pings and just prints "PING". I would expect ping not to work as I intercept the packets and I don't include the logic to send them to its destination. However ping is working (again, it seems as it is just sniffing/mirroring packets). My goal is that the ping packets are "trapped" in my script and I don't know how to do that. This is what I do in my current python script (I avoid writing how I do the decode for simplicity)
sock = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.ntohs(0x0003))
sock.bind((eth0, 0))
packet = sock.recvfrom(65565)
decode_eth(packet)
decode_ip(packet)
if (ipheader.ip_proto == 1):
print("\nPING")
Can somebody explain how can I achieve my goal or point me to the right documentation?
Your description seems to be different from what your title suggest. My understanding is that you want to receive, modify and possibly drop incoming network packets. And this is to be done on Linux. In that case I suggest you use a netfilter prerouting hook, which will make things a lot simpler (and likely more stable). Netfilter is well documented, a nice overview including information related to your requirements can be seen here. The important function to use is nf_register_hook(), read the answer to this question to get an idea of how to set things up.
I suppose that your Linux box is configured as a router (not a bridge). The packet will pass through your Linux because you have enabled IP Forwarding. So there are two solution:
Solution 1:
Disable IP Forwarding and then receive the packet from one interface and do the appropriate task (forwarding to another interface or dropping it).
Solution 2:
Use NetFilterQueue.
Install it on your Linux box (Debian/Ubuntu in my example):
apt-get install build-essential python-dev libnetfilter-queue-dev
Use iptables to send packets coming from input interface (eth0 in my example):
iptables -I INPUT -i eth0 -j NFQUEUE --queue-num 1
Run this script to handle packets forwarded to the Queue No.1 :
from netfilterqueue import NetfilterQueue
def print_and_accept(pkt):
print pkt
pkt.accept()
nfqueue = NetfilterQueue()
nfqueue.bind(1, print_and_accept)
try:
nfqueue.run()
except KeyboardInterrupt:
print
Note that pkt.drop() cause dropping the packet. Also you should accept/drop every packet.

How to create a kernel module that can intercept all packets coming to/from a network interface

I have 2 port NIC on my system - eth0 and eth1 as seen by Linux.
I want to intercept all packets coming in/to eth0, send them out through eth1 to an external device connected to the same switch as eth1 is. So I need to slap on an additional header to make it reach the correct external device.
I know that there is a concept of network taps that both the transmit and receive code in the kernel send to, but how do I create one? Also I want to capture not just IP, but all ethernet packets, I know NETFILTER_HOOK would have helped me get me IPv4 packets.
The can be readily implemented with a rx_handler:
static rx_handler_result_t handle_frame(struct sk_buff **pskb)
{
struct sk_buff *skb = *pskb;
struct net_device *whereto_dev;
skb = skb_share_check(skb, GFP_ATOMIC);
if (unlikely(!skb))
return RX_HANDLER_CONSUMED;
*pskb = skb;
whereto_dev = rcu_dereference(skb->dev->rx_handler_data);
skb->dev = whereto_dev;
return RX_HANDLER_ANOTHER; /* Do another round in receive path */
}
They are registered via netdev_rx_handler_register(slave_dev, handle_frame, whereto). See the bonding or my uman driver for example usage.
dev_add_pack would work too, but it seems, apart from af_packet.c, all all-packet-catching users of dev_add_pack have been migrated to use rx_handlers, e.g. https://patchwork.ozlabs.org/patch/367236/. The patch's discussion suggests this might be more effecient.

Resources