diff --git a/AUTHOR b/AUTHOR index c0ab6fb..345cab6 100644 --- a/AUTHOR +++ b/AUTHOR @@ -1,8 +1,10 @@ -Author +Authors song.xian-guang@hotmail.com - (C)2007-2008, China 2017 Hardik Bagdi(hbagdi1@binghamton.edu) Changes for Compatibility with Linux 4.9 to use iov_iter + +2025 Mephistolist(cloneozone@gmail.com) +Complete rewrite for kernels 5.11-6.16. diff --git a/README.md b/README.md index a15d8fe..cabcef8 100644 --- a/README.md +++ b/README.md @@ -1,39 +1,42 @@ # ksocket API -BSD-style socket API in kernel space for TCP/IP networking. -Original ksocket for v2.6 was published at [http://ksocket.sourceforge.net/](http://ksocket.sourceforge.net/). -This repository contains changes to make it compatible with new kernel versions. -The ksocket API has been updated to incorporate the changes related to the [iov_iter](https://lwn.net/Articles/625077/) interface introduced in kernel v3.19+. +A BSD-style socket API in kernel space for TCP/IP networking on Linux kernels 5.11-6.16. This is not backwards compatible with older kernels, but links will be provided to those later in this documentation. ### Getting started ``` -$ git clone https://github.com/hbagdi/ksocket.git +$ git clone https://github.com/mephistolist/ksocket.git $ cd ksocket/src -$ make # make sure you have the kernel headers/tree installed +$ make # make sure you have the kernel headers/tree installed first $ sudo insmod ksocket.ko #now you can use the exported symbols from this kernel module ``` - -### Sample -Look at `sample` sub-directory for code-samples. +You can then go to the samples directory in the root of this project. Inside it are TCP and UDP of servers and client examples you may build and insert into the kernel. After inserting the server and client for TCP, you should see something like the following with dmesg: ``` -$ cd ksocket/sample/tcp/ -$ make -# two kernel modules are ksocket_tcp_cli_demo.ko(TCP client) and ksocket_tcp_srv_demo.ko(TCP server) -$ sudo ksocket_tcp_srv_demo.ko -$ sudo ksocket_tcp_cli_demo.ko -$ dmesg +# dmesg +[ 137.259240] tcp_server: Loading (starting thread) +[ 137.260232] tcp_server: thread starting +[ 137.260634] tcp_server: listening on port 12345 +[ 151.256262] [tcp_client] Initializing +[ 151.257245] sock_create sk= 0x00000000db4a0058 +[ 151.264826] [tcp_client] Connected to 127.0.0.1:12345 +[ 151.264886] tcp_server: accepted newsock=000000000aae9c53 newsock->sk=00000000844b247d +[ 151.265311] tcp_server: received (29 bytes): Hello from kernel TCP client! +[ 151.265396] [tcp_client] Sent: Hello from kernel TCP client! +``` +Or with the UDP modules, the dmesg should resemble this: +``` +# dmesg +[ 501.520772] sock_create sk= 0x00000000295150e8 +[ 501.522605] kbind ret = 0 +[ 501.523914] UDP Server: Listening on port 4444 +[ 590.998621] [udp_client] Initializing +[ 591.001210] sock_create sk= 0x000000006da0c70b +[ 591.003466] [udp_client] Sent: Hello UDP Server +[ 591.003636] UDP Server: Received 'Hello UDP Server' +[ 591.062269] [udp_client] Received: ACK from UDP Server ``` - ### Support across kernel versions -The original ksocket work was to support Linux 2.6, however support for v5.4.0 has been -included. - -v5.4.0 support is a work on Linux ubuntu 5.4.0-66 x86-64, therefore there is no guarantee it works -well on versions > 2.6 && < 5.3.x - -In order to keep the 2.6 version stable it was left without the 5.4.0 work, -instead we now have two branches: v2.6 (master) and v5.4.0 +The original ksocket work was to support Linux 2.6, and later versions came for later kernels. This version of ksocket was designed for kernels 5.11-6.16. It may work in verions beyond 6.16, but we do not know what future kernel versions will entail. If you need this for an older kernel, see the links below: #### v2.6 original development https://github.com/hbagdi/ksocket @@ -43,7 +46,21 @@ https://github.com/hbagdi/ksocket/tree/linux-5.4.0 ### Contributing/Reporting Bugs - Feel free to open Pull-Requests here for any enhancements/fixes. -- Open an issue in the repository for any help or bugs. Make sure to mention Kernel version. +- Open an issue in the repository for any help or bugs. Make sure to mention Kernel version. + +### Stream-lining +If you wish to not have to load the ksocket module, or link its symbols in Makefiles you can statically link ksocket when building a kernel from source. Considering we have kernel 6.16 inside /usr/src and this ksocket project in /home/user/ksocket, we can do something like the following: +``` +# export VERSION=6.16 +# mkdir /usr/src/linux-$VERSION/drivers/ksocket +# rsync -avP /home/user/ksocket/ /usr/src/linux-$VERSION/drivers/ksocket/ +# sed -i '$ s|^endmenu$|source "drivers/ksocket/Kconfig"\nendmenu|' /usr/src/linux-$VERSION/drivers/Kconfig +# echo "obj-$(CONFIG_KSOCKET) += ksocket/" >> /usr/src/linux-$VERSION/drivers/Makefile +``` +If you proceed with then building and loading your kernel, you will not have to build or insert the ksocket module as it will already be in the kernel. You will also no longer need this line in your Makefiles to use or call kscoket's API: +``` +KBUILD_EXTRA_SYMBOLS := ../../../src/Module.symvers +``` ### Contact -Email at hardikbagdi@gmail.com for any further help. +For this version of kscoket you may reach out to cloneozone@gmail.com. diff --git a/sample/tcp/Makefile b/sample/tcp/Makefile deleted file mode 100644 index 65989dd..0000000 --- a/sample/tcp/Makefile +++ /dev/null @@ -1,33 +0,0 @@ -# -# ksocket project -# BSD-style socket APIs for kernel 2.6 developers -# -# @2007-2008, China -# @song.xian-guang@hotmail.com (MSN Accounts) -# -# This code is licenced under the GPL -# Feel free to contact me if any questions -# -# @2017 -# Hardik Bagdi (hbagdi1@binghamton.edu) -# Changes for Compatibility with Linux 4.9 to use iov_iter - -.PHONY: default clean - -obj-m := ksocket_tcp_srv_demo.o ksocket_tcp_cli_demo.o -#ksocket_tcp_srv-objs := ../ksocket.o -KDIR := /lib/modules/$(shell uname -r)/build -PWD := $(shell pwd) - -EXTRA_LDFLAGS := -I../../src - -ifeq ($(ADDRSAFE),true) - EXTRA_CFLAGS += -DKSOCKET_ADDR_SAFE -endif - -default: - $(MAKE) -C $(KDIR) M=$(PWD) modules - -clean: - rm -rf *.ko *.o *.mod.* .H* .tm* .*cmd Module.symvers modules.order - diff --git a/sample/tcp/ksocket_tcp_cli_demo.c b/sample/tcp/ksocket_tcp_cli_demo.c deleted file mode 100644 index 171b1aa..0000000 --- a/sample/tcp/ksocket_tcp_cli_demo.c +++ /dev/null @@ -1,92 +0,0 @@ -/* - * ksocket project test sample - tcp client - * BSD-style socket APIs for kernel 2.6 developers - * - * @2007-2008, China - * @song.xian-guang@hotmail.com (MSN Accounts) - * - * This code is licenced under the GPL - * Feel free to contact me if any questions - * - * @2017 - * Hardik Bagdi (hbagdi1@binghamton.edu) - * Changes for Compatibility with Linux 4.9 to use iov_iter - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ksocket.h" - -#define BUF_SIZE 100 - -int tcp_cli(void *arg) -{ - ksocket_t sockfd_cli; - struct sockaddr_in addr_srv; - char buf[BUF_SIZE], *tmp; - int addr_len; - -#ifdef KSOCKET_ADDR_SAFE - mm_segment_t old_fs; - old_fs = get_fs(); - set_fs(KERNEL_DS); -#endif - - memset(&addr_srv, 0, sizeof(addr_srv)); - addr_srv.sin_family = AF_INET; - addr_srv.sin_port = htons(4444); - addr_srv.sin_addr.s_addr = inet_addr("127.0.0.1");; - addr_len = sizeof(struct sockaddr_in); - - sockfd_cli = ksocket(AF_INET, SOCK_STREAM, 0); - printk("sockfd_cli = 0x%p\n", sockfd_cli); - if (sockfd_cli == NULL) - { - printk("socket failed\n"); - return -1; - } - if (kconnect(sockfd_cli, (struct sockaddr*)&addr_srv, addr_len) < 0) - { - printk("connect failed\n"); - return -1; - } - - tmp = "quit"; - printk("connected to : %s %d\n", tmp, ntohs(addr_srv.sin_port)); - - krecv(sockfd_cli, buf, 1024, 0); - ksend(sockfd_cli, tmp, 4, 0); - printk("got message : %s\n", buf); - - kclose(sockfd_cli); -#ifdef KSOCKET_ADDR_SAFE - set_fs(old_fs); -#endif - - return 0; -} - -static int ksocket_tcp_cli_init(void) -{ - kthread_run(tcp_cli,NULL,"tcp_cli_kthread"); - printk("ksocket tcp cli init ok\n"); - return 0; -} - -static void ksocket_tcp_cli_exit(void) -{ - printk("ksocket tcp cli exit\n"); -} - -module_init(ksocket_tcp_cli_init); -module_exit(ksocket_tcp_cli_exit); - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sample/tcp/ksocket_tcp_srv_demo.c b/sample/tcp/ksocket_tcp_srv_demo.c deleted file mode 100644 index 98052df..0000000 --- a/sample/tcp/ksocket_tcp_srv_demo.c +++ /dev/null @@ -1,128 +0,0 @@ -/* - * ksocket project test sample - tcp server - * BSD-style socket APIs for kernel 2.6 developers - * - * @2007-2008, China - * @song.xian-guang@hotmail.com (MSN Accounts) - * - * This code is licenced under the GPL - * Feel free to contact me if any questions - * - * @2017 - * Hardik Bagdi (hbagdi1@binghamton.edu) - * Changes for Compatibility with Linux 4.9 to use iov_iter - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ksocket.h" - -#define BUF_SIZE 100 - -static int port = 4444; -module_param(port, int, 0444); - -int tcp_srv(void *arg) -{ - ksocket_t sockfd_srv, sockfd_cli; - struct sockaddr_in addr_srv; - struct sockaddr_in addr_cli; - char buf[BUF_SIZE], *tmp; - int addr_len, len; - -#ifdef KSOCKET_ADDR_SAFE - mm_segment_t old_fs; - old_fs = get_fs(); - set_fs(KERNEL_DS); -#endif - - sockfd_srv = sockfd_cli = NULL; - memset(&addr_cli, 0, sizeof(addr_cli)); - memset(&addr_srv, 0, sizeof(addr_srv)); - addr_srv.sin_family = AF_INET; - addr_srv.sin_port = htons(port); - addr_srv.sin_addr.s_addr = INADDR_ANY; - addr_len = sizeof(struct sockaddr_in); - - sockfd_srv = ksocket(AF_INET, SOCK_STREAM, 0); - printk("sockfd_srv = 0x%p\n", sockfd_srv); - if (sockfd_srv == NULL) - { - printk("socket failed\n"); - return -1; - } - if (kbind(sockfd_srv, (struct sockaddr *)&addr_srv, addr_len) < 0) - { - printk("bind failed\n"); - return -1; - } - - if (klisten(sockfd_srv, 10) < 0) - { - printk("listen failed\n"); - return -1; - } - - sockfd_cli = kaccept(sockfd_srv, (struct sockaddr *)&addr_cli, &addr_len); - if (sockfd_cli == NULL) - { - printk("accept failed\n"); - return -1; - } - else - printk("sockfd_cli = 0x%p\n", sockfd_cli); - - tmp = inet_ntoa(&addr_cli.sin_addr); - printk("got connected from : %s %d\n", tmp, ntohs(addr_cli.sin_port)); - kfree(tmp); - - len = sprintf(buf, "%s", "Hello, welcome to ksocket tcp srv service\n"); - ksend(sockfd_cli, buf, len, 0); - - while (1) - { - memset(buf, 0, sizeof(buf)); - len = krecv(sockfd_cli, buf, sizeof(buf), 0); - if (len > 0) - { - printk("got message : %s\n", buf); - ksend(sockfd_cli, buf, len, 0); - if (memcmp(buf, "quit", 4) == 0) - break; - } - } - - kclose(sockfd_cli); - kclose(sockfd_srv); -#ifdef KSOCKET_ADDR_SAFE - set_fs(old_fs); -#endif - - return 0; -} - -static int ksocket_tcp_srv_init(void) -{ - kthread_run(tcp_srv, NULL, "tcp_srv_kthread"); - - printk("ksocket tcp srv init ok\n"); - return 0; -} - -static void ksocket_tcp_srv_exit(void) -{ - printk("ksocket tcp srv exit\n"); -} - -module_init(ksocket_tcp_srv_init); -module_exit(ksocket_tcp_srv_exit); - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sample/udp/Makefile b/sample/udp/Makefile deleted file mode 100644 index 811a0a3..0000000 --- a/sample/udp/Makefile +++ /dev/null @@ -1,33 +0,0 @@ -# -# ksocket project -# BSD-style socket APIs for kernel 2.6 developers -# -# @2007-2008, China -# @song.xian-guang@hotmail.com (MSN Accounts) -# -# This code is licenced under the GPL -# Feel free to contact me if any questions -# @2017 -# Hardik Bagdi (hbagdi1@binghamton.edu) -# Changes for Compatibility with Linux 4.9 to use iov_iter -# - -.PHONY: default clean - -obj-m := ksocket_udp_srv_demo.o ksocket_udp_cli_demo.o -#ksocket_tcp_srv-objs := ../ksocket.o -KDIR := /lib/modules/$(shell uname -r)/build -PWD := $(shell pwd) - -EXTRA_LDFLAGS := -I../../src - -ifeq ($(ADDRSAFE),true) - EXTRA_CFLAGS += -DKSOCKET_ADDR_SAFE -endif - -default: - $(MAKE) -C $(KDIR) M=$(PWD) modules - -clean: - rm -rf *.ko *.o *.mod.* .H* .tm* .*cmd Module.symvers modules.order - diff --git a/sample/udp/ksocket_udp_cli_demo.c b/sample/udp/ksocket_udp_cli_demo.c deleted file mode 100644 index f0632c5..0000000 --- a/sample/udp/ksocket_udp_cli_demo.c +++ /dev/null @@ -1,83 +0,0 @@ -/* - * ksocket project test sample - udp client - * BSD-style socket APIs for kernel 2.6 developers - * - * @2007-2008, China - * @song.xian-guang@hotmail.com (MSN Accounts) - * - * This code is licenced under the GPL - * Feel free to contact me if any questions - * - * @2017 - * Hardik Bagdi (hbagdi1@binghamton.edu) - * Changes for Compatibility with Linux 4.9 to use iov_iter - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ksocket.h" - -#define BUF_SIZE 100 - -int udp_cli(void *arg) -{ - ksocket_t sockfd_cli; - struct sockaddr_in addr_srv; - char buf[BUF_SIZE], *tmp; - int addr_len; - -#ifdef KSOCKET_ADDR_SAFE - mm_segment_t old_fs; - old_fs = get_fs(); - set_fs(KERNEL_DS); -#endif - - memset(&addr_srv, 0, sizeof(addr_srv)); - addr_srv.sin_family = AF_INET; - addr_srv.sin_port = htons(4444); - addr_srv.sin_addr.s_addr = inet_addr("127.0.0.1");; - addr_len = sizeof(struct sockaddr_in); - - sockfd_cli = ksocket(AF_INET, SOCK_DGRAM, 0); - printk("sockfd_cli = 0x%p\n", sockfd_cli); - if (sockfd_cli == NULL) - { - printk("socket failed\n"); - return -1; - } - tmp = "quit"; - ksendto(sockfd_cli, tmp, 4, 0,(struct sockaddr*)&addr_srv, sizeof(addr_srv)); - krecvfrom(sockfd_cli, buf, 1024, 0,(struct sockaddr*)&addr_srv, &addr_len); - printk("got message : %s\n", buf); - kclose(sockfd_cli); -#ifdef KSOCKET_ADDR_SAFE - set_fs(old_fs); -#endif - - return 0; -} - -static int ksocket_udp_cli_init(void) -{ - kthread_run(udp_cli,NULL,"tcp_cli_kthread"); - printk("ksocket udp cli init ok\n"); - return 0; -} - -static void ksocket_udp_cli_exit(void) -{ - printk("ksocket udp cli exit\n"); -} - -module_init(ksocket_udp_cli_init); -module_exit(ksocket_udp_cli_exit); - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sample/udp/ksocket_udp_srv_demo.c b/sample/udp/ksocket_udp_srv_demo.c deleted file mode 100644 index cf6dc95..0000000 --- a/sample/udp/ksocket_udp_srv_demo.c +++ /dev/null @@ -1,105 +0,0 @@ -/* - * ksocket project test sample - udp server - * BSD-style socket APIs for kernel 2.6 developers - * - * @2007-2008, China - * @song.xian-guang@hotmail.com (MSN Accounts) - * - * This code is licenced under the GPL - * Feel free to contact me if any questions - * - * @2017 - * Hardik Bagdi (hbagdi1@binghamton.edu) - * Changes for Compatibility with Linux 4.9 to use iov_iter - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ksocket.h" - -#define BUF_SIZE 100 - -static int port = 4444; -module_param(port, int, 0444); - -int udp_srv(void *arg) -{ - ksocket_t sockfd_srv, sockfd_cli; - struct sockaddr_in addr_srv; - struct sockaddr_in addr_cli; - char buf[BUF_SIZE]; - int addr_len, len; - -#ifdef KSOCKET_ADDR_SAFE - mm_segment_t old_fs; - old_fs = get_fs(); - set_fs(KERNEL_DS); -#endif - - sockfd_srv = sockfd_cli = NULL; - memset(&addr_cli, 0, sizeof(addr_cli)); - memset(&addr_srv, 0, sizeof(addr_srv)); - addr_srv.sin_family = AF_INET; - addr_srv.sin_port = htons(port); - addr_srv.sin_addr.s_addr = INADDR_ANY; - addr_len = sizeof(struct sockaddr_in); - - sockfd_srv = ksocket(AF_INET, SOCK_DGRAM, 0); - printk("sockfd_srv = 0x%p\n", sockfd_srv); - if (sockfd_srv == NULL) - { - printk("socket failed\n"); - return -1; - } - if (kbind(sockfd_srv, (struct sockaddr *)&addr_srv, addr_len) < 0) - { - printk("bind failed\n"); - return -1; - } - - while (1) - { - memset(buf, 0, sizeof(buf)); - len = krecvfrom(sockfd_srv, buf, sizeof(buf), 0,(struct sockaddr*)&addr_cli,&addr_len); - if (len > 0) - { - printk("got message : %s\n", buf); - ksendto(sockfd_srv, buf, len, 0,(struct sockaddr*)&addr_cli,addr_len); - if (memcmp(buf, "quit", 4) == 0) - break; - } - } - - kclose(sockfd_srv); -#ifdef KSOCKET_ADDR_SAFE - set_fs(old_fs); -#endif - - return 0; -} - -static int ksocket_udp_srv_init(void) -{ - kthread_run(udp_srv, NULL, "tcp_srv_kthread"); - - printk("ksocket udp srv init ok\n"); - return 0; -} - -static void ksocket_udp_srv_exit(void) -{ - printk("ksocket udp srv exit\n"); -} - -module_init(ksocket_udp_srv_init); -module_exit(ksocket_udp_srv_exit); - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/samples/tcp/client/Makefile b/samples/tcp/client/Makefile new file mode 100644 index 0000000..c7a4225 --- /dev/null +++ b/samples/tcp/client/Makefile @@ -0,0 +1,16 @@ +KBUILD_EXTRA_SYMBOLS := ../../../src/Module.symvers + +obj-m := tcp_client.o + +KDIR := /lib/modules/$(shell uname -r)/build +PWD := $(shell pwd) + +EXTRA_CFLAGS += -I$(PWD) + +default: modules + +modules: + $(MAKE) -C $(KDIR) M=$(PWD) modules + +clean: + rm -rf *.o *.ko *.mod.* *.symvers *.order .*cmd $(USER_BINARY) diff --git a/samples/tcp/client/ksocket.h b/samples/tcp/client/ksocket.h new file mode 100644 index 0000000..807a582 --- /dev/null +++ b/samples/tcp/client/ksocket.h @@ -0,0 +1,50 @@ +/* + * ksocket project + * BSD-style socket APIs for kernel 2.6 developers + * + * @2007-2008, China + * @song.xian-guang@hotmail.com (MSN Accounts) + * + * This code is licenced under the GPL + * Feel free to contact me if any questions + * + * @2017 + * Hardik Bagdi (hbagdi1@binghamton.edu) + * Changes for Compatibility with Linux 4.9 to use iov_iter + * + * @2025 + * Mephistolist (cloneozone@gmail.com) + * Changes for kernels 5.11 through at least 6.16. + */ +#ifndef _ksocket_h_ +#define _ksocket_h_ + +struct socket; +struct sockaddr; +struct in_addr; +typedef struct socket * ksocket_t; + +/* BSD socket APIs prototype declaration */ +extern ksocket_t ksocket(int domain, int type, int protocol); +extern int kshutdown(ksocket_t socket, int how); +extern int kclose(ksocket_t socket); + +extern int kbind(ksocket_t socket, struct sockaddr *address, int address_len); +extern int klisten(ksocket_t socket, int backlog); +extern int kconnect(ksocket_t socket, struct sockaddr *address, int address_len); +extern ksocket_t kaccept(ksocket_t socket, struct sockaddr *address, int *address_len); + +extern ssize_t krecv(ksocket_t socket, void *buffer, size_t length, int flags); +extern ssize_t ksend(ksocket_t socket, const void *buffer, size_t length, int flags); +extern ssize_t krecvfrom(ksocket_t socket, void * buffer, size_t length, int flags, struct sockaddr * address, int * address_len); +extern ssize_t ksendto(ksocket_t socket, void *message, size_t length, int flags, const struct sockaddr *dest_addr, int dest_len); + +extern int kgetsockname(ksocket_t socket, struct sockaddr *address, int *address_len); +extern int kgetpeername(ksocket_t socket, struct sockaddr *address, int *address_len); +extern int ksetsockopt(ksocket_t socket, int level, int optname, void *optval, int optlen); +extern int kgetsockopt(ksocket_t socket, int level, int optname, void *optval, int *optlen); + +extern unsigned int inet_addr(char* ip); +extern char *inet_ntoa(struct in_addr *in); /* DO NOT forget to kfree the return pointer */ + +#endif /* !_ksocket_h_ */ diff --git a/samples/tcp/client/tcp_client.c b/samples/tcp/client/tcp_client.c new file mode 100644 index 0000000..5e44803 --- /dev/null +++ b/samples/tcp/client/tcp_client.c @@ -0,0 +1,85 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ksocket.h" + +#define DEFAULT_IP "127.0.0.1" +#define DEFAULT_PORT 12345 + +static struct task_struct *client_thread; + +static int tcp_client_fn(void *data) { + struct socket *sock; + struct sockaddr_in server_addr; + char *ip = (char *)data ? (char *)data : DEFAULT_IP; + int port = DEFAULT_PORT; + const char *message = "Hello from kernel TCP client!"; + int ret; + + // Create TCP socket + sock = ksocket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (!sock) { + printk(KERN_ERR "[tcp_client] Failed to create socket\n"); + return -ENOMEM; + } + + // Prepare server address + memset(&server_addr, 0, sizeof(server_addr)); + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(port); + server_addr.sin_addr.s_addr = inet_addr(ip); + + // Connect to server + ret = kconnect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)); + if (ret < 0) { + printk(KERN_ERR "[tcp_client] Failed to connect to %s:%d (err=%d)\n", ip, port, ret); + kclose(sock); + return ret; + } + + printk(KERN_INFO "[tcp_client] Connected to %s:%d\n", ip, port); + + // Send message + ret = ksend(sock, (void *)message, strlen(message), 0); + if (ret < 0) { + printk(KERN_ERR "[tcp_client] Failed to send message (err=%d)\n", ret); + kclose(sock); + return ret; + } + + printk(KERN_INFO "[tcp_client] Sent: %s\n", message); + + kclose(sock); + return 0; +} + +static int __init tcp_client_init(void) { + printk(KERN_INFO "[tcp_client] Initializing\n"); + client_thread = kthread_run(tcp_client_fn, NULL, "tcp_client"); + if (IS_ERR(client_thread)) { + printk(KERN_ERR "[tcp_client] Failed to create thread\n"); + return PTR_ERR(client_thread); + } + return 0; +} + +static void __exit tcp_client_exit(void) { + if (client_thread) + kthread_stop(client_thread); + printk(KERN_INFO "[tcp_client] Exited\n"); +} + +module_init(tcp_client_init); +module_exit(tcp_client_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mephistolist"); +MODULE_DESCRIPTION("Simple TCP Client using ksocket"); diff --git a/samples/tcp/server/Makefile b/samples/tcp/server/Makefile new file mode 100644 index 0000000..930cc94 --- /dev/null +++ b/samples/tcp/server/Makefile @@ -0,0 +1,16 @@ +KBUILD_EXTRA_SYMBOLS := ../../../src/Module.symvers + +obj-m := tcp_server.o + +KDIR := /lib/modules/$(shell uname -r)/build +PWD := $(shell pwd) + +EXTRA_CFLAGS += -I$(PWD) + +default: modules + +modules: + $(MAKE) -C $(KDIR) M=$(PWD) modules + +clean: + rm -rf *.o *.ko *.mod.* *.symvers *.order .*cmd $(USER_BINARY) diff --git a/sample/udp/ksocket.h b/samples/tcp/server/ksocket.h similarity index 94% rename from sample/udp/ksocket.h rename to samples/tcp/server/ksocket.h index 9884f5d..d32fa99 100644 --- a/sample/udp/ksocket.h +++ b/samples/tcp/server/ksocket.h @@ -11,9 +11,11 @@ * @2017 * Hardik Bagdi (hbagdi1@binghamton.edu) * Changes for Compatibility with Linux 4.9 to use iov_iter - * + * + * @2025 + * Mephistolist (cloneozone@gmail.com) + * Changes for kernels 5.11 through at least 6.16. */ - #ifndef _ksocket_h_ #define _ksocket_h_ diff --git a/samples/tcp/server/tcp_server.c b/samples/tcp/server/tcp_server.c new file mode 100644 index 0000000..21227c0 --- /dev/null +++ b/samples/tcp/server/tcp_server.c @@ -0,0 +1,161 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ksocket.h" + +#define SERVER_PORT 12345 +#define BACKLOG 5 +#define RECV_BUF_SZ 1024 + +static struct task_struct *server_thread; +static ksocket_t listen_sock = NULL; + +static int tcp_server_thread(void *data) { + struct sockaddr_in addr; + int addrlen = sizeof(addr); + int ret; + + pr_info("tcp_server: thread starting (ksocket API)\n"); + + /* Create listening socket via ksocket() */ + listen_sock = ksocket(AF_INET, SOCK_STREAM, 0); + if (IS_ERR(listen_sock)) { + long err = PTR_ERR(listen_sock); + pr_err("tcp_server: ksocket() failed: %ld\n", err); + listen_sock = NULL; + return (int)err; + } + + /* (Optional) allow immediate port reuse */ + { + int optval = 1; + ksetsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, + (void *)&optval, sizeof(optval)); + } + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(INADDR_ANY); + addr.sin_port = htons(SERVER_PORT); + + ret = kbind(listen_sock, (struct sockaddr *)&addr, addrlen); + if (ret < 0) { + pr_err("tcp_server: kbind() failed: %d\n", ret); + kclose(listen_sock); + listen_sock = NULL; + return ret; + } + + ret = klisten(listen_sock, BACKLOG); + if (ret < 0) { + pr_err("tcp_server: klisten() failed: %d\n", ret); + kclose(listen_sock); + listen_sock = NULL; + return ret; + } + + pr_info("tcp_server: listening on port %d\n", SERVER_PORT); + + /* Accept loop */ + while (!kthread_should_stop()) { + ksocket_t client = NULL; + struct sockaddr_in peer; + int peerlen = sizeof(peer); + int n; + char *buf; + + /* Accept (blocking) */ + client = kaccept(listen_sock, (struct sockaddr *)&peer, &peerlen); + if (IS_ERR_OR_NULL(client)) { + long err = IS_ERR(client) ? PTR_ERR(client) : -ENOTCONN; + + /* Exit cleanly if we’re stopping */ + if (kthread_should_stop()) + break; + + /* Transient failure: back off a bit and retry */ + pr_debug("tcp_server: kaccept() error ptr=%p err=%ld; retrying\n", + client, err); + msleep(100); + continue; + } + + pr_info("tcp_server: accepted client=%p\n", client); + + /* One recv then close (demo behavior) */ + buf = kmalloc(RECV_BUF_SZ, GFP_KERNEL); + if (!buf) { + pr_err("tcp_server: kmalloc failed\n"); + kclose(client); + continue; + } + + n = krecv(client, buf, RECV_BUF_SZ - 1, 0); + if (n > 0) { + buf[n] = '\0'; + pr_info("tcp_server: received (%d bytes): %s\n", n, buf); + } else { + pr_info("tcp_server: krecv() returned %d\n", n); + } + + kfree(buf); + kclose(client); + } + + /* Cleanup listening socket */ + if (listen_sock) { + pr_info("tcp_server: closing listen socket %p\n", listen_sock); + kclose(listen_sock); + listen_sock = NULL; + } + + pr_info("tcp_server: thread exiting\n"); + return 0; +} + +static int __init tcp_server_init(void) { + pr_info("tcp_server: Loading (starting thread)\n"); + server_thread = kthread_run(tcp_server_thread, NULL, "tcp_server_thread"); + if (IS_ERR(server_thread)) { + int err = PTR_ERR(server_thread); + pr_err("tcp_server: kthread_run failed: %d\n", err); + server_thread = NULL; + return err; + } + return 0; +} + +static void __exit tcp_server_exit(void) { + pr_info("tcp_server: Unloading\n"); + + /* Ask the listen socket to shut down so accept/recv unblocks */ + if (listen_sock) { + kshutdown(listen_sock, 2 /* SHUT_RDWR */); + } + + if (server_thread) { + kthread_stop(server_thread); + server_thread = NULL; + } + + if (listen_sock) { + kclose(listen_sock); + listen_sock = NULL; + } + + pr_info("tcp_server: Unloaded\n"); +} + +module_init(tcp_server_init); +module_exit(tcp_server_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mephistolist"); +MODULE_DESCRIPTION("Kernel-space TCP server using ksocket wrapper API"); diff --git a/samples/udp/client/Makefile b/samples/udp/client/Makefile new file mode 100644 index 0000000..fddc4d1 --- /dev/null +++ b/samples/udp/client/Makefile @@ -0,0 +1,14 @@ +KBUILD_EXTRA_SYMBOLS := ../../../src/Module.symvers + +obj-m := udp_client.o + +KDIR := /lib/modules/$(shell uname -r)/build +PWD := $(shell pwd) +EXTRA_CFLAGS += -I$(PWD) + +.PHONY: all clean +all: + $(MAKE) -C $(KDIR) M=$(PWD) modules + +clean: + $(MAKE) -C $(KDIR) M=$(PWD) clean diff --git a/sample/tcp/ksocket.h b/samples/udp/client/ksocket.h similarity index 94% rename from sample/tcp/ksocket.h rename to samples/udp/client/ksocket.h index 66368f1..d32fa99 100644 --- a/sample/tcp/ksocket.h +++ b/samples/udp/client/ksocket.h @@ -11,8 +11,11 @@ * @2017 * Hardik Bagdi (hbagdi1@binghamton.edu) * Changes for Compatibility with Linux 4.9 to use iov_iter + * + * @2025 + * Mephistolist (cloneozone@gmail.com) + * Changes for kernels 5.11 through at least 6.16. */ - #ifndef _ksocket_h_ #define _ksocket_h_ diff --git a/samples/udp/client/udp_client.c b/samples/udp/client/udp_client.c new file mode 100644 index 0000000..3101851 --- /dev/null +++ b/samples/udp/client/udp_client.c @@ -0,0 +1,93 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ksocket.h" + +#define SERVER_PORT 4444 +#define SERVER_IP "127.0.0.1" +#define TIMEOUT_MS 2000 // 2 seconds + +static struct task_struct *client_thread; + +static int udp_client_fn(void *data) { + struct socket *sock; + struct sockaddr_in server_addr; + char buffer[256]; + const char *message = "Hello UDP Server"; + int ret; + + sock = ksocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (!sock) { + printk(KERN_ERR "[udp_client] Failed to create socket\n"); + return -ENOMEM; + } + + memset(&server_addr, 0, sizeof(server_addr)); + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(SERVER_PORT); + server_addr.sin_addr.s_addr = inet_addr(SERVER_IP); // <- use your exported symbol + + // Send message + ret = ksendto(sock, (void *)message, strlen(message), 0, + (struct sockaddr *)&server_addr, sizeof(server_addr)); + if (ret < 0) { + printk(KERN_ERR "[udp_client] Failed to send message (%d)\n", ret); + kclose(sock); + return ret; + } + + printk(KERN_INFO "[udp_client] Sent: %s\n", message); + + // Try receive (non-blocking with manual timeout loop) + { + unsigned long timeout = jiffies + msecs_to_jiffies(TIMEOUT_MS); + int addr_len = sizeof(server_addr); + ret = -EAGAIN; + + while (time_before(jiffies, timeout) && !kthread_should_stop()) { + ret = krecvfrom(sock, buffer, sizeof(buffer) - 1, MSG_DONTWAIT, + (struct sockaddr *)&server_addr, &addr_len); + if (ret >= 0) { + buffer[ret] = '\0'; + printk(KERN_INFO "[udp_client] Received: %s\n", buffer); + break; + } + msleep(50); + } + + if (ret < 0) + printk(KERN_WARNING "[udp_client] No response from server (timeout)\n"); + } + + kclose(sock); + return 0; +} + +static int __init udp_client_init(void) { + printk(KERN_INFO "[udp_client] Initializing\n"); + client_thread = kthread_run(udp_client_fn, NULL, "udp_client"); + if (IS_ERR(client_thread)) { + printk(KERN_ERR "[udp_client] Failed to create thread\n"); + return PTR_ERR(client_thread); + } + return 0; +} + +static void __exit udp_client_exit(void) { + if (client_thread) + kthread_stop(client_thread); + printk(KERN_INFO "[udp_client] Exited\n"); +} + +module_init(udp_client_init); +module_exit(udp_client_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mephistolist"); +MODULE_DESCRIPTION("Simple UDP Client using ksocket API"); diff --git a/samples/udp/server/Makefile b/samples/udp/server/Makefile new file mode 100644 index 0000000..cf9a8c7 --- /dev/null +++ b/samples/udp/server/Makefile @@ -0,0 +1,14 @@ +KBUILD_EXTRA_SYMBOLS := ../../../src/Module.symvers + +obj-m := udp_server.o + +KDIR := /lib/modules/$(shell uname -r)/build +PWD := $(shell pwd) +EXTRA_CFLAGS += -I$(PWD) + +.PHONY: all clean +all: + $(MAKE) -C $(KDIR) M=$(PWD) modules + +clean: + $(MAKE) -C $(KDIR) M=$(PWD) clean diff --git a/samples/udp/server/ksocket.h b/samples/udp/server/ksocket.h new file mode 100644 index 0000000..d32fa99 --- /dev/null +++ b/samples/udp/server/ksocket.h @@ -0,0 +1,50 @@ +/* + * ksocket project + * BSD-style socket APIs for kernel 2.6 developers + * + * @2007-2008, China + * @song.xian-guang@hotmail.com (MSN Accounts) + * + * This code is licenced under the GPL + * Feel free to contact me if any questions + * + * @2017 + * Hardik Bagdi (hbagdi1@binghamton.edu) + * Changes for Compatibility with Linux 4.9 to use iov_iter + * + * @2025 + * Mephistolist (cloneozone@gmail.com) + * Changes for kernels 5.11 through at least 6.16. + */ +#ifndef _ksocket_h_ +#define _ksocket_h_ + +struct socket; +struct sockaddr; +struct in_addr; +typedef struct socket * ksocket_t; + +/* BSD socket APIs prototype declaration */ +extern ksocket_t ksocket(int domain, int type, int protocol); +extern int kshutdown(ksocket_t socket, int how); +extern int kclose(ksocket_t socket); + +extern int kbind(ksocket_t socket, struct sockaddr *address, int address_len); +extern int klisten(ksocket_t socket, int backlog); +extern int kconnect(ksocket_t socket, struct sockaddr *address, int address_len); +extern ksocket_t kaccept(ksocket_t socket, struct sockaddr *address, int *address_len); + +extern ssize_t krecv(ksocket_t socket, void *buffer, size_t length, int flags); +extern ssize_t ksend(ksocket_t socket, const void *buffer, size_t length, int flags); +extern ssize_t krecvfrom(ksocket_t socket, void * buffer, size_t length, int flags, struct sockaddr * address, int * address_len); +extern ssize_t ksendto(ksocket_t socket, void *message, size_t length, int flags, const struct sockaddr *dest_addr, int dest_len); + +extern int kgetsockname(ksocket_t socket, struct sockaddr *address, int *address_len); +extern int kgetpeername(ksocket_t socket, struct sockaddr *address, int *address_len); +extern int ksetsockopt(ksocket_t socket, int level, int optname, void *optval, int optlen); +extern int kgetsockopt(ksocket_t socket, int level, int optname, void *optval, int *optlen); + +extern unsigned int inet_addr(char* ip); +extern char *inet_ntoa(struct in_addr *in); /* DO NOT forget to kfree the return pointer */ + +#endif /* !_ksocket_h_ */ diff --git a/samples/udp/server/udp_server.c b/samples/udp/server/udp_server.c new file mode 100644 index 0000000..c9afac0 --- /dev/null +++ b/samples/udp/server/udp_server.c @@ -0,0 +1,83 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ksocket.h" + +int udp_server_fn(void *data); + +static struct task_struct *server_thread; + +int udp_server_fn(void *data) { + struct socket *sock; + struct sockaddr_in addr, src_addr; + int ret, len; + char buffer[256]; + + sock = ksocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (!sock) { + printk(KERN_ERR "UDP Server: Failed to create socket\n"); + return -1; + } + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(INADDR_ANY); + addr.sin_port = htons(4444); + + ret = kbind(sock, (struct sockaddr *)&addr, sizeof(addr)); + if (ret < 0) { + printk(KERN_ERR "UDP Server: Bind failed (%d)\n", ret); + kclose(sock); + return ret; + } + + printk(KERN_INFO "UDP Server: Listening on port 4444\n"); + + while (!kthread_should_stop()) { + memset(buffer, 0, sizeof(buffer)); + len = sizeof(src_addr); + + ret = krecvfrom(sock, buffer, sizeof(buffer) - 1, 0, + (struct sockaddr *)&src_addr, &len); + if (ret > 0) { + buffer[ret] = '\0'; + printk(KERN_INFO "UDP Server: Received '%s'\n", buffer); + + ksendto(sock, "ACK from UDP Server", 19, 0, + (struct sockaddr *)&src_addr, sizeof(src_addr)); + } + + msleep(100); // this isn’t in your API, but it’s fine + } + + kclose(sock); + return 0; +} + +static int __init udp_server_init(void) { + server_thread = kthread_run(udp_server_fn, NULL, "udp_server"); + if (IS_ERR(server_thread)) { + printk(KERN_ERR "UDP Server: Failed to create thread\n"); + return PTR_ERR(server_thread); + } + return 0; +} + +static void __exit udp_server_exit(void) { + if (server_thread) + kthread_stop(server_thread); + printk(KERN_INFO "UDP Server: Exited\n"); +} + +module_init(udp_server_init); +module_exit(udp_server_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Simple UDP Server Example using ksocket API"); +MODULE_AUTHOR("Mephistolist"); diff --git a/src/Kconfig b/src/Kconfig new file mode 100644 index 0000000..587d661 --- /dev/null +++ b/src/Kconfig @@ -0,0 +1,5 @@ +config KSOCKET + bool "Kernel Socket API helper" + help + Provides a simple kernel-space TCP/UDP socket API wrapper. + Needed for your custom kernel networking code. diff --git a/src/Makefile b/src/Makefile index 19d8745..17a6d88 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,5 +1,8 @@ obj-m += ksocket.o +MARCH=$(gcc -Q -march=native --help=target|grep -m1 march=|awk '{print $2}') +EXTRA_CFLAGS += -Wall -Wextra -Wno-unused-parameter -march=$(MARCH) -pedantic -pipe -O2 + all: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules clean: diff --git a/src/ksocket.c b/src/ksocket.c index 1a4f74f..a03175f 100644 --- a/src/ksocket.c +++ b/src/ksocket.c @@ -11,77 +11,50 @@ * @2017 * Hardik Bagdi (hbagdi1@binghamton.edu) * Changes for Compatibility with Linux 4.9 to use iov_iter - * + * + * @2025 + * Mephistolist (cloneozone@gmail.com) + * Changes for kernels 5.11 through at least 6.16. */ #include #include #include +#include #include #include #include #include #include +#include #include "ksocket.h" -//#include "nested.h" -//#include "sxgdebug.h" #define KSOCKET_NAME "ksocket" -#define KSOCKET_VERSION "0.0.2" -#define KSOCKET_DESCPT "BSD-style socket APIs for kernel 2.6 developers" -#define KSOCKET_AUTHOR "msn : song.xian-guang@hotmail.com\n"\ - "blog: http://sxg.cublog.cn" -#define KSOCKET_DATE "2008-05-15" +#define KSOCKET_VERSION "0.0.3" +#define KSOCKET_DESCPT "BSD-style socket APIs for kernels 5.11 - 6.16.x" +#define KSOCKET_AUTHOR "mail : cloneozone@gmail.com\n"\ + "blog: https://myresume.sh" +#define KSOCKET_DATE "2025-08-03" MODULE_AUTHOR(KSOCKET_AUTHOR); MODULE_DESCRIPTION(KSOCKET_NAME"-"KSOCKET_VERSION"\n"KSOCKET_DESCPT); MODULE_LICENSE("Dual BSD/GPL"); -/* -static void (*origSk)(struct sock *sk, int bytes) = NULL; - -static void yh_sk_data_ready(struct sock *sk, int bytes) -{ - if (origSk) { - (*origSk)(sk, bytes); - } - - wake_up_rcv(); - return; -} -*/ - -ksocket_t ksocket(int domain, int type, int protocol) -{ +ksocket_t ksocket(int domain, int type, int protocol) { struct socket *sk = NULL; int ret = 0; ret = sock_create(domain, type, protocol, &sk); - if (ret < 0) - { + if (ret < 0) { printk(KERN_INFO "sock_create failed\n"); return NULL; } - /* - if (sk && sk->sk) { - if (sk->sk->sk_data_ready) { - origSk = sk->sk->sk_data_ready; - sk->sk->sk_data_ready = yh_sk_data_ready; - } else { - printk(KERN_INFO "sk->sk->sk_data_ready is NULL\n"); - } - } else { - printk(KERN_INFO "sk or sk->sk is NULL\n"); - } - */ - printk("sock_create sk= 0x%p\n", sk); return sk; } -int kbind(ksocket_t socket, struct sockaddr *address, int address_len) -{ +int kbind(ksocket_t socket, struct sockaddr *address, int address_len) { struct socket *sk; int ret = 0; @@ -92,23 +65,22 @@ int kbind(ksocket_t socket, struct sockaddr *address, int address_len) return ret; } -int klisten(ksocket_t socket, int backlog) -{ +int klisten(ksocket_t socket, int backlog) { struct socket *sk; int ret; sk = (struct socket *)socket; - if ((unsigned)backlog > SOMAXCONN) + if ((unsigned)backlog > SOMAXCONN) { backlog = SOMAXCONN; + } ret = sk->ops->listen(sk, backlog); return ret; } -int kconnect(ksocket_t socket, struct sockaddr *address, int address_len) -{ +int kconnect(ksocket_t socket, struct sockaddr *address, int address_len) { struct socket *sk; int ret; @@ -118,343 +90,212 @@ int kconnect(ksocket_t socket, struct sockaddr *address, int address_len) return ret; } -ksocket_t kaccept(ksocket_t socket, struct sockaddr *address, int *address_len) -{ - struct socket *sk; - struct socket *new_sk = NULL; - int ret; - - sk = (struct socket *)socket; - - printk("family = %d, type = %d, protocol = %d\n", - sk->sk->sk_family, sk->type, sk->sk->sk_protocol); - //new_sk = sock_alloc(); - //sock_alloc() is not exported, so i use sock_create() instead - ret = sock_create(sk->sk->sk_family, sk->type, sk->sk->sk_protocol, &new_sk); - if (ret < 0) - return NULL; - if (!new_sk) - return NULL; - - new_sk->type = sk->type; - new_sk->ops = sk->ops; - - ret = sk->ops->accept(sk, new_sk, 0 /*sk->file->f_flags*/); - if (ret < 0) - goto error_kaccept; - - if (address) - { - ret = new_sk->ops->getname(new_sk, address, address_len, 2); - if (ret < 0) - goto error_kaccept; - } - - return new_sk; - -error_kaccept: - sock_release(new_sk); - return NULL; +ksocket_t kaccept(ksocket_t socket, struct sockaddr *address, int *address_len) { + struct socket *sk = (struct socket *)socket; + struct socket *new_sk = NULL; + int ret; + + printk("family = %d, type = %d, protocol = %d\n", + sk->sk->sk_family, sk->type, sk->sk->sk_protocol); + + // Create a new socket + ret = sock_create(sk->sk->sk_family, sk->type, sk->sk->sk_protocol, &new_sk); + if (ret < 0 || !new_sk) + return NULL; + + new_sk->type = sk->type; + new_sk->ops = sk->ops; + + // Accept connection + ret = sk->ops->accept(sk, new_sk, 0 /*sk->file->f_flags*/); + if (ret < 0) { + sock_release(new_sk); + return NULL; + } + + // Retrieve peer address if requested + if (address) { + ret = new_sk->ops->getname(new_sk, address, 1); + if (ret < 0) { + sock_release(new_sk); + return NULL; + } + } + + return new_sk; } -ssize_t krecv(ksocket_t socket, void *buffer, size_t length, int flags) -{ - struct socket *sk; - struct msghdr msg; - struct iovec iov; - int ret; -#ifndef KSOCKET_ADDR_SAFE - mm_segment_t old_fs; -#endif - - memset(&msg,0,sizeof(msg)); - sk = (struct socket *)socket; +ssize_t krecv(ksocket_t socket, void *buffer, size_t length, int flags) { + struct socket *sk = (struct socket *)socket; + struct msghdr msg = { 0 }; + struct kvec iov; - iov.iov_base = (void *)buffer; - iov.iov_len = (__kernel_size_t)length; - - //type - msg.msg_iter.type = READ; - //address - msg.msg_name = NULL; - msg.msg_namelen = 0; - //msg_iter - msg.msg_iter.iov = &iov; - msg.msg_iter.iov_offset = 0; - msg.msg_iter.count = iov.iov_len; - msg.msg_iter.nr_segs = 1; - //control - msg.msg_control = NULL; - msg.msg_controllen = 0; - - /* - * msg.msg_iov->iov_base is declared as follows: - * void __user *iov_base; - * which means there is an user space pointer in 'msg' - * use set_fs(KERNEL_DS) to make the pointer safe to kernel space - */ -#ifndef KSOCKET_ADDR_SAFE - old_fs = get_fs(); - set_fs(KERNEL_DS); -#endif - //hardik - ret = sock_recvmsg(sk, &msg, flags); -#ifndef KSOCKET_ADDR_SAFE - set_fs(old_fs); -#endif - if (ret < 0) - goto out_krecv; - //ret = msg.msg_iov.iov_len;//? - -out_krecv: - return ret; + iov.iov_base = buffer; + iov.iov_len = length; + return kernel_recvmsg(sk, &msg, &iov, 1, length, flags); } -ssize_t ksend(ksocket_t socket, const void *buffer, size_t length, int flags) -{ +ssize_t ksend(ksocket_t socket, const void *buffer, size_t length, int flags) { struct socket *sk; - struct msghdr msg; - struct iovec iov; + struct msghdr msg = {0}; + struct kvec iov; int len; -#ifndef KSOCKET_ADDR_SAFE - mm_segment_t old_fs; -#endif sk = (struct socket *)socket; iov.iov_base = (void *)buffer; - iov.iov_len = (__kernel_size_t)length; - - //type - msg.msg_iter.type = READ; - //address - msg.msg_name = NULL; - msg.msg_namelen = 0; - //msg_iter - msg.msg_iter.iov = &iov; - msg.msg_iter.iov_offset = 0; - msg.msg_iter.count = iov.iov_len; - msg.msg_iter.nr_segs = 1; - //control - msg.msg_control = NULL; - msg.msg_controllen = 0; - - msg.msg_flags = flags; + iov.iov_len = length; -#ifndef KSOCKET_ADDR_SAFE - old_fs = get_fs(); - set_fs(KERNEL_DS); -#endif - //hardik - len = sock_sendmsg(sk, &msg);//? -#ifndef KSOCKET_ADDR_SAFE - set_fs(old_fs); -#endif - - return len;//len ? + len = kernel_sendmsg(sk, &msg, &iov, 1, length); + return len; } -int kshutdown(ksocket_t socket, int how) -{ +int kshutdown(ksocket_t socket, int how) { struct socket *sk; int ret = 0; sk = (struct socket *)socket; - if (sk) + if (sk) { ret = sk->ops->shutdown(sk, how); - + } return ret; } //TODO: ? -int kclose(ksocket_t socket) -{ +int kclose(ksocket_t socket) { struct socket *sk; int ret; sk = (struct socket *)socket; ret = sk->ops->release(sk); - if (sk) + if (sk) { sock_release(sk); - + } return ret; } -ssize_t krecvfrom(ksocket_t socket, void * buffer, size_t length, - int flags, struct sockaddr * address, - int * address_len) -{ +ssize_t krecvfrom(ksocket_t socket, void *buffer, size_t length, + int flags, struct sockaddr *address, int *address_len) { struct socket *sk; - struct msghdr msg; - struct iovec iov; - int len; -#ifndef KSOCKET_ADDR_SAFE - mm_segment_t old_fs; -#endif + struct msghdr msg = {0}; + struct kvec iov; + int ret; sk = (struct socket *)socket; - iov.iov_base = (void *)buffer; - iov.iov_len = (__kernel_size_t)length; - - //type - msg.msg_iter.type = READ; - //address - msg.msg_name = address; - msg.msg_namelen = 128; - //msg_iter - msg.msg_iter.iov = &iov; - msg.msg_iter.iov_offset = 0; - msg.msg_iter.count = iov.iov_len; - msg.msg_iter.nr_segs = 1; - //control - msg.msg_control = NULL; - msg.msg_controllen = 0; - -#ifndef KSOCKET_ADDR_SAFE - old_fs = get_fs(); - set_fs(KERNEL_DS); -#endif - //hardik - len = sock_recvmsg(sk, &msg, flags); -#ifndef KSOCKET_ADDR_SAFE - set_fs(old_fs); -#endif - - if (address) - { + // Set up kvec for kernel buffer + iov.iov_base = buffer; + iov.iov_len = length; + + // Set the msg_name and msg_namelen if address is requested + if (address && address_len) { + msg.msg_name = address; + msg.msg_namelen = *address_len; + } + + ret = kernel_recvmsg(sk, &msg, &iov, 1, length, flags); + + // Update actual received address length + if (ret >= 0 && address_len && msg.msg_namelen > 0) { *address_len = msg.msg_namelen; } - - return len; + return ret; } ssize_t ksendto(ksocket_t socket, void *message, size_t length, - int flags, const struct sockaddr *dest_addr, - int dest_len) -{ - struct socket *sk; - struct msghdr msg; - struct iovec iov; - int len; -#ifndef KSOCKET_ADDR_SAFE - mm_segment_t old_fs; -#endif - - sk = (struct socket *)socket; - - iov.iov_base = (void *)message; - iov.iov_len = (__kernel_size_t)length; + int flags, const struct sockaddr *dest_addr, int dest_len) { + struct socket *sk = (struct socket *)socket; + struct msghdr msg = {0}; + struct kvec iov; + int ret; - //type - msg.msg_iter.type = READ; - //msg_iter - msg.msg_iter.iov = &iov; - msg.msg_iter.iov_offset = 0; - msg.msg_iter.count = iov.iov_len; - msg.msg_iter.nr_segs = 1; - //control - msg.msg_control = NULL; - msg.msg_controllen = 0; + // Set up kvec for kernel-safe buffer + iov.iov_base = message; + iov.iov_len = length; - msg.msg_flags = flags; - if (dest_addr) - { + // Populate destination if provided + if (dest_addr) { msg.msg_name = (void *)dest_addr; msg.msg_namelen = dest_len; } -#ifndef KSOCKET_ADDR_SAFE - old_fs = get_fs(); - set_fs(KERNEL_DS); -#endif - //hardik - len = sock_sendmsg(sk, &msg);//? -#ifndef KSOCKET_ADDR_SAFE - set_fs(old_fs); -#endif - - return len;//len ? -} + msg.msg_flags = flags; -int kgetsockname(ksocket_t socket, struct sockaddr *address, int *address_len) -{ - struct socket *sk; - int ret; - - sk = (struct socket *)socket; - ret = sk->ops->getname(sk, address, address_len, 0); - + // Use kernel_sendmsg for modern compatibility + ret = kernel_sendmsg(sk, &msg, &iov, 1, length); return ret; } -int kgetpeername(ksocket_t socket, struct sockaddr *address, int *address_len) -{ - struct socket *sk; +int kgetsockname(ksocket_t socket, struct sockaddr *address, int *address_len) { + struct socket *sk = (struct socket *)socket; + struct sockaddr_storage addr; int ret; - - sk = (struct socket *)socket; - ret = sk->ops->getname(sk, address, address_len, 1); - - return ret; + + ret = kernel_getsockname(sk, (struct sockaddr *)&addr); + if (ret < 0) { + return ret; + } + if (address) { + memcpy(address, &addr, sizeof(addr)); + if (address_len) { + *address_len = sizeof(addr); + } + } + + return 0; } -int ksetsockopt(ksocket_t socket, int level, int optname, void *optval, int optlen) -{ - struct socket *sk; +int kgetpeername(ksocket_t socket, struct sockaddr *address, int *address_len) { + struct socket *sk = (struct socket *)socket; + struct sockaddr_storage addr; int ret; -#ifndef KSOCKET_ADDR_SAFE - mm_segment_t old_fs; -#endif - sk = (struct socket *)socket; + ret = kernel_getpeername(sk, (struct sockaddr *)&addr); + if (ret < 0) { + return ret; + } + if (address) { + memcpy(address, &addr, sizeof(addr)); + if (address_len) + *address_len = sizeof(addr); + } -#ifndef KSOCKET_ADDR_SAFE - old_fs = get_fs(); - set_fs(KERNEL_DS); -#endif + return 0; +} - if (level == SOL_SOCKET) - ret = sock_setsockopt(sk, level, optname, optval, optlen); - else - ret = sk->ops->setsockopt(sk, level, optname, optval, optlen); +int ksetsockopt(ksocket_t socket, int level, int optname, void *optval, int optlen) { + struct socket *sk = (struct socket *)socket; + sockptr_t opt_ptr; + int ret; -#ifndef KSOCKET_ADDR_SAFE - set_fs(old_fs); -#endif + // Wrap kernel pointer as a safe sockptr_t + opt_ptr = KERNEL_SOCKPTR(optval); + if (level == SOL_SOCKET) { + ret = sock_setsockopt(sk, level, optname, opt_ptr, optlen); + } + else { + ret = sk->ops->setsockopt(sk, level, optname, opt_ptr, optlen); + } return ret; } -int kgetsockopt(ksocket_t socket, int level, int optname, void *optval, int *optlen) -{ -/* struct socket *sk; +int kgetsockopt(ksocket_t socket, int level, int optname, void *optval, int *optlen) { + struct socket *sk = (struct socket *)socket; int ret; - mm_segment_t old_fs; - - sk = (struct socket *)socket; - - old_fs = get_fs(); - set_fs(KERNEL_DS); - if (level == SOL_SOCKET) - ret = sock_getsockopt(sk, level, optname, optval, optlen); - else - ret = sk->ops->getsockopt(sk, level, optname, optval, optlen); - - set_fs(old_fs); + if (!sk || !sk->ops || !sk->ops->getsockopt) { + return -ENOSYS; + } + ret = sk->ops->getsockopt(sk, level, optname, (char *)optval, optlen); return ret; -*/ - return -ENOSYS; } - //helper functions -unsigned int inet_addr(char* ip) -{ +unsigned int inet_addr(char* ip) { int a, b, c, d; char addr[4]; @@ -467,29 +308,28 @@ unsigned int inet_addr(char* ip) return *(unsigned int *)addr; } -char *inet_ntoa(struct in_addr *in) -{ +char *inet_ntoa(struct in_addr *in) { char* str_ip = NULL; u_int32_t int_ip = 0; str_ip = kmalloc(16 * sizeof(char), GFP_KERNEL); - if (!str_ip) + if (!str_ip) { return NULL; - else + } + else { memset(str_ip, 0, 16); - + } int_ip = in->s_addr; sprintf(str_ip, "%d.%d.%d.%d", (int_ip ) & 0xFF, - (int_ip >> 8 ) & 0xFF, - (int_ip >> 16) & 0xFF, - (int_ip >> 24) & 0xFF); + (int_ip >> 8 ) & 0xFF, + (int_ip >> 16) & 0xFF, + (int_ip >> 24) & 0xFF); return str_ip; } //module init and cleanup procedure -static int ksocket_init(void) -{ +static int ksocket_init(void) { printk("%s version %s\n%s\n%s\n", KSOCKET_NAME, KSOCKET_VERSION, KSOCKET_DESCPT, KSOCKET_AUTHOR); @@ -497,8 +337,7 @@ static int ksocket_init(void) return 0; } -static void ksocket_exit(void) -{ +static void ksocket_exit(void) { printk("ksocket exit\n"); } diff --git a/src/ksocket.h b/src/ksocket.h index 42475f3..0528ea0 100644 --- a/src/ksocket.h +++ b/src/ksocket.h @@ -11,8 +11,11 @@ * @2017 * Hardik Bagdi (hbagdi1@binghamton.edu) * Changes for Compatibility with Linux 4.9 to use iov_iter + * + * @2025 + * Mephistolist (cloneozone@gmail.com) + * Changes for kernels 5.11 through at least 6.16. */ - #ifndef _ksocket_h_ #define _ksocket_h_