/**
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define _GNU_SOURCE
#define ARRAY_SIZE(__a) (sizeof(__a) / sizeof((__a)[0]))
#include <errno.h>
#include <linux/filter.h>
#include <linux/netlink.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
static struct sock_filter nlattr[] = {
{ 0000, 0, 0, 0x87654321 },
{ 0x01, 0, 0, 0x0000002a },
{ 0x20, 0, 0, 0xfffff00c },
{ 0x16, 0, 0, 0000000000 },
};
static struct sock_fprog bpf_nlattr = {
.len = ARRAY_SIZE(nlattr),
.filter = nlattr,
};
static struct sock_filter nlattr_nest[] = {
{ 0000, 0, 0, 0x87654321 },
{ 0x01, 0, 0, 0x0000002a },
{ 0x20, 0, 0, 0xfffff010 },
{ 0x16, 0, 0, 0000000000 },
};
static struct sock_fprog bpf_nlattr_nest = {
.len = ARRAY_SIZE(nlattr_nest),
.filter = nlattr_nest,
};
static struct sock_filter nest_rem[] = {
{ 0000, 0, 0, 0000000000 },
{ 0x01, 0, 0, 0x0000002a },
{ 0x20, 0, 0, 0xfffff010 },
{ 0x16, 0, 0, 0000000000 },
};
static struct sock_fprog bpf_nest_rem = {
.len = ARRAY_SIZE(nest_rem),
.filter = nest_rem,
};
static int send_receive_packet(int s[2], const void* pkt, int len)
{
char tmp[1024];
ssize_t ret;
ret = send(s[1], pkt, len, 0);
if (ret != len) {
return -1;
}
ret = recv(s[0], tmp, len, MSG_DONTWAIT);
if (ret < 0 && errno == EAGAIN)
return 0;
return 1;
}
int main()
{
struct nlattr chkrem[2] = {
[0] = {
.nla_len = 0xfff0,
.nla_type = 0,
},
[1] = {
.nla_len = sizeof(struct nlattr),
.nla_type = 42,
},
};
__u16 chksz = 0xfefe;
int s[2], ret;
ret = socketpair(AF_UNIX, SOCK_DGRAM, 0, s);
if (ret) {
return -1;
}
ret = setsockopt(s[0], SOL_SOCKET, SO_ATTACH_FILTER,
&bpf_nlattr, sizeof(bpf_nlattr));
if (ret < 0) {
return -1;
}
ret = send_receive_packet(s, &chksz, sizeof(chksz));
if (ret) {
ret = 113;
goto out;
}
ret = setsockopt(s[0], SOL_SOCKET, SO_ATTACH_FILTER,
&bpf_nlattr_nest, sizeof(bpf_nlattr_nest));
if (ret < 0) {
return -1;
}
ret = send_receive_packet(s, &chksz, sizeof(chksz));
if (ret) {
ret = 113;
goto out;
}
ret = setsockopt(s[0], SOL_SOCKET, SO_ATTACH_FILTER,
&bpf_nest_rem, sizeof(bpf_nest_rem));
if (ret < 0) {
return -1;
}
ret = send_receive_packet(s, chkrem, sizeof(chkrem));
if(ret){
ret = 113;
}
out:
return ret;
}