dev_queue_xmit results in kernel panic - linux

I am writing a part of kernel module which transfers skbuff from one interface out to another interface. Ex all packet coming on eth0, gets forwarded out to on eth1. The problem even the first packet I intend to transmit is resulting in kernel crash in dev_queue_xmit(). Can anyone help me understand whats going wrong here ?. Kernel Panic occurs in
<2>kernel BUG at net/core/skbuff.c:927!
code sample function that I am using to transmit packet is as below. Please let me know.
enter code here
int txPktOnOtherIf(struct sk_buff *skb, struct net_device *tdev)
{
int reservedSpace=max((int)LL_RESERVED_SPACE(tdev),(int)sizeof(struct ethhdr));
int buffLen = reservedSpace - sizeof(struct ethhdr) + skb->len + skb->dev->needed_tailroom;
struct sk_buff* nskb = NULL;
int err = 0;
printk("ReservedSpace is %d and buffer len is %d",reservedSpace,buffLen);
nskb = alloc_skb(buffLen, GFP_KERNEL);
if (!nskb) {
printk("Couldn't allocate SKB\n");
return -1;
}
skb_reserve(nskb, reservedSpace);
skb_reset_network_header(nskb);
skb_put(nskb, skb->len - sizeof(struct ethhdr));
skb_push(nskb, sizeof(struct ethhdr));
skb_reset_mac_header(nskb);
skb_reset_mac_len(nskb);
err = skb_store_bits(nskb, 0, skb->data, skb->len);
if (err) {
kfree_skb(nskb);
printk("Error %d storing to SKB\n", err);
return -1;
}
nskb->dev = tdev;
nskb->protocol = skb->protocol;
skb_get(nskb);
err = dev_queue_xmit(nskb);
err = net_xmit_eval(err);
if (err) {
kfree_skb(nskb);
printk("Error %d sending frame\n", err);
return -1;
}
return 0;
}

Related

Does Linux AIO support RAW sockets?

I am struggling to get AIO working on Linux (version 3.19) for receiving packets on a RAW socket, but to no avail. I've successfully used AIO for UDP and TCP sockets, but can't make it work for a RAW socket. I've tried both IPv4 and IPv6.
Does anyone know if AIO supports RAW sockets?
Here's some code snippets from my application:
void readCallback(sigval_t sigval) {
debug(LOG_DEBUG, "RAW packet received\n");
}
int main(int argc, char *argv[]) {
int sock = socket(domain, SOCK_RAW, IPPROTO_RAW);
if (-1 == sock) {
debug(LOG_CRIT, "FAILED to create raw socket\n");
return 1;
}
char *iface = "eth0";
ifreq ifr;
memset (&ifr, 0, sizeof(ifr));
snprintf (ifr.ifr_name, sizeof(ifr.ifr_name), "%s", iface);
if (ioctl (sock, SIOCGIFINDEX, &ifr) < 0) {
debug(LOG_CRIT, "FAILED to query interface '%s' index\n", iface);
return 1;
}
// Set flag so socket expects us to provide IP header.
const int on = 1;
if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on)) < 0) {
debug(LOG_CRIT, "FAILED to configure raw socket on '%s'\n", iface);
return 1;
}
// Bind socket to interface index.
if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) < 0) {
debug(LOG_CRIT, "FAILED to bind socket to %s/%u\n", iface, ifr.ifr_ifindex);
return 1;
}
// listen for packets
struct aiocb aio;
char buf[MAX_PACKET];
bzero((char*)&aio, sizeof(struct aiocb));
aio.aio_fildes = sock;
aio.aio_buf = &buf;
aio.aio_nbytes = MAX_PACKET;
aio.aio_offset = 0;
aio.aio_sigevent.sigev_notify = SIGEV_THREAD;
aio.aio_sigevent.sigev_notify_function = readCallback;
aio.aio_sigevent.sigev_notify_attributes = NULL;
aio.aio_sigevent.sigev_value.sival_ptr = buf;
if (!RequestAioRead(&aio)) {
debug(LOG_DEBUG, "FAILED to listen on raw socket...\n");
return 1;
}
debug(LOG_DEBUG, "Listening on raw socket...\n");
// main loop
while (true) {
usleep(100000);
}
close(sock);
return 0;
}
Turns out my socket() protocol was wrong. The correct protocol seems to be htons(0x0800):
socket(AF_PACKET, SOCK_RAW, htons(0x0800));
With this, aio seems to work fine.

