Comment utiliser netlink socket pour communiquer avec un module du noyau?
Je suis en train d'écrire un module du noyau linux qui communique avec l'utilisateur processus à l'aide de netlink. Je suis, en utilisant netlink parce que le programme de l'utilisateur j'ai envie de communiquer pour communiquer uniquement à l'aide de sockets et je ne peux pas changer cela d'ajouter ioctl()
ou quoi que ce soit.
Problème est que je ne peux pas comprendre comment le faire. J'ai googlé mais tous les exemples que j'ai trouvé sont pour les vieux comme cette une et n'est plus valable pour les actuelles versions du noyau. J'ai aussi regardé cette SORTE de question mais l'exemple ici utilise libnl pour les opérations de socket mais je veux m'en tenir à douille standard de fonctions (définies par sys/socket.h
). Si certains ont un plz me guide ici pour un tutoriel ou guide ou quelque chose qui peut m'aider à comprendre l'interface et l'utilisation de netlink. Je serais très apprécier un exemple de travail, rien de compliqué, juste un exemple de base de la façon d'établir une connexion à partir d'une prise dans le programme utilisateur à un socket dans le noyau et puis envoyer les données de l'utilisateur processus d'amande et de recevoir en retour de noyau.
Aussi s'il vous plaît ne me dites pas de regarder le code du noyau. Je fais déjà, mais il faudra beaucoup de temps et je n'ai pas beaucoup de la gauche.
Mise à jour:
Après beaucoup d'essais et d'erreur que j'ai suivantes code qui envoie un message à partir du programme utilisateur à noyau, mais le message à partir du noyau de l'utilisateur, programme, que je.e à l'aide de netlink_unicast()
ne fonctionne pas. Ce n'est pas seulement ne fonctionne pas, l'appel se bloque les systèmes et puis j'ai redémarrer la machine. Certains plz un prendre un coup d'oeil et me dire ce que de mal, je suis en train de faire. Le netlink_unicast()
appel est commenté dans le code suivant. Il doit être retirée pour le noyau de programme utilisateur message.
Programme Utilisateur
#include <sys/socket.h>
#include <linux/netlink.h>
#define NETLINK_USER 31
#define MAX_PAYLOAD 1024 /* maximum payload size*/
struct sockaddr_nl src_addr, dest_addr;
struct nlmsghdr *nlh = NULL;
struct iovec iov;
int sock_fd;
struct msghdr msg;
void main()
{
sock_fd=socket(PF_NETLINK, SOCK_RAW, NETLINK_USER);
if(sock_fd<0)
return -1;
memset(&src_addr, 0, sizeof(src_addr));
src_addr.nl_family = AF_NETLINK;
src_addr.nl_pid = getpid(); /* self pid */
/* interested in group 1<<0 */
bind(sock_fd, (struct sockaddr*)&src_addr,
sizeof(src_addr));
memset(&dest_addr, 0, sizeof(dest_addr));
memset(&dest_addr, 0, sizeof(dest_addr));
dest_addr.nl_family = AF_NETLINK;
dest_addr.nl_pid = 0; /* For Linux Kernel */
dest_addr.nl_groups = 0; /* unicast */
nlh = (struct nlmsghdr *)malloc(
NLMSG_SPACE(MAX_PAYLOAD));
memset(nlh, 0, NLMSG_SPACE(MAX_PAYLOAD));
nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
nlh->nlmsg_pid = getpid();
nlh->nlmsg_flags = 0;
strcpy(NLMSG_DATA(nlh), "Hello");
iov.iov_base = (void *)nlh;
iov.iov_len = nlh->nlmsg_len;
msg.msg_name = (void *)&dest_addr;
msg.msg_namelen = sizeof(dest_addr);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
printf("Sending message to kernel\n");
sendmsg(sock_fd,&msg,0);
printf("Waiting for message from kernel\n");
/* Read message from kernel */
recvmsg(sock_fd, &msg, 0);
printf(" Received message payload: %s\n",
NLMSG_DATA(nlh));
close(sock_fd);
}
Code Du Noyau
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <net/sock.h>
#include <linux/socket.h>
#include <linux/net.h>
#include <asm/types.h>
#include <linux/netlink.h>
#include <linux/skbuff.h>
#define NETLINK_USER 31
struct sock *nl_sk = NULL;
static void hello_nl_recv_msg(struct sk_buff *skb)
{
struct nlmsghdr *nlh;
int pid;
printk(KERN_INFO "Entering: %s\n", __FUNCTION__);
nlh=(struct nlmsghdr*)skb->data;
printk(KERN_INFO "Netlink received msg payload: %s\n",
(char*)NLMSG_DATA(nlh));
pid = nlh->nlmsg_pid; /*pid of sending process */
NETLINK_CB(skb).dst_group = 0; /* not in mcast group */
NETLINK_CB(skb).pid = 0; /* from kernel */
//NETLINK_CB(skb).groups = 0; /* not in mcast group */
//NETLINK_CB(skb).dst_pid = pid;
printk("About to send msg bak:\n");
//netlink_unicast(nl_sk,skb,pid,MSG_DONTWAIT);
}
static int __init hello_init(void)
{
printk("Entering: %s\n",__FUNCTION__);
nl_sk=netlink_kernel_create(&init_net, NETLINK_USER, 0,
hello_nl_recv_msg, NULL, THIS_MODULE);
if(!nl_sk)
{
printk(KERN_ALERT "Error creating socket.\n");
return -10;
}
return 0;
}
static void __exit hello_exit(void)
{
printk(KERN_INFO "exiting hello module\n");
netlink_kernel_release(nl_sk);
}
module_init(hello_init);
module_exit(hello_exit);
- Comment pourrait-10 personnes marque ce en tant que favori, mais seulement de 5 personnes upvote il?
- Je sais que c'est un peu en retard, mais ce livre (ch 2) aborde également les sockets netlink: amazon.com/Linux-Kernel-Networking-Implementation-Experts/dp/...
- ce programme utilisateur fonctionne en tant que
struct msghdr msg;
est défini dans la portée globale. Mais dès que j'ai déplacer qu'à l'intérieur d'une fonction (comme principale), le programme utilisateur ne fonctionne plus etsendmsg
renvoie -1 et errno est positionnée à l'erreur 105 (ENOBUFS - pas de tampon de l'espace disponible). Quelqu'un peut-il expliquer pourquoimsghdr
ne fonctionne que lorsqu'il est défini à l'échelle mondiale dans ce programme?
Vous devez vous connecter pour publier un commentaire.
Après la lecture de la source du noyau, j'ai enfin réussi à faire des sockets netlink de travail pour moi. Ci-dessous est un exemple de Netlink socket trucs de base.e l'ouverture d'un netlink socket, de la lecture et de l'écriture et de fermeture.
Module De Noyau
Programme Utilisateur
Sujet à propos de la magie de la constante
NETLINK_USER 31
: Puis-je avoir plus de 32 sockets netlink dans kernelspace?Juste au cas où quelqu'un ne sait pas comment compiler, google "comment compiler et charger le module du noyau"
reportez-vous à http://www.cyberciti.biz/tips/compiling-linux-kernel-module.html
Saisir le code source du noyau vers lequel vous allez compiler le module contre http://kernel.org
Ou simplement mettre à jour votre les en-têtes si vous êtes en cours d'exécution prévu noyau
Créer un fichier makefile, par exemple
Faire et vous obtiendrez un tas de fichiers. *.ko est celui que vous chargez dans votre noyau, exécutez
si vous nous lsmod pour vérifier tous les modules chargés, vous trouverez le vôtre, plus vous aurez de chances de voir:
Dans notre cas, de compiler et d'exécuter le code de l'utilisateur:
Si tout est OK, vous obtiendrez le message suivant à l'aide de binW code:
Enfin, retirez le module à l'aide de:
Il fonctionne pour moi avec le noyau 3.2. Pour le noyau 3.6 & ci-dessus, il faut un peu de changement à la
netlink_kernel_create
fonction.vous avez besoin d'inclure les suivantes fichier d'en-tête dans client_side code: