I am trying to access the __sk_buff struct passed within the consume_skb tracepoint. However nothing I tried has worked so far. I am running the kernel version 5.4.0. This is what I tried so far, and in what it resulted:
Loader
gist
Direct access
SEC("tracepoint/skb/consume_skb")
int handle_skb(struct __sk_buff *skb)
{
void *data = (void *)(long)skb->data;
void *data_end = (void *)(long)skb->data_end;
struct ethhdr *eth = data;
struct iphdr *iph = data + sizeof(*eth);
if (data + sizeof(*eth) > data_end)
return 0;
if (data + sizeof(*eth) + sizeof(*iph) > data_end)
return 0;
bpf_trace_printk("%x\n", eth->h_proto);
return 0;
}
results in:
libbpf: prog 'handle_skb': BPF program load failed: Permission denied
libbpf: prog 'handle_skb': -- BEGIN PROG LOAD LOG --
; void *data = (void *)(long)skb->data;
0: (61) r2 = *(u32 *)(r1 +76)
; void *data_end = (void *)(long)skb->data_end;
1: (61) r1 = *(u32 *)(r1 +80)
; struct iphdr *iph = data + sizeof(*eth);
2: (bf) r3 = r2
3: (07) r3 += 14
; if (data + sizeof(*eth) > data_end)
4: (2d) if r3 > r1 goto pc+7
R1_w=inv(id=0,umax_value=4294967295,var_off=(0x0; 0xffffffff)) R2_w=inv(id=0,umax_value=4294967295,var_off=(0x0; 0xffffffff)) R3_w=inv(id=0,umin_value=14,umax_value=4294967309,var_off=(0x0; 0x1ffffffff)) R10=fp0
;
5: (bf) r3 = r2
6: (07) r3 += 34
; if (data + sizeof(*eth) > data_end)
7: (2d) if r3 > r1 goto pc+4
R1_w=inv(id=0,umax_value=4294967295,var_off=(0x0; 0xffffffff)) R2_w=inv(id=0,umax_value=4294967295,var_off=(0x0; 0xffffffff)) R3_w=inv(id=0,umin_value=34,umax_value=4294967329,var_off=(0x0; 0x1ffffffff)) R10=fp0
; bpf_trace_printk("%x\n", eth->h_proto);
8: (69) r2 = *(u16 *)(r2 +12)
R2 invalid mem access 'inv'
processed 9 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0
-- END PROG LOAD LOG --
libbpf: failed to load program 'handle_skb'
libbpf: failed to load object 'skb_bpf'
libbpf: failed to load BPF skeleton 'skb_bpf': -13
Failed to load and verify BPF skeleton
The way I understand it, is that direct access to skb is not allowed in this context (why?).
bpf_skb_load_bytes
SEC("tracepoint/skb/consume_skb")
int handle_skb(struct __sk_buff *skb)
{
struct ethhdr *eth;
int ret;
ret = skb_load_bytes(skb, 0, eth, sizeof(struct ethhdr));
//Or alternatively
//ret = bpf_skb_load_bytes(skb, 0, eth, sizeof(struct ethhdr));
if (!ret)
{
return 0;
}
bpf_trace_printk("%x\n", eth->h_proto);
return 0;
}
which results in:
libbpf: prog 'handle_skb': BPF program load failed: Invalid argument
libbpf: prog 'handle_skb': -- BEGIN PROG LOAD LOG --
; ret = bpf_skb_load_bytes(skb, 0, eth, sizeof(struct ethhdr));
0: (b7) r2 = 0
1: (b7) r4 = 14
2: (85) call bpf_skb_load_bytes#26
unknown func bpf_skb_load_bytes#26
processed 3 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0
-- END PROG LOAD LOG --
libbpf: failed to load program 'handle_skb'
libbpf: failed to load object 'skb_bpf'
libbpf: failed to load BPF skeleton 'skb_bpf': -22
Failed to load and verify BPF skeleton
This confuses me even more, as bpf_skb_load_bytes should be an available helper function.
Now I am doubting how to even access and read (not even write) the __sk_buff.
Is there just no way? Or have I missed something?
There are a few things going on here. First is that the argument to the tracepoint is of type struct sk_buff, not struct __sk_buff. I believe you have to use thebpf_probe_read helper to read memory the pointer is pointing to.
Second is that bpf_skb_load_bytes would only work with a __sk_buff. Besides, not all helpers are available for each program type, tracing programs can't use the bpf_skb_load_bytes helper. Here is the code that lists all available helpers for tracepoint programs:
https://elixir.bootlin.com/linux/v5.18.1/source/kernel/trace/bpf_trace.c#L1415
https://elixir.bootlin.com/linux/v5.18.1/source/kernel/trace/bpf_trace.c#L1167
Related
I like to test this function bpf_spin_lock in ebpf kernel program.
This is my code
#include <stddef.h>
#include <linux/bpf.h>
#include <linux/in.h>
#include <linux/if_ether.h>
#include <linux/if_packet.h>
#include <linux/ipv6.h>
#include <linux/icmpv6.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_endian.h>
/* Defines xdp_stats_map from packet04 */
#include "../common/xdp_stats_kern_user.h"
#include "../common/xdp_stats_kern.h"
#include <../common/parsing_helpers.h>
#include <bpf/bpf_helpers.h>
#define ETH_ALEN 6
#define MAX_ENTRIES 1000
/*struct {
__uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS);
__type(key, __u32);
__type(value, __u64);
__uint(max_entries, MAX_ENTRIES);
} hash_map SEC(".maps");
*/
struct hash_elem {
int cnt;
struct bpf_spin_lock lock;
};
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__type(key, __u32);
__type(value, struct hash_elem);
__uint(max_entries, 100);
} hash_map SEC(".maps");
struct a{struct bpf_spin_lock lock;};
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__type(key, __u32);
__type(value, long);
__uint(max_entries, 2);
} hash_map1 SEC(".maps");
//static __u32 i=0;
SEC("xdp")
int xdp_prog_simple(struct xdp_md *ctx)
{
struct hash_elem val;
bpf_spin_lock(&val.lock);
val.cnt++;
bpf_spin_unlock(&val.lock);
bpf_map_update_elem(&hash_map, &val.cnt, &val, BPF_ANY);
return XDP_PASS;
}
But to load program there is error
libbpf: load bpf program failed: Permission denied
libbpf: -- BEGIN DUMP LOG ---
libbpf:
; bpf_spin_lock(&val.lock);
0: (bf) r6 = r10
1: (07) r6 += -4
; bpf_spin_lock(&val.lock);
2: (bf) r1 = r6
3: (85) call bpf_spin_lock#93
R1 type=fp expected=map_value
processed 4 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0
libbpf: -- END LOG --
libbpf: failed to load program 'xdp'
libbpf: failed to load object './k.o'
ERR: loading BPF-OBJ file(./k.o) (-22): Invalid argument
ERR: loading file: ./k.o
The last line of function instructions are
; bpf_spin_lock(&val.lock);
2: (bf) r1 = r6
3: (85) call bpf_spin_lock#93
R1 type=fp expected=map_value
is it saying bpf_spin_lock expects map? but this makes no sense, or correct me if its saying something, what the error means and the function assembly language dump
Can I use spin lock from the api in ebpf/xdp programs?
trace_output_kern.c traces sys_write syscall and prints the pid in userland:
#include <linux/ptrace.h>
#include <linux/version.h>
#include <uapi/linux/bpf.h>
#include "bpf_helpers.h"
struct bpf_map_def SEC("maps") my_map = {
.type = BPF_MAP_TYPE_PERF_EVENT_ARRAY,
.key_size = sizeof(int),
.value_size = sizeof(u32),
.max_entries = 2,
};
SEC("kprobe/sys_write")
int bpf_prog1(struct pt_regs *ctx)
{
struct S {
u64 pid;
u64 cookie;
} data;
data.pid = bpf_get_current_pid_tgid();
data.cookie = 0x12345678;
bpf_perf_event_output(ctx, &my_map, 0, &data, sizeof(data));
return 0;
}
char _license[] SEC("license") = "GPL";
u32 _version SEC("version") = LINUX_VERSION_CODE;
sys_read has a signature of sys_read(unsigned int fd, char __user *buf, size_t count);, and currently we only see the PID. The premise of tracing is that we get to intercept, and inspect the arguments. I was trying to see the arguments that gets passed on as well.
If I change that struct S to hold a char array to hold char *buf as
struct S {
u64 pid;
u64 cookie;
char bleh[128]; //<-- added this
} data;
it is throwing a fit:
/usr/src/linux-5.4/samples/bpf# ./trace_output
bpf_load_program() err=13
0: (bf) r6 = r1
1: (85) call bpf_get_current_pid_tgid#14
2: (b7) r1 = 305419896
3: (7b) *(u64 *)(r10 -136) = r1
4: (7b) *(u64 *)(r10 -144) = r0
5: (bf) r4 = r10
6: (07) r4 += -144
7: (bf) r1 = r6
8: (18) r2 = 0xffff8975bd44aa00
10: (b7) r3 = 0
11: (b7) r5 = 144
12: (85) call bpf_perf_event_output#25
invalid indirect read from stack off -144+16 size 144
processed 12 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0
0: (bf) r6 = r1
1: (85) call bpf_get_current_pid_tgid#14
2: (b7) r1 = 305419896
3: (7b) *(u64 *)(r10 -136) = r1
4: (7b) *(u64 *)(r10 -144) = r0
5: (bf) r4 = r10
6: (07) r4 += -144
7: (bf) r1 = r6
8: (18) r2 = 0xffff8975bd44aa00
10: (b7) r3 = 0
11: (b7) r5 = 144
12: (85) call bpf_perf_event_output#25
invalid indirect read from stack off -144+16 size 144
processed 12 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0
if sys_write is a bad (question) example, I've been also trying to trace sys_execve, which has an arg list of
asmlinkage long sys_execve(const char __user *filename,
const char __user *const __user *argv,
const char __user *const __user *envp);
Please point me the correct direction, thanks!
Edit 1
How do I intercept the arguments that was used for __x64_sys_execve?
When I try this below,
#include <linux/ptrace.h>
#include <linux/version.h>
#include <uapi/linux/bpf.h>
#include "bpf_helpers.h"
struct bpf_map_def SEC("maps") my_map = {
.type = BPF_MAP_TYPE_PERF_EVENT_ARRAY,
.key_size = sizeof(int),
.value_size = sizeof(u32),
.max_entries = 2,
};
//SEC("kprobe/sys_write")
SEC("kprobe/__x64_sys_execve")
/* Signature of sys_execve:
asmlinkage long sys_execve(const char __user *filename,
const char __user *const __user *argv,
const char __user *const __user *envp);
*/
int bpf_prog1(struct pt_regs *ctx, const char *filename)
{
struct S {
u64 pid;
u64 cookie;
char bleh[128];
} data;
data.pid = bpf_get_current_pid_tgid();
data.cookie = 0x12345678;
//bpf_get_current_comm(&data.bleh, 128);
bpf_probe_read(&data.bleh, 128, (void *)filename);
bpf_perf_event_output(ctx, &my_map, 0, &data, sizeof(data));
return 0;
}
char _license[] SEC("license") = "GPL";
u32 _version SEC("version") = LINUX_VERSION_CODE;
It blows up thusly:
/usr/src/linux-5.4/samples/bpf# ./borky
bpf_load_program() err=13
0: (bf) r6 = r2
R2 !read_ok
processed 1 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0
0: (bf) r6 = r2
R2 !read_ok
processed 1 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0
The first part of your question was answered by pchaigno: if you extend your struct S and try to read it (bpf_perf_event_output(ctx, &my_map, 0, &data, sizeof(data));) without having initialised it, the verifier complains, because reading uninitialised memory from the kernel introduces a security risk. What you could do is, for example, zero the whole struct when declaring it:
struct S {
u64 pid;
u64 cookie;
char bleh[128];
} data = {0};
Regarding the second part of your question with sys_execve, it turns out you cannot pass the syscall arguments to your function bpf_prog1() as you try to do. Your function should only take the struct pt_regs *ctx.
The confusion likely comes from the syntax used in bcc, where arguments are passed this way, but it is important to understand that bcc rewrites some parts under the hood, in particular this thing about accessing the arguments.
What you could use instead is the set of PT_REGS_PARM*(ctx) macros that are specifically defined to access the arguments of the probed function, from the relevant computer registers (example, definition). I think bcc also uses them when doing its rewriting job, but you wouldn't see it.
I am using gdb to debug a code that starts a timer. When the timer rings in gdb I always end up at instruction timer_settime+16.
Is this expected behavior?
As an example I slightly modified the code of timer_settime man page. The idea is to pass two arguments: a string of integers and a nsec value. The code launches the timer to ring after nsec, then copies the string.
I expected that by incrementing the nsec value, gdb stopped at different code lines, to end up inside the copy loop. However it always stops at .
So is this expected behavior?
Is it documented somewhere?
Is there a way to achieve what I expected (i.e.: launch a timer that when ring makes gdb stops where the program was just before (or after) the signal)? (always with nsec granularity).
Code:
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
#include <time.h>
#define CLOCKID CLOCK_REALTIME
#define SIG SIGUSR1
#define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \
} while (0)
unsigned char OUT[32];
unsigned char IN[32];
unsigned char ascii2hex(char in){
unsigned char out;
if( ('0' <= in) && (in <= '9') )
out = in - '0';
if( ('A' <= in) && (in <= 'F') )
out = in - 'A' + 10;
if( ('a' <= in) && (in <= 'f') )
out = in - 'a' + 10;
return out;
}
void asciiStr2hex(char * in, unsigned char * out, unsigned int len){
int i = 0;
int j = 0;
for( i = 0; i < len; i+=2){
out[j++] = (ascii2hex(in[i ]) << 4) + ascii2hex(in[i+1]);
}
}
void testcode(unsigned char *out, unsigned char *in, unsigned int len){
unsigned int i;
for (i=0;i<len;i++)
out[i] = in[i];
}
static void print_siginfo(siginfo_t *si)
{
timer_t *tidp;
int or;
tidp = si->si_value.sival_ptr;
printf(" sival_ptr = %p; ", si->si_value.sival_ptr);
printf(" *sival_ptr = 0x%lx\n", (long) *tidp);
or = timer_getoverrun(*tidp);
if (or == -1)
errExit("timer_getoverrun");
else
printf(" overrun count = %d\n", or);
}
static void handler(int sig, siginfo_t *si, void *uc)
{
/* Note: calling printf() from a signal handler is not
strictly correct, since printf() is not async-signal-safe;
see signal(7) */
printf("Caught signal %d\n", sig);
print_siginfo(si);
signal(sig, SIG_IGN);
}
int main(int argc, char *argv[])
{
timer_t timerid;
struct sigevent sev;
struct itimerspec its;
long long freq_nanosecs;
//sigset_t mask;
struct sigaction sa;
if (argc != 3) {
fprintf(stderr, "Usage: %s <16byte> <time-nanosecs>\n",
argv[0]);
exit(EXIT_FAILURE);
}
asciiStr2hex(argv[1], IN, 32);
/* Establish handler for timer signal */
printf("Establishing handler for signal %d\n", SIG);
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = handler;
sigemptyset(&sa.sa_mask);
if (sigaction(SIG, &sa, NULL) == -1)
errExit("sigaction");
/* Block timer signal temporarily */
/* printf("Blocking signal %d\n", SIG);
sigemptyset(&mask);
sigaddset(&mask, SIG);
if (sigprocmask(SIG_SETMASK, &mask, NULL) == -1)
errExit("sigprocmask");
*/
/* Create the timer */
sev.sigev_notify = SIGEV_SIGNAL;
sev.sigev_signo = SIG;
sev.sigev_value.sival_ptr = &timerid;
if (timer_create(CLOCKID, &sev, &timerid) == -1)
errExit("timer_create");
printf("timer ID is 0x%lx\n", (long) timerid);
/* Start the timer */
freq_nanosecs = atoll(argv[2]);
its.it_value.tv_sec = freq_nanosecs / 1000000000;
its.it_value.tv_nsec = freq_nanosecs % 1000000000;
its.it_interval.tv_sec = its.it_value.tv_sec;
its.it_interval.tv_nsec = its.it_value.tv_nsec;
if (timer_settime(timerid, 0, &its, NULL) == -1)
errExit("timer_settime");
/* Sleep for a while; meanwhile, the timer may expire
multiple times */
printf("Sleeping for %d seconds\n", atoi(argv[1]));
testcode(OUT, IN, 16);
/* Unlock the timer signal, so that timer notification
can be delivered */
/* printf("Unblocking signal %d\n", SIG);
if (sigprocmask(SIG_UNBLOCK, &mask, NULL) == -1)
errExit("sigprocmask");
*/
exit(EXIT_SUCCESS);
}
When debug into gdb with r 00112233445566778899001122334455 2
I obtain:
Program received signal SIGUSR1, User defined signal 1.
0x76fc7c38 in timer_settime () from /lib/arm-linux-gnueabihf/librt.so.1
(gdb) x/30i $pc
=> 0x76fc7c38 <timer_settime+16>: cmn r0, #4096 ; 0x1000
0x76fc7c3c <timer_settime+20>: mov r4, r0
0x76fc7c40 <timer_settime+24>: bhi 0x76fc7c4c <timer_settime+36>
0x76fc7c44 <timer_settime+28>: mov r0, r4
0x76fc7c48 <timer_settime+32>: pop {r3, r4, r7, pc}
0x76fc7c4c <timer_settime+36>: bl 0x76fc55b4
0x76fc7c50 <timer_settime+40>: rsb r3, r4, #0
0x76fc7c54 <timer_settime+44>: mvn r4, #0
0x76fc7c58 <timer_settime+48>: str r3, [r0]
0x76fc7c5c <timer_settime+52>: b 0x76fc7c44 <timer_settime+28>
0x76fc7c60 <timer_settime+56>: andeq r0, r0, r2, lsl #2
0x76fc7c64: push {r4, r5, r6, r7, r8, r9, r10, lr}
0x76fc7c68: sub sp, sp, #600 ; 0x258
0x76fc7c6c: ldr r4, [pc, #340] ; 0x76fc7dc8
0x76fc7c70: add r1, sp, #512 ; 0x200
0x76fc7c74: add r4, pc, r4
0x76fc7c78: mov r0, r4
0x76fc7c7c: bl 0x76fc56b0
0x76fc7c80: cmp r0, #0
0x76fc7c84: bne 0x76fc7c98
0x76fc7c88: ldr r2, [sp, #512] ; 0x200
0x76fc7c8c: ldr r3, [pc, #312] ; 0x76fc7dcc
0x76fc7c90: cmp r2, r3
0x76fc7c94: beq 0x76fc7d94
0x76fc7c98: ldr r5, [pc, #304] ; 0x76fc7dd0
0x76fc7c9c: ldr r0, [pc, #304] ; 0x76fc7dd4
0x76fc7ca0: add r5, pc, r5
0x76fc7ca4: add r0, pc, r0
0x76fc7ca8: mov r1, r5
0x76fc7cac: bl 0x76fc5524
I am running such code on a raspberry pi, but I'am pretty sure I had the same behavior on another linux machine x86_64.
I have tested with "handle stop SIGUSR1".
I finally found that the problem was that I have to set unwindonsignal off in gdb to obtain the behavior I expected.
I am trying to use nl_recvmsgs as a blocking function to receive Netlink messages from a kernel module.
In my example the client sends a message to the kernel and then it calls nl_recvmsgs_report()(is equal to nl_recvmsgs). Then the kernel module sends a return message. That message is successful received by the client.
Now I want the client to listen for more messages in the future and call nl_recvmsgs_report() again. The kernel did not sent any second message. But somehow an ERRORMSG is received by the client. This leads to a SEGFAULT at the client because he tries to parse the message not as an ERRORMSG.
If I check if the message type is 2 , and skip the message parsing, a third call of nl_recvmsgs_report() blocks perfectly fine.
Does someone know why the client receives this ERRORMSG?
Have a look at my github branch. Just call make, sudo insmod nlk.ko, ./nlclient I copied only the relevant parts here.
client code
nlclient.c main() sending and receiving part:
// setup netlink socket
sk = nl_socket_alloc();
nl_socket_disable_seq_check(sk); // disable sequence number check
genl_connect(sk);
int id = genl_ctrl_resolve(sk, DEMO_FAMILY_NAME);
struct nl_msg * msg;
// create a messgae
msg = nlmsg_alloc();
genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, id, 0, // hdrlen
0, // flags
DEMO_CMD, // numeric command identifier
DEMO_VERSION // interface version
);
nla_put_string(msg, DEMO_ATTR1_STRING, "hola");
nla_put_u16(msg, DEMO_ATTR2_UINT16, 0xf1);
// send it
nl_send_auto(sk, msg);
// handle reply
struct nl_cb * cb = NULL;
cb = nl_cb_alloc(NL_CB_CUSTOM);
//nl_cb_set_all(cb, NL_CB_DEBUG, NULL, NULL);
nl_cb_set_all(cb, NL_CB_CUSTOM, cb_handler, &cbarg);
nl_cb_err(cb, NL_CB_DEBUG, NULL, NULL);
int nrecv = nl_recvmsgs_report(sk, cb);
printf("cbarg %d nrecv %d\n", cbarg, nrecv);
printf("First test if it blocks here for incoming messages:\n");
nrecv = nl_recvmsgs_report(sk, cb);
printf("cbarg %d nrecv %d\n", cbarg, nrecv);
printf("Second test if it blocks here for incoming messages:\n");
nrecv = nl_recvmsgs_report(sk, cb);
printf("cbarg %d nrecv %d\n", cbarg, nrecv);
nlclient.c cb_handler() parsing the header and message
struct nlmsghdr * hdr = nlmsg_hdr(msg);
struct genlmsghdr * gnlh = nlmsg_data(hdr);
nl_msg_dump(msg, stderr);
if (hdr->nlmsg_type == 2) {
printf("hdr->nlmsg_type is ERROR. Skipping message parsing!\n");
} else {
int valid =
genlmsg_validate(hdr, 0, DEMO_ATTR_MAX, demo_gnl_policy);
printf("valid %d %s\n", valid, valid ? "ERROR" : "OK");
// one way
struct nlattr * attrs[DEMO_ATTR_MAX + 1];
if (genlmsg_parse(hdr, 0, attrs, DEMO_ATTR_MAX, demo_gnl_policy) < 0)
{
printf("genlsmg_parse ERROR\n");
}
else
{
printf("genlsmg_parse OK\n");
printf("attr1 %s\n", nla_get_string(attrs[DEMO_ATTR1_STRING]));
printf("attr2 %x\n", nla_get_u16(attrs[DEMO_ATTR2_UINT16]));
struct attr_custom * cp = (struct attr_custom *) nla_data(attrs[DEMO_ATTR3_CUSTOM]);
printf("attr3 %d %ld %f %lf\n", cp->a, cp->b, cp->c,cp->d);
}
}
// another way
printf("gnlh->cmd %d\n", gnlh->cmd); //--- DEMO_CMD_ECHO
int remaining = genlmsg_attrlen(gnlh, 0);
struct nlattr * attr = genlmsg_attrdata(gnlh, 0);
while (nla_ok(attr, remaining))
{
printf("remaining %d\n", remaining);
printf("attr # %p\n", attr); // nla_get_string(attr)
attr = nla_next(attr, &remaining);
}
kernel code
nlkernel.c demo_cmd() sending to client part:
/* send message back */
/* allocate some memory, since the size is not yet known use NLMSG_GOODSIZE */
skb = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
if (skb == NULL) {
goto out;
}
/* create the message */
msg_head =
genlmsg_put(skb, 0, info->snd_seq + 1, &demo_gnl_family, 0,
DEMO_CMD);
if (msg_head == NULL) {
rc = -ENOMEM;
goto out;
}
rc |= nla_put_string(skb, DEMO_ATTR1_STRING,"world");
rc |= nla_put_u16(skb, DEMO_ATTR2_UINT16, 0x1f);
cp.a = 1;
cp.b = 2;
cp.c = 3.0;
cp.d = 4.0;
rc |= nla_put(skb, DEMO_ATTR3_CUSTOM, sizeof(struct attr_custom), &cp);
if (rc != 0) {
goto out;
}
/* finalize the message */
genlmsg_end(skb, msg_head);
/* send the message back */
rc = genlmsg_unicast(&init_net, skb, info->snd_portid);
if (rc != 0) {
goto out;
}
return 0;
output
nlclient console output
./nlclient
-------------------------- BEGIN NETLINK MESSAGE ---------------------------
[NETLINK HEADER] 16 octets
.nlmsg_len = 76
.type = 27 <0x1b>
.flags = 0 <>
.seq = 1458476257
.port = 0
[GENERIC NETLINK HEADER] 4 octets
.cmd = 1
.version = 1
.unused = 0
[PAYLOAD] 56 octets
0a 00 01 00 77 6f 72 6c 64 00 00 00 06 00 02 00 ....world.......
1f 00 00 00 24 00 03 00 01 00 00 00 ff ff ff ff ....$...........
02 00 00 00 00 00 00 00 00 00 40 40 04 88 ff ff ..........##....
00 00 00 00 00 00 10 40 .......#
--------------------------- END NETLINK MESSAGE ---------------------------
valid 0 OK
genlsmg_parse OK
attr1 world
attr2 1f
attr3 1 2 3.000000 4.000000
gnlh->cmd 1
remaining 56
attr # 0x10df344
remaining 44
attr # 0x10df350
remaining 36
attr # 0x10df358
cbarg 123 nrecv 1
First test if it blocks here for incoming messages:
-------------------------- BEGIN NETLINK MESSAGE ---------------------------
[NETLINK HEADER] 16 octets
.nlmsg_len = 36
.type = 2 <ERROR>
.flags = 0 <>
.seq = 1458476256
.port = -1061151077
[ERRORMSG] 20 octets
.error = 0 "Success"
[ORIGINAL MESSAGE] 16 octets
.nlmsg_len = 16
.type = 27 <0x1b>
.flags = 5 <REQUEST,ACK>
.seq = 1458476256
.port = -1061151077
--------------------------- END NETLINK MESSAGE ---------------------------
hdr->nlmsg_type is ERROR. Skipping message parsing!
gnlh->cmd 0
cbarg 123 nrecv 1
Second test if it blocks here for incoming messages:
KERNEL syslog
kernel: [ 4694.318428] got demo_cmd
kernel: [ 4694.318430] attr1: hola
kernel: [ 4694.318431] attr2: f1
Sorry for taking so long.
The output is somewhat misleading. That's not an error message; it's an automatic ACK. Netlink defines ACKs to be "error" messages with error code 0.
(Zero is typical jargon for success in the C language.)
Since you're crafting an answer, you probably don't need ACKs anyway. You can stop your client from requesting ACKs by adding a call to nl_socket_disable_auto_ack().
I'd hack it close to sequence check disabling because it's kind of similar:
sk = nl_socket_alloc();
nl_socket_disable_seq_check(sk);
nl_socket_disable_auto_ack(sk);
genl_connect(sk);
I have my omap4460 pandaboard loaded with linux kernel 3.4.I have unbinded the driver from uart4 instance using echo -n omap_uart.3 > /sys/bus/platform/drivers/omap_uart/unbind.
I have written a new driver using simple struct file_operations
Now after the pad configuration when I do a software reset and wait for its completion the loop does not come out of the loop.
l = ioread32(io_map + 0x54);
printk(KERN_ALERT "SYSC value before = %x\n", l);
iowrite32(0x2,io_map + 0x54);
l = ioread32(io_map + 0x54);
printk(KERN_ALERT "SYSC value after = %x\n", l);
readval = ioread32(io_map + 0x58);
printk(KERN_ALERT "SYSS read value = %x\n", readval);
while((readval & 0x1)== 0);
printk(KERN_ALERT "software reset completed\n");
io_map is the address obtained from the call
io_map = ioremap(UART4_BASE,UART_SIZE);
where UART_SIZE is 0x83 a nd UART4_BASE is 0x4806eooo.
1st and 2nd printk statements give the same value 0.