How to add a new custom layer 4 protocol (a new Raw socket) in linux kernel?

i am trying adding my own customized layer 4 protocol in linux (ubuntu 14.04) - IPPROTO_MYPROTO as a loadable kernel module. I have done all necessary steps to register the protocol. Here i am sharing my code.
When i am trying to send a mesage from user space program using sendmsg(), i expect the corresponding fn myproto_sendmsg() registered via struct proto structure should be called in kernel space. But what i am observing is that though the myproto_sendmsg() in kernel space is not being called, yet destination machine is receiving the correct data. surprise ! surprise !. Is the default udp sendmsg() fn kicking in here which is like uninvited guest doing his work.
Here, sendmsg() call in user space returns as many bytes as send. Hence, fn returns success.
User space program :
void forwardUDP( int destination_node ,char sendString[] )
{
struct msghdr msg;
destination_node = destination_node % N; //destination node to which data is to be forwaded
int sock, rc;
struct sockaddr_in server_addr;
struct iovec iov;
struct hostent *host; //hostent predefined structure use to store info about host
host = (struct hostent *) gethostbyname(node[destination_node].ip_address);//gethostbyname returns a pointer to hostent
if ((sock = socket(AF_INET, SOCK_RAW, 5)) == -1)
{
perror("socket");
exit(1);
}
//destination address structure
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(node[destination_node].udpportno);
server_addr.sin_addr = *((struct in_addr *)host->h_addr); //host->h_addr gives address of host
bzero(&(server_addr.sin_zero),8);
/* fill the messsage structure*/
memset(&msg, 0 , sizeof(struct msghdr));
memset(&iov, 0, sizeof(struct iovec));
msg.msg_name = (void *)&server_addr;
msg.msg_namelen = sizeof(struct sockaddr_in);
printf("sendString = %s\n", sendString);
iov.iov_base = (void *)sendString;
iov.iov_len = strlen(sendString);
msg.msg_iov = &iov;
printf("len = %d\n", strlen(sendString));
#if 1
msg.msg_iovlen = 1;
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_flags = 0;
#endif
//sendto(sock, sendString, strlen(sendString), 0,(struct sockaddr *)&server_addr, sizeof(struct sockaddr));
**rc = sendmsg(sock, &msg, 0);**
printf("rc = %d\n", rc);
//sendto() function shall send a message through a connectionless-mode socket.
printf("\nFORWARD REQUEST : '%s' has been forwarded to node ---->%d\n",sendString,destination_node);
//close(sock);
}
Kernel Module
/* Define the handler which will recieve all ingress packets for protocol = IPPROTO_MYPROTO
defined in net/protocol.h
*/
/* Resgiter the call backs for pkt reception */
static const struct net_protocol myproto_protocol = {
.handler = myproto_rcv,
.err_handler = myproto_err,
.no_policy = 1,
.netns_ok = 1,
};
static struct inet_protosw myproto_protosw;
int
myproto_rcv(struct sk_buff *skb){
printk(KERN_INFO "myproto_rcv is called\n");
return 0;
}
int
myproto_sendmsg(struct kiocb *iocb, struct sock *sk,
struct msghdr *msg, size_t len){
printk(KERN_INFO "myproto_sendmsg() is called\n");
return 0;
}
void myproto_lib_close(struct sock *sk, long timeout){
printk(KERN_INFO "close is called\n");
return;
}
int
myproto_recvmsg(struct kiocb *iocb, struct sock *sk,
struct msghdr *msg,
size_t len, int noblock, int flags,
int *addr_len){
printk(KERN_INFO "myproto_recvmsg() is called.\n");
printk(KERN_INFO "iocb = 0x%x,\nsk = 0x%x,\nmsg = 0x%x,\nlen = %d,\nnoblock = %d,\nflags = %d,\naddr_len = 0x%x", iocb, sk, msg, len, noblock, flags, addr_len);
return 0;
}
/* Socket structure for Custom protocol, see struct udp_sock for example*/
struct myproto_sock{
struct inet_sock inet; // should be first member
__u16 len;
};
void
myproto_lib_hash(struct sock *sk){
printk(KERN_INFO "myproto_lib_hash() is called");
}
/* Define the **struct proto** structure for the Custom protocol defined in
net/sock.h */
struct proto myproto_prot = {
.name = "MYPROTO",
.owner = THIS_MODULE,
.close = myproto_lib_close,
.sendmsg = myproto_sendmsg,
.hash = myproto_lib_hash,
.recvmsg = myproto_recvmsg,
.obj_size = sizeof(struct myproto_sock),
.slab_flags = SLAB_DESTROY_BY_RCU,
};
int init_module(void);
void cleanup_module(void);
int
init_module(void)
{
int rc = 0;
rc = proto_register(&myproto_prot, 1);
if(rc == 0){
printk(KERN_INFO "Protocol registration is successful\n");
}
else{
printk(KERN_INFO "Protocol registration is failed\n");
cleanup_module();
return rc;
}
rc = inet_add_protocol(&myproto_protocol, IPPROTO_MYPROTO);
if(rc == 0){
printk(KERN_INFO "Protocol insertion in inet_protos[] is successful\n");
}
else{
printk(KERN_INFO "Protocol insertion in inet_protos[] is failed\n");
cleanup_module();
return rc;
}
memset(&myproto_protosw, 0 ,sizeof(myproto_protosw));
myproto_protosw.type = SOCK_RAW;
myproto_protosw.protocol = IPPROTO_MYPROTO;
myproto_protosw.prot = &myproto_prot;
extern const struct proto_ops inet_dgram_ops; // defined in ipv4/af_inet.c
myproto_protosw.ops = &inet_dgram_ops;
myproto_protosw.flags = INET_PROTOSW_REUSE;
inet_register_protosw(&myproto_protosw);
return 0;
}
void cleanup_module(void)
{
int rc = 0;
rc = inet_del_protocol(&myproto_protocol, IPPROTO_MYPROTO);
if(rc == 0)
printk(KERN_INFO "Protocol removed successful\n");
else
printk(KERN_INFO "Protocol removal failed\n");
proto_unregister(&myproto_prot);
printk(KERN_INFO "Module cleaned up\n");
return;
}

