Messages in this thread | | | Date | Thu, 20 Apr 2006 17:12:33 +0200 | From | "Libor Vanek" <> | Subject | Re: Connector - how to start? |
| |
Hi, I got it all finally everything working with "setsockopt" as suggested.
In case anybody else wants to experiment with connector, I attach my examples (maybe add it to Documentation/connector/?)
Anyway - there are two more issues (not bugs) which I'd like to solve: - When sending message from kernel, cn_netlink_send returns an error in case when there is no reciever - BUT user space "send" doesn't return an error when there is no reciever in kernel :-(
- How (if) can I do ACK (acknoledge received and processed message)?
Thanks for your help, Libor Vanek /* * cn_recv.c */
#include <linux/kernel.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/skbuff.h> #include <linux/timer.h>
#include <linux/connector.h>
static struct cb_id cn_recv_id = { 0x3, 0x1 }; static char cn_recv_name[] = "cn_recv";
void cn_recv_callback(void *data) { struct cn_msg *msg = (struct cn_msg *)data; printk("%s: %lu: idx=%x, val=%x, seq=%u, ack=%u, len=%d: %s\n", __func__, jiffies, msg->id.idx, msg->id.val, msg->seq, msg->ack, msg->len, (char *)msg->data); }
static int cn_recv_init(void) { int err;
err = cn_add_callback(&cn_recv_id, cn_recv_name, cn_recv_callback);
printk(KERN_INFO "cn_recv loaded, cn_add_callback retval: %i\n", err); return 0; }
static void cn_recv_fini(void) { cn_del_callback(&cn_recv_id); printk(KERN_INFO "cn_recv unloaded\n"); }
module_init(cn_recv_init); module_exit(cn_recv_fini);
MODULE_LICENSE("GPL"); MODULE_AUTHOR("Libor Vanek <libor.vanek@gmail.com>"); MODULE_DESCRIPTION("Connector's test recieve module");
/* * cn_send.c */
#include <linux/kernel.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/skbuff.h> #include <linux/timer.h>
#include <linux/connector.h>
static struct cb_id cn_send_id = { 0x3, 0x1 }; static int seq_id = 0;
void my_send_test(void) { struct cn_msg *msg; char data[32]; int ret; msg = kmalloc(sizeof(*msg) + sizeof(data), GFP_ATOMIC); memset(msg, 0, sizeof(*msg) + sizeof(data));
msg->id.idx = cn_send_id.idx; msg->id.val = cn_send_id.val; msg->ack = 0; msg->seq = seq_id++; msg->len = 5;
msg->len = sizeof(data); msg->len = scnprintf(data, sizeof(data), "Ping") + 1; memcpy(msg + 1, data, msg->len);
ret = cn_netlink_send(msg, cn_send_id.idx, gfp_any()); kfree(msg); printk("Sent, retval: %i\n", ret); }
static int cn_send_init(void) { my_send_test(); return 0; }
static void cn_send_fini(void) { printk(KERN_INFO "cn_send unloaded\n"); }
module_init(cn_send_init); module_exit(cn_send_fini);
MODULE_LICENSE("GPL"); MODULE_AUTHOR("Libor Vanek <libor.vanek@gmail.com>"); MODULE_DESCRIPTION("Connector's test send module");
/* * cn_user_recv.c */
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <time.h>
#include <endian.h> #include <asm/types.h>
#include <sys/socket.h> #include <sys/poll.h> #include <sys/types.h> #include <sys/socket.h>
#include <linux/connector.h> #include <linux/netlink.h> #include <linux/rtnetlink.h>
void process_msg(int s, struct cn_msg *msg) { fprintf(stdout, "Message: %08x.%08x, len=%u, seq=%u, ack=%u, len=%u %s\n", msg->id.idx, msg->id.val, msg->len, msg->seq, msg->ack, msg->len, (void *)msg->data); }
int main(int argc, char *argv[]) { int s; unsigned char buf[1024]; int len, need_exit;
struct sockaddr_nl l_local; struct cn_msg *msg; struct pollfd pfd; struct nlmsghdr *reply; memset(buf, 0, sizeof(buf)); s = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR); if (s == -1) { perror("socket"); return -1; } l_local.nl_family = AF_NETLINK; l_local.nl_groups = 0x3; l_local.nl_pid = getpid(); if (bind(s, (struct sockaddr *)&l_local, sizeof(struct sockaddr_nl)) == -1) { perror("bind"); close(s); return -1; } int on = l_local.nl_groups; if (setsockopt(s, 270, 1, &on, sizeof(on))) { perror("setsockopt"); close(s); return -1; }
pfd.fd = s;
need_exit = 0; while (!need_exit) { pfd.events = POLLIN; pfd.revents = 0; switch (poll(&pfd, 1, -1)) { case 0: need_exit = 1; break; case -1: if (errno != EINTR) { need_exit = 1; break; } continue; default: break; } if (need_exit) break;
len = recv(s, buf, sizeof(buf), 0); if (len == -1) { perror("recv buf"); close(s); return -1; }
reply = (struct nlmsghdr *)buf;
switch (reply->nlmsg_type) { case NLMSG_ERROR: fprintf(stdout, "Error message received.\n"); fflush(stdout); break; case NLMSG_DONE: msg = (struct cn_msg *)NLMSG_DATA(reply); process_msg(s, msg); break; default: break; } } close(s); return 0; }
/* * cn_user_send.c */
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <time.h>
#include <endian.h> #include <asm/types.h>
#include <sys/socket.h> #include <sys/poll.h> #include <sys/types.h> #include <sys/socket.h>
#include <linux/connector.h> #include <linux/netlink.h> #include <linux/rtnetlink.h>
#define GROUP 0x3
static int send_seq;
static int send_cmd(int s) { static char txtmsg[] = "Ping pong"; void *m; struct cn_msg *cmsg; struct nlmsghdr *nlh; int size, err; size = NLMSG_SPACE(sizeof(struct cn_msg) + sizeof(txtmsg));
nlh = malloc(size); if (!nlh) return -ENOMEM; memset(nlh, 0, size); nlh->nlmsg_seq = send_seq++; nlh->nlmsg_pid = getpid(); nlh->nlmsg_type = NLMSG_DONE; nlh->nlmsg_len = NLMSG_LENGTH(size - sizeof(struct nlmsghdr)); nlh->nlmsg_flags = 0;
cmsg = NLMSG_DATA(nlh); cmsg->id.idx = GROUP; cmsg->id.val = 0x1; cmsg->seq = nlh->nlmsg_seq; cmsg->ack = 0; cmsg->len = sizeof(txtmsg);
m = (void *)(cmsg + 1); memcpy(m, (void *)txtmsg, sizeof(txtmsg)); err = send(s, nlh, size, 0); if (err == -1) { fprintf(stdout, "Failed to send: %s [%d].\n", strerror(errno), errno); } free(nlh);
return err; }
int main(int argc, char *argv[]) { int s; unsigned char buf[1024]; int len;
send_seq = 0;
struct sockaddr_nl l_local; struct cn_msg *msg; struct nlmsghdr *reply; memset(buf, 0, sizeof(buf)); s = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR); if (s == -1) { perror("socket"); return -1; } l_local.nl_family = AF_NETLINK; l_local.nl_groups = GROUP; l_local.nl_pid = getpid(); if (bind(s, (struct sockaddr *)&l_local, sizeof(struct sockaddr_nl)) == -1) { perror("bind"); close(s); return -1; } int on = l_local.nl_groups; if (setsockopt(s, 270, 1, &on, sizeof(on))) { perror("setseckopt"); close(s); return -1; }
send_cmd(s); close(s); return 0; }
| |