diff --git a/bp_socket/af_bp.c b/bp_socket/af_bp.c index 69b93b0..49ea184 100644 --- a/bp_socket/af_bp.c +++ b/bp_socket/af_bp.c @@ -21,18 +21,19 @@ struct proto bp_proto = { static struct sock* bp_alloc_socket(struct net* net, int kern) { struct bp_sock* bp; - struct sock* sk = sk_alloc(net, AF_BP, GFP_KERNEL, &bp_proto, 1); - - if (!sk) - goto out; + struct sock* sk; - sock_init_data(NULL, sk); + sk = sk_alloc(net, AF_BP, GFP_KERNEL, &bp_proto, 1); + if (sk) { + sock_init_data(NULL, sk); - bp = bp_sk(sk); - skb_queue_head_init(&bp->queue); - init_waitqueue_head(&bp->wait_queue); + bp = bp_sk(sk); + skb_queue_head_init(&bp->queue); + init_waitqueue_head(&bp->wait_queue); + bp->bp_node_id = 0; + bp->bp_service_id = 0; + } -out: return sk; } @@ -65,14 +66,17 @@ int bp_create(struct net* net, struct socket* sock, int protocol, int kern) { struct sock* sk; struct bp_sock* bp; - int rc = -EAFNOSUPPORT; + int ret; - if (!net_eq(net, &init_net)) + if (!net_eq(net, &init_net)) { + ret = -EOPNOTSUPP; goto out; + } - rc = -ENOMEM; - if ((sk = bp_alloc_socket(net, kern)) == NULL) + if ((sk = bp_alloc_socket(net, kern)) == NULL) { + ret = -ENOMEM; goto out; + } bp = bp_sk(sk); sock_init_data(sock, sk); @@ -80,50 +84,57 @@ int bp_create(struct net* net, struct socket* sock, int protocol, int kern) sock->ops = &bp_proto_ops; sk->sk_protocol = protocol; - rc = 0; + return 0; + out: - return rc; + return ret; } int bp_bind(struct socket* sock, struct sockaddr* uaddr, int addr_len) { - struct sock *iter_sk, *sk = sock->sk; + struct sock *iter_sk, *sk; struct bp_sock *iter_bp, *bp; - struct sockaddr_bp* addr = (struct sockaddr_bp*)uaddr; - int service_id = -1; - int node_id = -1; - - if (addr_len != sizeof(struct sockaddr_bp)) - return -EINVAL; - - if (addr->bp_family != AF_BP) - return -EINVAL; - - switch (addr->bp_scheme) { - case BP_SCHEME_IPN: - service_id = addr->bp_addr.ipn.service_id; - node_id = addr->bp_addr.ipn.node_id; - - if (service_id < 1 || service_id > 255) { - pr_err("bp_bind: invalid service ID %d (must be in " - "[1,255])\n", - service_id); - return -EINVAL; - } + struct sockaddr_bp* addr; + u_int32_t service_id; + u_int32_t node_id; + int ret; - if (node_id < 1) { - pr_err("bp_bind: invalid node ID (must be > 0)\n"); - return -EINVAL; - } + sk = sock->sk; + addr = (struct sockaddr_bp*)uaddr; + service_id = addr->bp_addr.ipn.service_id; + node_id = addr->bp_addr.ipn.node_id; - break; + if (addr_len != sizeof(struct sockaddr_bp)) { + ret = -EINVAL; + goto out; + } - case BP_SCHEME_DTN: - pr_err("bp_bind: DTN scheme not supported\n"); - return -EAFNOSUPPORT; - default: - pr_err("bp_bind: unknown scheme %d\n", addr->bp_scheme); - return -EINVAL; + if (addr->bp_family != AF_BP) { + ret = -EINVAL; + goto out; + } + + if (addr->bp_scheme != BP_SCHEME_IPN) { + pr_err("bp_bind: unsupported address scheme %d\n", + addr->bp_scheme); + ret = -EAFNOSUPPORT; + goto out; + } + + // https://www.rfc-editor.org/rfc/rfc9758.html#name-node-numbers + if (node_id > 0xFFFFFFFF) { + pr_err("bp_bind: invalid node ID (must be in [0;2^31])\n"); + ret = -EINVAL; + goto out; + } + + // https://www.rfc-editor.org/rfc/rfc9758.html#name-service-numbers + if (service_id < 1 || service_id > 0xFFFFFFFF) { + pr_err("bp_bind: invalid service ID %d (must be in " + "[1;2^31])\n", + service_id); + ret = -EINVAL; + goto out; } read_lock_bh(&bp_list_lock); @@ -133,7 +144,8 @@ int bp_bind(struct socket* sock, struct sockaddr* uaddr, int addr_len) if (iter_bp->bp_service_id == service_id && iter_bp->bp_node_id == node_id) { read_unlock_bh(&bp_list_lock); - return -EADDRINUSE; + ret = -EADDRINUSE; + goto out; } } read_unlock_bh(&bp_list_lock); @@ -145,9 +157,12 @@ int bp_bind(struct socket* sock, struct sockaddr* uaddr, int addr_len) write_lock_bh(&bp_list_lock); sk_add_node(sk, &bp_list); write_unlock_bh(&bp_list_lock); - release_sock(sk); + return 0; + +out: + return ret; } int bp_release(struct socket* sock) @@ -155,21 +170,20 @@ int bp_release(struct socket* sock) struct sock* sk = sock->sk; struct bp_sock* bp; - if (!sk) - return 0; - - lock_sock(sk); - sock_orphan(sk); - bp = bp_sk(sk); + if (sk) { + lock_sock(sk); + sock_orphan(sk); + bp = bp_sk(sk); - write_lock_bh(&bp_list_lock); - sk_del_node_init(sk); - write_unlock_bh(&bp_list_lock); - skb_queue_purge(&bp->queue); + write_lock_bh(&bp_list_lock); + sk_del_node_init(sk); + write_unlock_bh(&bp_list_lock); + skb_queue_purge(&bp->queue); - sock->sk = NULL; - release_sock(sk); - sock_put(sk); + sock->sk = NULL; + release_sock(sk); + sock_put(sk); + } return 0; } @@ -178,21 +192,22 @@ int bp_sendmsg(struct socket* sock, struct msghdr* msg, size_t size) { struct sockaddr_bp* addr; void* payload; - uintptr_t sockid; - int service_id = -1; - int node_id = -1; + u_int32_t service_id; + u_int32_t node_id; int ret; if (!msg->msg_name) { - pr_err("bp_sendmsg: no destination address provided"); - return -EINVAL; + pr_err("bp_sendmsg: no destination address provided\n"); + ret = -EINVAL; + goto out; } if (msg->msg_namelen < sizeof(struct sockaddr_bp)) { pr_err("bp_sendmsg: address length too short (expected: %zu, " "provided: %u)\n", sizeof(struct sockaddr_bp), msg->msg_namelen); - return -EINVAL; + ret = -EINVAL; + goto out; } addr = (struct sockaddr_bp*)msg->msg_name; @@ -200,102 +215,110 @@ int bp_sendmsg(struct socket* sock, struct msghdr* msg, size_t size) if (addr->bp_family != AF_BP) { pr_err("bp_sendmsg: unsupported address family %d\n", addr->bp_family); - return -EAFNOSUPPORT; + ret = -EAFNOSUPPORT; + goto out; } - switch (addr->bp_scheme) { - case BP_SCHEME_IPN: - service_id = addr->bp_addr.ipn.service_id; - node_id = addr->bp_addr.ipn.node_id; - - if (service_id < 1 || service_id > 255) { - pr_err("bp_sendmsg: invalid service ID %d (must be in " - "[1,255])\n", - service_id); - return -EINVAL; - } - if (node_id < 1) { - pr_err("bp_sendmsg: invalid node ID (must be > 0)"); - return -EINVAL; - } - break; + if (addr->bp_scheme != BP_SCHEME_IPN) { + pr_err("bp_sendmsg: unsupported address scheme %d\n", + addr->bp_scheme); + ret = -EAFNOSUPPORT; + goto out; + } - case BP_SCHEME_DTN: - pr_err("bp_sendmsg: DTN scheme not supported"); - return -EAFNOSUPPORT; + service_id = addr->bp_addr.ipn.service_id; + node_id = addr->bp_addr.ipn.node_id; - default: - pr_err("bp_sendmsg: unknown scheme %d", addr->bp_scheme); - return -EINVAL; + // https://www.rfc-editor.org/rfc/rfc9758.html#name-node-numbers + if (node_id > 0xFFFFFFFF) { + pr_err("bp_bind: invalid node ID (must be in [0;2^31])\n"); + ret = -EINVAL; + goto out; } - if (size == 0) { - return 0; + // https://www.rfc-editor.org/rfc/rfc9758.html#name-service-numbers + if (service_id < 1 || service_id > 0xFFFFFFFF) { + pr_err("bp_bind: invalid service ID %d (must be in " + "[1;2^31])\n", + service_id); + ret = -EINVAL; + goto out; } if (size > BP_MAX_PAYLOAD) { - pr_err("bp_sendmsg: payload too big (%zu bytes)", size); - return -EMSGSIZE; - } - - payload = kmalloc(size, GFP_KERNEL); - if (!payload) { - pr_err("bp_sendmsg: failed to allocate memory"); - return -ENOMEM; + pr_err("bp_sendmsg: payload too big (%zu bytes)\n", size); + ret = -EMSGSIZE; + goto out; } - if (copy_from_iter(payload, size, &msg->msg_iter) != size) { - pr_err("bp_sendmsg: failed to copy data from user"); - kfree(payload); - return -EFAULT; - } + if (size > 0) { + payload = kmalloc(size, GFP_KERNEL); + if (!payload) { + pr_err("bp_sendmsg: failed to allocate memory\n"); + ret = -ENOMEM; + goto out; + } - sockid = (uintptr_t)sock->sk->sk_socket; + if (copy_from_iter(payload, size, &msg->msg_iter) != size) { + pr_err("bp_sendmsg: failed to copy data from user\n"); + ret = -EFAULT; + goto err_free; + } - ret = send_bundle_doit( - sockid, (char*)payload, size, node_id, service_id, 8443); - kfree(payload); + ret = send_bundle_doit((uintptr_t)sock->sk->sk_socket, payload, + size, node_id, service_id, 8443); + if (ret < 0) { + pr_err( + "bp_sendmsg: send_bundle_doit failed (%d)\n", ret); + goto err_free; + } - if (ret < 0) { - pr_err("bp_sendmsg: send_bundle_doit failed (%d)", ret); - return ret; + kfree(payload); } return size; + +err_free: + kfree(payload); +out: + return ret; } int bp_recvmsg(struct socket* sock, struct msghdr* msg, size_t size, int flags) { - struct sock* sk = sock->sk; + struct sock* sk; struct bp_sock* bp; struct sk_buff* skb; - u32 service_id; int ret; + sk = sock->sk; lock_sock(sk); bp = bp_sk(sk); - service_id = bp->bp_service_id; - request_bundle_doit(bp->bp_service_id, 8443); + ret = request_bundle_doit(bp->bp_node_id, bp->bp_service_id, 8443); + if (ret < 0) { + pr_err("bp_recvmsg: request_bundle_doit failed (%d)\n", ret); + goto out; + } ret = wait_event_interruptible( bp->wait_queue, !skb_queue_empty(&bp->queue)); if (ret < 0) { pr_err("bp_recvmsg: interrupted while waiting\n"); - goto out_unlock; + goto out; } if (sock_flag(sk, SOCK_DEAD)) { pr_err("bp_recvmsg: socket closed while waiting\n"); - ret = -ECONNRESET; - goto out_unlock; + ret = -ESHUTDOWN; + goto out; } skb = skb_dequeue(&bp->queue); if (!skb) { pr_info("bp_recvmsg: no messages in the queue for service %d\n", - service_id); - ret = -EAGAIN; - goto out_unlock; + bp->bp_service_id); + ret = -ENOMSG; + goto out; } if (skb->len > size) { @@ -303,21 +326,20 @@ int bp_recvmsg(struct socket* sock, struct msghdr* msg, size_t size, int flags) "provided=%zu)\n", skb->len, size); ret = -EMSGSIZE; - goto out_free_skb; + goto out; } if (copy_to_iter(skb->data, skb->len, &msg->msg_iter) != skb->len) { pr_err("bp_recvmsg: failed to copy data to user space\n"); ret = -EFAULT; - goto out_free_skb; + goto out; } ret = skb->len; -out_free_skb: - kfree_skb(skb); -out_unlock: +out: + if (skb) + kfree_skb(skb); release_sock(sk); - return ret; } diff --git a/bp_socket/bp_genl.c b/bp_socket/bp_genl.c index 9402561..be97f6c 100644 --- a/bp_socket/bp_genl.c +++ b/bp_socket/bp_genl.c @@ -36,117 +36,103 @@ struct genl_family genl_fam = { .n_mcgrps = ARRAY_SIZE(genl_mcgrps), }; -int fail_doit(struct sk_buff* skb, struct genl_info* info) +int send_bundle_doit(u64 sockid, void* payload, int payload_size, + u_int32_t node_id, u_int32_t service_id, int port_id) { - pr_alert("Kernel receieved an SSA netlink notification. This should " - "never happen.\n"); - return -1; -} - -int send_bundle_doit(u64 sockid, const char* payload, int payload_size, - u32 node_id, u32 service_id, int port_id) -{ - int ret = 0; - void* hdr; + void* msg_head; struct sk_buff* msg; - int msg_size; + size_t msg_size; + int ret; - /* Compute total size of Netlink attributes */ - msg_size = nla_total_size(sizeof(u64)) + nla_total_size(sizeof(u32)) - + nla_total_size(sizeof(u32)) + nla_total_size(payload_size); - - /* Allocate a new buffer */ - msg = genlmsg_new(msg_size + GENL_HDRLEN, GFP_KERNEL); + msg_size = nla_total_size(sizeof(u64)) + + nla_total_size(sizeof(u_int32_t)) + + nla_total_size(sizeof(u_int32_t)) + nla_total_size(payload_size); + msg = genlmsg_new(msg_size, GFP_KERNEL); if (!msg) { pr_err("send_bundle: failed to allocate message buffer\n"); - return -ENOMEM; + ret = -ENOMEM; + goto out; } - /* Generic Netlink header */ - hdr = genlmsg_put(msg, 0, 0, &genl_fam, 0, BP_GENL_CMD_SEND_BUNDLE); - if (!hdr) { + msg_head + = genlmsg_put(msg, 0, 0, &genl_fam, 0, BP_GENL_CMD_SEND_BUNDLE); + if (!msg_head) { pr_err("send_bundle: failed to create genetlink header\n"); - nlmsg_free(msg); - return -EMSGSIZE; + ret = -EMSGSIZE; + goto err_free; } - /* And the message */ ret = nla_put_u64_64bit(msg, BP_GENL_A_SOCKID, sockid, 0); if (ret) { pr_err("send_bundle: failed to put SOCKID (%d)\n", ret); - goto fail; + goto err_cancel; } ret = nla_put_u32(msg, BP_GENL_A_NODE_ID, node_id); if (ret) { pr_err("send_bundle: failed to put NODE_ID (%d)\n", ret); - goto fail; + goto err_cancel; } ret = nla_put_u32(msg, BP_GENL_A_SERVICE_ID, service_id); if (ret) { pr_err("send_bundle: failed to put SERVICE_ID (%d)\n", ret); - goto fail; + goto err_cancel; } ret = nla_put(msg, BP_GENL_A_PAYLOAD, payload_size, payload); if (ret) { pr_err("send_bundle: failed to put PAYLOAD (%d)\n", ret); - goto fail; + goto err_cancel; } - genlmsg_end(msg, hdr); - ret = genlmsg_unicast(&init_net, msg, port_id); - if (ret != 0) { - pr_err("send_bundle: genlmsg_unicast failed (%d)\n", ret); - } - return ret; + genlmsg_end(msg, msg_head); + return genlmsg_unicast(&init_net, msg, port_id); -fail: - genlmsg_cancel(msg, hdr); +err_cancel: + genlmsg_cancel(msg, msg_head); +err_free: nlmsg_free(msg); +out: return ret; } -int request_bundle_doit(u32 service_id, int port_id) +int request_bundle_doit(u_int32_t node_id, u_int32_t service_id, int port_id) { - int ret = 0; - void* hdr; + void* msg_head; struct sk_buff* msg; - int msg_size; + size_t msg_size; + int ret; - /* Allocate a new buffer for the reply */ msg_size = nla_total_size(sizeof(u32)); - msg = genlmsg_new(msg_size + GENL_HDRLEN, GFP_KERNEL); + msg = genlmsg_new(msg_size, GFP_KERNEL); if (!msg) { - pr_err("failed to allocate message buffer\n"); - return -ENOMEM; + pr_err("request_bundle: failed to allocate message buffer\n"); + ret = -ENOMEM; + goto out; } - /* Put the Generic Netlink header */ - hdr = genlmsg_put(msg, 0, 0, &genl_fam, 0, BP_GENL_CMD_REQUEST_BUNDLE); - if (!hdr) { - pr_err("failed to create genetlink header\n"); - nlmsg_free(msg); - return -EMSGSIZE; + msg_head + = genlmsg_put(msg, 0, 0, &genl_fam, 0, BP_GENL_CMD_REQUEST_BUNDLE); + if (!msg_head) { + pr_err("request_bundle: failed to create genetlink header\n"); + ret = -EMSGSIZE; + goto err_free; } - /* And the message */ - if ((ret = nla_put_u32(msg, BP_GENL_A_SERVICE_ID, service_id))) { - pr_err("failed to create message string\n"); - genlmsg_cancel(msg, hdr); - nlmsg_free(msg); - goto out; + ret = nla_put_u32(msg, BP_GENL_A_SERVICE_ID, service_id); + if (ret) { + pr_err("request_bundle: failed to put SERVICE_ID (%d)\n", ret); + goto err_cancel; } - /* Finalize the message and send it */ - genlmsg_end(msg, hdr); - ret = genlmsg_unicast(&init_net, msg, port_id); - if (ret != 0) { - pr_alert("Failed in gemlmsg_unicast [setsockopt notify]\n (%d)", - ret); - } + genlmsg_end(msg, msg_head); + return genlmsg_unicast(&init_net, msg, port_id); +err_cancel: + genlmsg_cancel(msg, msg_head); +err_free: + nlmsg_free(msg); out: return ret; } @@ -155,15 +141,18 @@ int deliver_bundle_doit(struct sk_buff* skb, struct genl_info* info) { struct sock* sk; struct bp_sock* bp; - u32 service_id; - char* payload; - size_t payload_len; struct sk_buff* new_skb; + bool new_skb_queued = false; + u_int32_t service_id; + void* payload; + size_t payload_len; + int ret; if (!info->attrs[BP_GENL_A_SERVICE_ID] || !info->attrs[BP_GENL_A_PAYLOAD]) { pr_err("deliver_bundle: missing required attributes\n"); - return -EINVAL; + ret = -EINVAL; + goto out; } service_id = nla_get_u32(info->attrs[BP_GENL_A_SERVICE_ID]); payload = nla_data(info->attrs[BP_GENL_A_PAYLOAD]); @@ -172,7 +161,8 @@ int deliver_bundle_doit(struct sk_buff* skb, struct genl_info* info) new_skb = alloc_skb(payload_len, GFP_KERNEL); if (!new_skb) { pr_err("Failed to allocate sk_buff for payload\n"); - return -ENOMEM; + ret = -ENOMEM; + goto out; } skb_put_data(new_skb, payload, payload_len); @@ -185,6 +175,7 @@ int deliver_bundle_doit(struct sk_buff* skb, struct genl_info* info) if (bp->bp_service_id == service_id) { skb_queue_tail(&bp->queue, new_skb); + new_skb_queued = true; if (waitqueue_active(&bp->wait_queue)) wake_up_interruptible(&bp->wait_queue); bh_unlock_sock(sk); @@ -194,5 +185,17 @@ int deliver_bundle_doit(struct sk_buff* skb, struct genl_info* info) } read_unlock_bh(&bp_list_lock); + if (!new_skb_queued) { + pr_err("deliver_bundle: no socket found for service ID %d\n", + service_id); + ret = -ENODEV; + goto err_free; + } + return 0; + +err_free: + kfree_skb(new_skb); +out: + return ret; } diff --git a/bp_socket/bp_genl.h b/bp_socket/bp_genl.h index 8d9f9c0..157bf44 100644 --- a/bp_socket/bp_genl.h +++ b/bp_socket/bp_genl.h @@ -6,9 +6,9 @@ extern struct genl_family genl_fam; int fail_doit(struct sk_buff* skb, struct genl_info* info); -int send_bundle_doit(u64 sockid, const char* payload, int payload_size, - u32 node_id, u32 service_id, int port_id); +int send_bundle_doit(u64 sockid, void* payload, int payload_size, + u_int32_t node_id, u_int32_t service_id, int port_id); int deliver_bundle_doit(struct sk_buff* skb, struct genl_info* info); -int request_bundle_doit(u32 service_id, int port_id); +int request_bundle_doit(u_int32_t node_id, u_int32_t service_id, int port_id); #endif \ No newline at end of file diff --git a/bp_socket/bp_module.c b/bp_socket/bp_module.c index 4ade19a..e7c518c 100644 --- a/bp_socket/bp_module.c +++ b/bp_socket/bp_module.c @@ -15,48 +15,45 @@ static int __init bp_init(void) { int ret; - int rc; - - pr_info("bp_init: initializing module\n"); /* generic netlink */ ret = genl_register_family(&genl_fam); if (unlikely(ret)) { - pr_crit("bp_init: failed to register generic netlink family\n"); - return ret; + pr_err("bp_init: failed to register generic netlink family\n"); + goto out; } /* protocol */ - rc = proto_register(&bp_proto, 0); - if (rc) { + ret = proto_register(&bp_proto, 0); + if (ret) { pr_err("bp_init: failed to register proto\n"); - return rc; + goto out; } - rc = sock_register(&bp_family_ops); - if (rc) { + ret = sock_register(&bp_family_ops); + if (ret) { pr_err("bp_init: failed to register socket family\n"); - proto_unregister(&bp_proto); - return rc; + goto err_unreg_proto; } - pr_info("bp_init: module initialized successfully\n"); return 0; + +err_unreg_proto: + proto_unregister(&bp_proto); +out: + pr_err("bp_init: module initialization failed\n"); + return ret; } static void __exit bp_exit(void) { - pr_info("bp_exit: unloading module\n"); sock_unregister(AF_BP); proto_unregister(&bp_proto); if (unlikely(genl_unregister_family(&genl_fam))) { pr_err( "bp_init: failed to unregister generic netlink family\n"); - return; } - - pr_info("bp_exit: module unloaded successfully\n"); } module_init(bp_init); @@ -64,5 +61,5 @@ module_exit(bp_exit); // Module metadata MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Your Name"); -MODULE_DESCRIPTION("Custom socket protocol module"); \ No newline at end of file +MODULE_AUTHOR("Sylvain Pierrot"); +MODULE_DESCRIPTION("A socket family for the Bundle Protocol (BP)"); \ No newline at end of file diff --git a/receiver.c b/receiver.c index 3f017f0..3a6ed42 100644 --- a/receiver.c +++ b/receiver.c @@ -1,4 +1,4 @@ -#include "../include/bp_socket.h" +#include "include/bp_socket.h" #include #include #include diff --git a/sender.c b/sender.c index 3c358dc..87c250a 100644 --- a/sender.c +++ b/sender.c @@ -1,4 +1,4 @@ -#include "../include/bp_socket.h" +#include "include/bp_socket.h" #include #include #include