how to read/write from/to a SOCK_SEQPACKET socket?

I try to use a SOCK_SEQPACKET socket with this:
int rc, len;
int worker_sd, pass_sd;
char buffer[80];
struct iovec iov[1];
struct msghdr msg;
memset(&msg, 0, sizeof(msg));
memset(iov, 0, sizeof(iov));
iov[0].iov_base = buffer;
iov[0].iov_len = sizeof(buffer);
msg.msg_iov = iov;
msg.msg_iovlen = 1;
if((socket_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0)) < 0)
{
perror("server: socket");
exit -1;
}
memset(&server_address, 0, sizeof(server_address));
server_address.sun_family = AF_UNIX;
strcpy(server_address.sun_path, "/mysocket");
unlink("/mysocket");
if(bind(socket_fd, (const struct sockaddr *) &server_address, sizeof(server_address)) < 0)
{
close(socket_fd);
perror("server: bind error");
return 1;
}
while(1)
{
printf("wait for message\n");
bytes_received = recvmsg(socket_fd, &msg, MSG_WAITALL);
printf("%d bytes\n", bytes_received);
}
The problem is that the process does not wait but receives -1 from recvmsg and loops forever. Nowhere in the manpages is there any reference what functions shall be used with SOCK_SEQPACKET-style sockets, for example I am not really sure whether recvmsg is even the correct function.
SOCK_SEQPACKET is connection-orientated so you must first accept a connection then do your IO on the accepted client socket.
recvmsg() returns -1 when an error has occured - errno will be set to the error number.
Read here: http://pubs.opengroup.org/onlinepubs/009695399/functions/recvmsg.html

"resource temporarily unavailable" in recv in socket programming

