#include #include #include #include #include #include #include "comandi_mastruzzo.h" typedef struct command_packet payload_type; struct iovec iov_send; struct iovec iov_recv; struct channel { int sock_fd; struct sockaddr_nl src_addr; struct sockaddr_nl dest_addr; }; /* * Fill up a netlink address using the specified port. The case port == 0 * refers to the kernel side. */ void set_address(struct sockaddr_nl *address, int port) { memset(address, 0, sizeof(struct sockaddr_nl)); address->nl_family = AF_NETLINK; address->nl_pid = port; address->nl_groups = 0; /* unicast */ } struct channel *open_channel(int my_port) { struct channel *ch; ch = malloc(sizeof(struct channel)); if (ch == NULL) { return NULL; } ch->sock_fd=socket(PF_NETLINK, SOCK_RAW, NETLINK_USERSOCK); if(ch->sock_fd<0) { free(ch); return NULL; } set_address(&(ch->src_addr), my_port); set_address(&(ch->dest_addr), 0); bind (ch->sock_fd, (struct sockaddr*)&(ch->src_addr), sizeof(ch->src_addr)); connect (ch->sock_fd, (struct sockaddr*)&(ch->dest_addr), sizeof(ch->dest_addr)); return ch; } int buffer_size(int fd) { int n; unsigned int m = sizeof(n); int fdsocket; getsockopt(fd, SOL_SOCKET, SO_RCVBUF, (void *)&n, &m); return n; } struct nlmsghdr* new_nlmsghdr(int payload_len) { struct nlmsghdr *result; int total_size = NLMSG_SPACE(payload_len); result = (struct nlmsghdr *)malloc(total_size); memset(result, 0, total_size); result->nlmsg_len = total_size; return result; } /* * Create a netlink packet with the given payload, to be sent from * port src_port. */ struct nlmsghdr *create_packet(void *payload, int payload_len, int src_port) { struct nlmsghdr* packet = new_nlmsghdr(payload_len); printf("total=%d, payload_len=%d\n", packet->nlmsg_len, payload_len); packet->nlmsg_pid = src_port; packet->nlmsg_flags = 0; packet->nlmsg_type = NLMSG_DONE; memcpy(NLMSG_DATA(packet), payload, payload_len); printf("len=%d, port=%d\n", packet->nlmsg_len, packet->nlmsg_pid); return packet; } struct msghdr *new_msghdr(struct nlmsghdr *nl_header) { struct msghdr *message = malloc(sizeof(struct msghdr)); message->msg_iov = malloc(sizeof(struct iovec)); message->msg_iovlen = 1; if (nl_header == NULL) { message->msg_iov->iov_base = new_nlmsghdr(sizeof(payload_type)); } else { message->msg_iov->iov_base = nl_header; } message->msg_iov->iov_len = ((struct nlmsghdr*) message->msg_iov->iov_base)->nlmsg_len; return message; } /* * Create a message to be sent from src_addr to dest_addr containing * the given payload. The result will be stored in message. The * last parameter (iov) is there for convenience, since it is not * clear if we could use a local version, probably not, it would give * rise to a dangling pointer. */ struct msghdr *make_message (payload_type *payload, struct sockaddr_nl* src_addr, struct sockaddr_nl* dest_addr) { struct nlmsghdr *packet; const int payload_len = sizeof(payload_type); struct msghdr *message; packet = create_packet(payload, payload_len, src_addr->nl_pid); message = new_msghdr(packet); message->msg_name = (void *)dest_addr; message->msg_namelen = sizeof(*dest_addr); message->msg_control = NULL; message->msg_controllen = 0; message->msg_flags = 0; return message; } void dump(struct msghdr msg) { printf("namelen: %d\n", (int)msg.msg_namelen); } void extract_command (comando *cmd, int *parameter, struct nlmsghdr *header) { struct command_packet *packet = NLMSG_DATA(header); *cmd = packet->cmd; *parameter = packet->parameter; } int say_to_kernel (struct channel *ch, comando cmd, int parameter) { const int payload_len = sizeof(payload_type); struct command_packet payload = {.cmd = cmd, .parameter = parameter}; struct nlmsghdr *packet; packet = create_packet(&payload, payload_len, getpid()); return send(ch->sock_fd, packet, packet->nlmsg_len, 0); } int main() { struct channel *ch; int my_port = getpid(); struct nlmsghdr *packet = NULL; struct nlmsghdr *recv_buffer = new_nlmsghdr(sizeof(payload_type)); const int recv_buffer_len = recv_buffer->nlmsg_len; ssize_t err; ch = open_channel(my_port); if (ch == NULL) { perror("Error opening channel"); exit(1); } printf("Sending message to kernel..."); say_to_kernel (ch, HELO, 0); perror("done"); // (%d)\n", (int) err); printf("Waiting for message from kernel..."); /* Read message from kernel */ recv(ch->sock_fd, recv_buffer, recv_buffer_len, 0); { comando cmd; int parameter; extract_command (&cmd, ¶meter, recv_buffer); switch(cmd) { case QUERY: say_to_kernel(ch, REPLY, 2 * parameter); break; case HELO: case REPLY: case BYE: default: printf("??? cmd=%d\n", (int) cmd); break; } } say_to_kernel(ch, BYE, 0); return 0; }