diff --git a/src/l2_packet/l2_packet.h b/src/l2_packet/l2_packet.h index dd825b568..f391f3682 100644 --- a/src/l2_packet/l2_packet.h +++ b/src/l2_packet/l2_packet.h @@ -39,6 +39,10 @@ struct l2_ethhdr { #pragma pack(pop) #endif /* _MSC_VER */ +enum l2_packet_filter_type { + L2_PACKET_FILTER_DHCP, +}; + /** * l2_packet_init - Initialize l2_packet interface * @ifname: Interface name @@ -121,4 +125,16 @@ int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len); */ void l2_packet_notify_auth_start(struct l2_packet_data *l2); +/** + * l2_packet_set_packet_filter - Set socket filter for l2_packet + * @l2: Pointer to internal l2_packet data from l2_packet_init() + * @type: enum l2_packet_filter_type, type of filter + * Returns: 0 on success, -1 on failure + * + * This function is used to set the socket filter for l2_packet socket. + * + */ +int l2_packet_set_packet_filter(struct l2_packet_data *l2, + enum l2_packet_filter_type type); + #endif /* L2_PACKET_H */ diff --git a/src/l2_packet/l2_packet_freebsd.c b/src/l2_packet/l2_packet_freebsd.c index 2e9a04c89..d87c32b2c 100644 --- a/src/l2_packet/l2_packet_freebsd.c +++ b/src/l2_packet/l2_packet_freebsd.c @@ -308,3 +308,10 @@ int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len) void l2_packet_notify_auth_start(struct l2_packet_data *l2) { } + + +int l2_packet_set_packet_filter(struct l2_packet_data *l2, + enum l2_packet_filter_type type) +{ + return -1; +} diff --git a/src/l2_packet/l2_packet_linux.c b/src/l2_packet/l2_packet_linux.c index 1419830db..fcbf7e040 100644 --- a/src/l2_packet/l2_packet_linux.c +++ b/src/l2_packet/l2_packet_linux.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "common.h" #include "eloop.h" @@ -28,6 +29,32 @@ struct l2_packet_data { * buffers */ }; +/* Generated by 'sudo tcpdump -s 3000 -dd greater 278 and ip and udp and + * src port bootps and dst port bootpc' + */ +static struct sock_filter dhcp_sock_filter_insns[] = { + { 0x80, 0, 0, 0x00000000 }, + { 0x35, 0, 12, 0x00000116 }, + { 0x28, 0, 0, 0x0000000c }, + { 0x15, 0, 10, 0x00000800 }, + { 0x30, 0, 0, 0x00000017 }, + { 0x15, 0, 8, 0x00000011 }, + { 0x28, 0, 0, 0x00000014 }, + { 0x45, 6, 0, 0x00001fff }, + { 0xb1, 0, 0, 0x0000000e }, + { 0x48, 0, 0, 0x0000000e }, + { 0x15, 0, 3, 0x00000043 }, + { 0x48, 0, 0, 0x00000010 }, + { 0x15, 0, 1, 0x00000044 }, + { 0x6, 0, 0, 0x00000bb8 }, + { 0x6, 0, 0, 0x00000000 }, +}; + +static const struct sock_fprog dhcp_sock_filter = { + .len = ARRAY_SIZE(dhcp_sock_filter_insns), + .filter = dhcp_sock_filter_insns, +}; + int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr) { @@ -202,3 +229,28 @@ int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len) void l2_packet_notify_auth_start(struct l2_packet_data *l2) { } + + +int l2_packet_set_packet_filter(struct l2_packet_data *l2, + enum l2_packet_filter_type type) +{ + const struct sock_fprog *sock_filter; + + switch (type) { + case L2_PACKET_FILTER_DHCP: + sock_filter = &dhcp_sock_filter; + break; + default: + return -1; + } + + if (setsockopt(l2->fd, SOL_SOCKET, SO_ATTACH_FILTER, + sock_filter, sizeof(struct sock_fprog))) { + wpa_printf(MSG_ERROR, + "l2_packet_linux: setsockopt(SO_ATTACH_FILTER) failed: %s", + strerror(errno)); + return -1; + } + + return 0; +} diff --git a/src/l2_packet/l2_packet_ndis.c b/src/l2_packet/l2_packet_ndis.c index 23b8ddcc9..39a62a0ab 100644 --- a/src/l2_packet/l2_packet_ndis.c +++ b/src/l2_packet/l2_packet_ndis.c @@ -514,3 +514,10 @@ int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len) void l2_packet_notify_auth_start(struct l2_packet_data *l2) { } + + +int l2_packet_set_packet_filter(struct l2_packet_data *l2, + enum l2_packet_filter_type type) +{ + return -1; +} diff --git a/src/l2_packet/l2_packet_none.c b/src/l2_packet/l2_packet_none.c index 6896c4e4e..0501925c6 100644 --- a/src/l2_packet/l2_packet_none.c +++ b/src/l2_packet/l2_packet_none.c @@ -116,3 +116,10 @@ void l2_packet_notify_auth_start(struct l2_packet_data *l2) { /* This function can be left empty */ } + + +int l2_packet_set_packet_filter(struct l2_packet_data *l2, + enum l2_packet_filter_type type) +{ + return -1; +} diff --git a/src/l2_packet/l2_packet_pcap.c b/src/l2_packet/l2_packet_pcap.c index 45aef56bc..f06417254 100644 --- a/src/l2_packet/l2_packet_pcap.c +++ b/src/l2_packet/l2_packet_pcap.c @@ -378,3 +378,10 @@ void l2_packet_notify_auth_start(struct l2_packet_data *l2) l2, l2->pcap); #endif /* CONFIG_WINPCAP */ } + + +int l2_packet_set_packet_filter(struct l2_packet_data *l2, + enum l2_packet_filter_type type) +{ + return -1; +} diff --git a/src/l2_packet/l2_packet_privsep.c b/src/l2_packet/l2_packet_privsep.c index 6b117ca2b..8b9524762 100644 --- a/src/l2_packet/l2_packet_privsep.c +++ b/src/l2_packet/l2_packet_privsep.c @@ -259,3 +259,10 @@ void l2_packet_notify_auth_start(struct l2_packet_data *l2) { wpa_priv_cmd(l2, PRIVSEP_CMD_L2_NOTIFY_AUTH_START, NULL, 0); } + + +int l2_packet_set_packet_filter(struct l2_packet_data *l2, + enum l2_packet_filter_type type) +{ + return -1; +}