First, CircuitPython has great networking support! It is amazing how much you can do with it. While I'm aware of wifi.radio.ping, I've recently been attempting to manually create an ICMP ping as a RAW packet and have run into a bit of a speed bump. I think I see a fairly simple possible solution that I'll describe below. Note that I'm using CircuitPython 9 on a RPi Pico.
The issue:
To create an ICMP packet, in addition to specifying a socket type of SOCK_RAW, you also need to be able to specify the protocol value (1 for ICMP). CPython includes the 'proto' parameter to pass this information. CircuitPython's implementation doesn't allow this to be passed, and in the source hard codes the value to 0. The signatures of both versions are:
CircuitPython: socketpool.SocketPool().socket(family: int = AF_INET, type: int = SOCK_STREAM)
CPython: socket.socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None)
Using wireshark, I've verified that a manually created ICMP packet contains a value of 0 in the internet header in the protocol field (https://datatracker.ietf.org/doc/html/rfc791). This protocol field is the one that would typically be filled with the value passed to socket in the 'proto' parameter WHEN type=SOCK_RAW.
The enhancement:
After examining the code, I think that adding support for specifying the protocol for a raw packet would require the following:
- Modify 'socketpool.SocketPool().socket' to match CPython by adding a 'proto=0' param after the 'type'.
- Modify the block of code in circuitpython/ports/raspberrypi/common-hal/socketpool/Socket.C in the 'socketpool_socket' function to change:
case SOCKETPOOL_SOCK_RAW: {
socket->pcb.raw = raw_new(0);
break;
}
to:
case SOCKETPOOL_SOCK_RAW: {
socket->pcb.raw = raw_new(proto);
break;
}
- In the espressif port, the 'proto' parameter would have to be added as above, and it looks like the _socketpool_socket function should have the following change:
} else { // SOCKETPOOL_SOCK_RAW
socket_type = SOCK_RAW;
}
to:
} else { // SOCKETPOOL_SOCK_RAW
socket_type = SOCK_RAW;
ipproto = proto; // Assuming that 'proto' is the name of the new parameter added
}
Comments:
I think that those changes along with the the associated ones required by the CircuitPython/MicroPython architecture to modify the parameters to the 'socket' function would extend the capability of CP RAW sockets and bring it a little closer to CPython. I'll be the first to admit I'm not familiar enough with the CP C-code architecture to know if there are other cans of worms this opens. From the pure Python perspective, the addition of the 'proto' parameter to the 'socket' method shouldn't break existing code since it has a default value of 0 and is at the end of the parameter list.
Regardless of whether this gets adopted or not, kudos to the CircuitPython team for all of the hard work on this code base. It is a joy to use!
First, CircuitPython has great networking support! It is amazing how much you can do with it. While I'm aware of wifi.radio.ping, I've recently been attempting to manually create an ICMP ping as a RAW packet and have run into a bit of a speed bump. I think I see a fairly simple possible solution that I'll describe below. Note that I'm using CircuitPython 9 on a RPi Pico.
The issue:
To create an ICMP packet, in addition to specifying a socket type of SOCK_RAW, you also need to be able to specify the protocol value (1 for ICMP). CPython includes the 'proto' parameter to pass this information. CircuitPython's implementation doesn't allow this to be passed, and in the source hard codes the value to 0. The signatures of both versions are:
CircuitPython: socketpool.SocketPool().socket(family: int = AF_INET, type: int = SOCK_STREAM)
CPython: socket.socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None)
Using wireshark, I've verified that a manually created ICMP packet contains a value of 0 in the internet header in the protocol field (https://datatracker.ietf.org/doc/html/rfc791). This protocol field is the one that would typically be filled with the value passed to socket in the 'proto' parameter WHEN type=SOCK_RAW.
The enhancement:
After examining the code, I think that adding support for specifying the protocol for a raw packet would require the following:
to:
to:
Comments:
I think that those changes along with the the associated ones required by the CircuitPython/MicroPython architecture to modify the parameters to the 'socket' function would extend the capability of CP RAW sockets and bring it a little closer to CPython. I'll be the first to admit I'm not familiar enough with the CP C-code architecture to know if there are other cans of worms this opens. From the pure Python perspective, the addition of the 'proto' parameter to the 'socket' method shouldn't break existing code since it has a default value of 0 and is at the end of the parameter list.
Regardless of whether this gets adopted or not, kudos to the CircuitPython team for all of the hard work on this code base. It is a joy to use!