I want to read and write over Wanpipe driver (a network device driver for Sangoma cards) via socket programming but i get this message error: "resource temporarily unavailable". The card is working and i see it send and receive packets in ifconfig. I have included my code and would be very pleased if somebody help me in this.
A related question: I set the socket to blocking mode but the recv message does not block? how could i block the recv?
int main(void)
{
int sd;
int buflen=WP_HEADER + MAX_PACKET;
char buf[buflen];
struct wan_sockaddr_ll sa;
sd = socket(AF_WANPIPE, SOCK_RAW,0);
if (sd < 0) /* if socket failed to initialize, exit */
{
perror("Error Creating Socket");
exit(1);
}
printf("Socket Descriptor:%d\n",sd);
memset(&sa,0,sizeof(struct wan_sockaddr_ll));
strncpy((char*)sa.sll_card,"wanpipe1",sizeof(sa.sl l_card));
strncpy((char*)sa.sll_device,"w1g1",sizeof(sa.sll_ device));
sa.sll_protocol = htons(PVC_PROT);
sa.sll_family = AF_WANPIPE;
if(bind(sd, (struct sockaddr *)&sa, sizeof(sa)) < 0)
{
perror("error bind failed");
close(sd);
exit(1);
}
int data=0;
int ret=ioctl(sd,FIONBIO,&data);
if (ret < 0)
{
perror("ioctl error!");
close(sd);
return 1;
}
fd_set read_fds;
struct timeval timeout;
timeout.tv_sec = 10;
timeout.tv_usec = 0;
FD_ZERO(&read_fds);
FD_SET(sd,&read_fds);
if(select(sd+1, &read_fds, NULL, NULL, &timeout) < 0)
{
perror("select() error!");
exit(1);
}
if (FD_ISSET(sd,&read_fds))
printf("There is data for reading\n");
else
printf("There is no data for reading\n");*/
// MSG_WAITALL | MSG_PEEK | MSG_OOB
int r=recv(sd,buf,buflen,0);
if (r < 0)
{
perror("Wanpipe raw socket reading");
close(sd);
exit(1);
}
printf("\nNumber of bytes read into the buffer: %d",r);
printf("\nThe read buffer: ");
puts(buf);
close(sd);
}
thank you in advance.

Problem with netlink socket: kernel freeze

I'm trying to use netlink sockets to exchange messages between user-space and kernel space...i send a message from user-space to kernel-space and all works well but when i try to reply from kernel-space, system freezes. In particular i schedule with a workqueue a function that create the message and send to user-space using netlink_unicast function...here some kernel code:
void wq_func(struct work_queue *wq)
{
struct sk_buff *resp = alloc_skb(NLMSG_LENGTH(100), GFP_KERNEL);
if (!resp)
{
printk(KERN_INFO "alloc_skb failed");
return;
}
struct nlmsghdr *nlh = (struct nlmsghdr *)skb_put(resp, NLMSG_LENGTH(100));
memset(nlh, 0, NLMSG_LENGTH(100));
nlh->nlmsg_len = NLMSG_LENGTH(100);
nlh->nlmsg_pid = 0;
nlh->nlmsg_flags = 0;
strcpy(NLMSG_DATA(nlh), "From kernel: Yes i'm here!");
NETLINK_CB(resp).pid = 0;
NETLINK_CB(resp).dst_group = 0;
printk(KERN_INFO "Trying to send a netlink message to pid %d", pid);
int err = netlink_unicast(s, resp, pid, MSG_DONTWAIT);
if (err < 0)
printk(KERN_ALERT "Error sending message to user-space");
kfree_skb(resp);
}
DECLARE_WORK(wq, wq_func);
static void input_nl(struct sk_buff *buff)
{
printk(KERN_INFO "Received message socket NETLINK_TEST");
if (buff == NULL)
{
printk(KERN_ALERT "NULL sk_buff!");
return;
}
struct nlmsghdr *nlh = (struct nlmsghdr *)buff->data;
printk(KERN_INFO "Received netlink message from pid %d: %s", nlh->nlmsg_pid, NLMSG_DATA(nlh));
pid = nlh->nlmsg_pid;
schedule_work(&wq);
}
int __init knl_init()
{
printk(KERN_INFO "knl module loaded");
s = netlink_kernel_create(&init_net, NETLINK_TEST, 0, input_nl, NULL, THIS_MODULE);
if (s == NULL)
return -1;
return 0;
}
If i try to comment the call to netlink_unicast kernel doesn't freeze. From user-space i can send a message correctly. I remember that the same code worked well in the past and i 'm very surprised about this strange error now.
Any idea?
Thank you all!
I tried to remove kfree_skb call after netlink_unicast call and all works...so, why the system hangs with that call? Where should i free allocated sk_buff?
netlink_unicast() takes ownership of the skb and frees it itself.
After calling netlink_unicast you cannot free struct sk_buff

Resources