I am trying (in vain) to create and send a single TCP packet from kernel,
from scratch (i.e. sk_buff and sock both need to be created and
initialized). I read the source code for various functions in net and
net/ipv4 but I am not sure I am doing all steps and in correct order, as
the kernel keeps crashing. Is there a sample code someone could send me or
a good book on this matter? I am using 2.4.9 version.
If this question is not appropriate for this list, could someone point me
to more suitable list?
Thanks
Jelena
The following is the code i once downloaded from the net... Apart from
this one, the code of khttpd (linux/net/khttpd) would be very useful...
Go through thug_receive, thug_accept, thug_send, thug_listen... They
should be sufficient for most of the networking...
Prasad
IIIT-Hyderabad, INDIA.
--------- START OF CODE ----------
/*
*
*
* Networking code for thug
*
*
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/malloc.h>
#include <linux/socket.h>
#include <linux/in.h>
#include <linux/locks.h>
#include <linux/smp_lock.h>
#include <asm/fcntl.h>
#include <net/scm.h>
#include <asm/uaccess.h>
#include <linux/socket.h>
#include <linux/inet.h>
#include <asm/errno.h>
#include "thugd.h"
void fput(struct file *file);
struct socket *socki_lookup(struct inode *inode)
{
return &inode->u.socket_i;
}
struct socket* thug_connect(struct sockaddr_in* sock_addr)
{
int retval;
struct socket *sock;
retval = sock_create(AF_INET,SOCK_STREAM,0,&sock);
if (retval < 0) {
printk("thug_connect: error creating socket\n");
return NULL;
}
retval = sock->ops->connect(sock,(struct sockaddr *)sock_addr,sizeof(struct sockaddr_in),0);
if (retval < 0) {
printk("thug_connect: error on connect: %d\n",retval);
sock_release(sock);
return NULL;
}
thug_print("Connection ok\n");
return sock;
}
struct socket* thug_listen(void)
{
struct socket *sock;
struct sockaddr_in servaddr;
if (sock_create(AF_INET,SOCK_STREAM,0,&sock) < 0) {
printk("thug_listen: error creating socket\n");
return NULL;
}
memset(&servaddr,0,sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(THUG_PORT);
if(sock->ops->bind(sock, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {
printk("thug_listen: bind error\n");
sock_release(sock);
return NULL;
}
if (sock->ops->listen(sock,5) < 0) {
printk("thug_listen: listen error\n");
sock_release(sock);
return NULL;
}
return sock;
}
struct socket* thug_accept(struct socket* sock)
{
struct inode* inode;
struct socket* newsock;
int err;
struct sockaddr_in sin;
int slen;
if (!(newsock = sock_alloc())) {
printk("thug_accept: error creating socket(2)\n");
return NULL;
}
inode = newsock->inode;
newsock->type = sock->type;
newsock->ops = sock->ops;
/*if (sock->ops->dup(newsock,sock) < 0) {
printk("thug_accept: error dupping socket\n");
sock_release(newsock);
return NULL;
}*/
if ((err = newsock->ops->accept(sock,newsock,0)) < 0) {
sock_release(newsock);
return ERR_PTR(err);
}
slen = sizeof(sin);
if ( (err = newsock->ops->getname(newsock,(struct sockaddr*)&sin,&slen,1)) < 0) {
printk("thug_accept: error on getname: %d\n",err);
sock_release(newsock);
return ERR_PTR(err);
}
newsock = socki_lookup(inode);
return newsock;
}
int thug_receive(struct socket* sock,unsigned char* buf,int len)
{
struct msghdr msg;
struct iovec iov;
mm_segment_t oldfs;
int size = 0;
iov.iov_base = buf;
iov.iov_len = len;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = NULL;
msg.msg_name = NULL;
msg.msg_namelen = 0;
oldfs = get_fs();
set_fs(KERNEL_DS);
size = sock_recvmsg(sock,&msg,len,0);
set_fs(oldfs);
if (size < 0)
printk("thug_read_from_socket: sock_recvmsg error: %d\n",size);
return size;
}
int thug_read_from_socket(struct socket* sock,unsigned char* buf,int len)
{
int result;
int received = 0;
while(received < len) {
result = thug_receive(sock,buf + received,len - received);
if (result == 0)
return -EIO;
else if (result < 0)
return result;
received += result;
}
return received;
}
int thug_send(struct socket* sock,unsigned char* buf,int len)
{
struct msghdr msg;
struct iovec iov;
mm_segment_t oldfs;
int size = 0;
iov.iov_base = buf;
iov.iov_len = len;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_flags = 0;
oldfs = get_fs();
set_fs(KERNEL_DS);
size = sock_sendmsg(sock,&msg,len);
set_fs(oldfs);
if (size < 0)
printk("thug_write_to_socket: sock_sendmsg error: %d\n",size);
return size;
}
int thug_write_to_socket(struct socket* sock,unsigned char* buf,int len)
{
int result;
int sent = 0;
while (sent < len) {
result = thug_send(sock,buf + sent,len - sent);
if (result == 0)
return -EIO;
else if (result < 0)
return result;
sent += result;
}
return sent;
}
int send_ack(struct socket* sock)
{
unsigned char buf = 0;
if (thug_write_to_socket(sock,&buf,1) != 1) {
printk("Error sending ack");
return -1;
}
return 0;
}
int send_break(struct socket* sock)
{
unsigned char buf = 1;
if (thug_write_to_socket(sock,&buf,1) != 1) {
printk("Error sending break");
return -1;
}
return 0;
}
int get_ack(struct socket* sock)
{
unsigned char buf;
if (thug_read_from_socket(sock,&buf,1) != 1) {
printk("Error getting ack");
return -1;
}
if (buf != 0)
return -1;
return 0;
}
void decodeui(unsigned int* dest,char* src)
{
if (dest && src) {
*dest = 0;
*dest = (src[0] << 24) & 0xFF000000;
*dest |= (src[1] << 16) & 0xFF0000;
*dest |= (src[2] << 8) & 0xFF00;
*dest |= src[3] & 0xFF;
}
}
void encodeui(char* dest,unsigned int src)
{
if (dest) {
dest[0] = (src & 0xFF000000) >> 24;
dest[1] = (src & 0xFF0000) >> 16;
dest[2] = (src & 0xFF00) >> 8;
dest[3] = src & 0xFF;
}
}
void encodeus(char* dest,unsigned short src)
{
if (dest) {
dest[0] = (src & 0xFF00) >> 8;
dest[1] = src & 0xFF;
}
}
void decodeus(unsigned short* dest,char* src)
{
if (dest && src) {
*dest = 0;
*dest = src[0] << 8;
*dest |= src[1] & 0xFF;
}
}
void decodel(long* dest,char* src)
{
if (dest && src) {
*dest = 0;
*dest = (src[0] << 24) & 0xFF000000;
*dest |= (src[1] << 16) & 0xFF0000;
*dest |= (src[2] << 8) & 0xFF00;
*dest |= src[3] & 0xFF;
}
}
void encodel(char* dest,long src)
{
if (dest) {
dest[0] = (src & 0xFF000000) >> 24;
dest[1] = (src & 0xFF0000) >> 16;
dest[2] = (src & 0xFF00) >> 8;
dest[3] = src & 0xFF;
}
}
void decodeul(unsigned long* dest,char* src)
{
if (dest && src) {
*dest = 0;
*dest = (src[0] << 24) & 0xFF000000;
*dest |= (src[1] << 16) & 0xFF0000;
*dest |= (src[2] << 8) & 0xFF00;
*dest |= src[3] & 0xFF;
}
}
void encodeul(char* dest,unsigned long src)
{
if (dest) {
dest[0] = (src & 0xFF000000) >> 24;
dest[1] = (src & 0xFF0000) >> 16;
dest[2] = (src & 0xFF00) >> 8;
dest[3] = src & 0xFF;
}
}
void decodell(long long* dest,char* src)
{
if (dest && src) {
*dest = 0;
*dest = (src[0] << 56) & 0xFF00000000000000;
*dest |= (src[1] << 48) & 0xFF000000000000;
*dest |= (src[2] << 40) & 0xFF0000000000;
*dest |= (src[3] << 32) & 0xFF00000000;
*dest |= (src[4] << 24) & 0xFF000000;
*dest |= (src[5] << 16) & 0xFF0000;
*dest |= (src[6] << 8) & 0xFF00;
*dest |= src[7] & 0xFF;
}
}
void encodell(char* dest,long long src)
{
if (dest) {
dest[0] = (src & 0xFF00000000000000) >> 56;
dest[1] = (src & 0x00FF000000000000) >> 48;
dest[2] = (src & 0x0000FF0000000000) >> 40;
dest[3] = (src & 0x000000FF00000000) >> 32;
dest[4] = (src & 0x00000000FF000000) >> 24;
dest[5] = (src & 0x0000000000FF0000) >> 16;
dest[6] = (src & 0x000000000000FF00) >> 8;
dest[7] = src & 0x00000000000000FF;
}
}
void decodei(int* dest,char* src)
{
if (dest && src) {
*dest = 0;
*dest = (src[0] << 24) & 0xFF000000;
*dest |= (src[1] << 16) & 0xFF0000;
*dest |= (src[2] << 8) & 0xFF00;
*dest |= src[3] & 0xFF;
}
}
void encodei(char* dest,int src)
{
if (dest) {
dest[0] = (src & 0xFF000000) >> 24;
dest[1] = (src & 0xFF0000) >> 16;
dest[2] = (src & 0xFF00) >> 8;
dest[3] = src & 0xFF;
}
}
/* must be called with the socket locked */
int thug_request(struct mfs_sb_info* thug_sb, unsigned int msglen)
{
unsigned short len;
unsigned long flags;
int error = 0;
int mask;
sigset_t old_set;
spin_lock_irqsave(¤t->sigmask_lock, flags);
old_set = current->blocked;
mask = sigmask(SIGKILL) | sigmask(SIGSTOP);
siginitsetinv(¤t->blocked,mask);
recalc_sigpending(current);
spin_unlock_irqrestore(¤t->sigmask_lock, flags);
if ((error = thug_write_to_socket(thug_sb->sock, thug_sb->packet, msglen)) != msglen) {
printk("thug_request: error sending request to server\n");
goto out;
}
memset(thug_sb->packet, 0, thug_sb->packet_len);
if ((error = thug_read_from_socket(thug_sb->sock, thug_sb->packet, 2)) != 2) {
printk("thug_request: error reading reply length from socket\n");
goto out;
}
decodeus(&len, thug_sb->packet);
if ((error = thug_read_from_socket(thug_sb->sock, thug_sb->packet + 2, len)) != len) {
printk("thug_request: error reading reply body from socket (%d)\n",len);
goto out;
}
out:
spin_lock_irqsave(¤t->sigmask_lock, flags);
current->blocked = old_set;
recalc_sigpending(current);
spin_unlock_irqrestore(¤t->sigmask_lock, flags);
return error;
}
void encode_iattr(char* dest, struct iattr* attr)
{
encodeui(dest, attr->ia_valid);
encodeus(dest + 4, attr->ia_mode);
encodeui(dest + 6, attr->ia_uid);
encodeui(dest + 10, attr->ia_gid);
encodell(dest + 14, attr->ia_size);
encodel(dest + 22, attr->ia_atime);
encodel(dest + 26, attr->ia_mtime);
encodel(dest + 30, attr->ia_ctime);
encodeui(dest + 34, attr->ia_attr_flags);
}
void decode_iattr(struct iattr* dest, char* src)
{
decodeui(&dest->ia_valid, src);
decodeus(&dest->ia_mode, src + 4);
decodeui(&dest->ia_uid, src + 6);
decodeui(&dest->ia_gid, src + 10);
decodell(&dest->ia_size, src + 14);
decodel(&dest->ia_atime, src + 22);
decodel(&dest->ia_mtime, src + 26);
decodel(&dest->ia_ctime, src + 30);
decodeui(&dest->ia_attr_flags, src + 34);
}
----------- END OF CODE ------------
On Mon, 23 Dec 2002, Jelena Mirkovic wrote:
> I am trying (in vain) to create and send a single TCP packet from kernel,
> from scratch (i.e. sk_buff and sock both need to be created and
> initialized). I read the source code for various functions in net and
> net/ipv4 but I am not sure I am doing all steps and in correct order, as
> the kernel keeps crashing. Is there a sample code someone could send me or
> a good book on this matter? I am using 2.4.9 version.
>
> If this question is not appropriate for this list, could someone point me
> to more suitable list?
>
> Thanks
> Jelena
>
> -
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
>
--
Failure is not an option