guile-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] socket: Add AF_NETLINK support.


From: David Thompson
Subject: [PATCH] socket: Add AF_NETLINK support.
Date: Sun, 03 May 2015 10:12:49 -0400
User-agent: Notmuch/0.18.2 (http://notmuchmail.org) Emacs/24.4.1 (x86_64-pc-linux-gnu)

Hello Guile hackers,

This is my first attempt at providing support for AF_NETLINK sockets in
Guile, based on a preliminary patch that Ludovic sent me.  Netlink
sockets are supported only on Linux.  The ultimate goal of this work is
to be able to create virtual ethernet devices from Scheme code.

There are no tests yet and I'm not sure if I went overboard by defining
all of the numerous netlink families and multicast group constants.
Feedback requested! :)

This patch is for stable-2.0.

Thanks,

>From 3fed7633ee4556907408c55ae29c12641ad6d80c Mon Sep 17 00:00:00 2001
From: David Thompson <address@hidden>
Date: Sun, 3 May 2015 09:35:49 -0400
Subject: [PATCH] socket: Add AF_NETLINK support.

* libguile/socket.c (scm_fill_sockaddr, _scm_from_sockaddr,
  scm_to_sockaddr): Add AF_NETLINK cases.
  (AF_NETLINK, PF_NETLINK, NETLINK_ROUTE, NETLINK_USERSOCK,
  NETLINK_FIREWALL, NETLINK_SOCK_DIAG, NETLINK_NFLOG, NETLINK_XFRM,
  NETLINK_SELINUX, NETLINK_ISCSI, NETLINK_AUDIT, NETLINK_FIB_LOOKUP,
  NETLINK_CONNECTOR, NETLINK_NETFILTER, NETLINK_IP6_FW, NETLINK_DNRTMSG,
  NETLINK_UEVENT, NETLINK_GENERIC, NETLINK_SCSITRANSPORT,
  NETLINK_ECRYPTFS, NETLINK_RDMA, NETLINK_CRYPTO, RTNLGRP_NONE,
  RTNGRP_LINK, RTNGRP_NOTIFY, RTNGRP_NEIGH, RTNGRP_TC,
  RTNGRP_IPV4_IFADDR, RTNGRP_IPV4_MROUTE, RTNGRP_IPV4_ROUTE,
  RTNGRP_IPV4_RULE, RTNGRP_IPV6_IFADDR, RTNGRP_IPV6_MROUTE,
  RTNGRP_IPV6_ROUTE, RTNGRP_IPV6_IFINFO, RTNGRP_DECnet_IFADDR,
  RTNGRP_DECnet_ROUTE, RTNGRP_DECnet_RULE, RTNGRP_IPV6_PREFIX,
  RTNGRP_IPV6_RULE, RTNGRP_ND_USEROPT, RTNGRP_PHONET_IFADDR,
  RTNGRP_PHONET_ROUTE, RTNGRP_DCB, RTNGRP_IPV4_NETCONF,
  RTNGRP_IPV6_NETCONF, RTNGRP_MDB): New Scheme variables.
* module/ice-9/networking.scm (sockaddr:pid, sockaddr:groups): New
  procedures.
* doc/ref/posix.texi (make-socket-address, connect, bind): Document
  AF_NETLINK usage.
  (sockaddr:pid, sockaddr:groups): Document new procedures.
  (socket): Document PF_NETLINK family constant.
---
 doc/ref/posix.texi          |  17 ++++
 libguile/socket.c           | 203 ++++++++++++++++++++++++++++++++++++++++++++
 module/ice-9/networking.scm |   2 +
 3 files changed, 222 insertions(+)

diff --git a/doc/ref/posix.texi b/doc/ref/posix.texi
index ad5460c..33fe185 100644
--- a/doc/ref/posix.texi
+++ b/doc/ref/posix.texi
@@ -2950,6 +2950,7 @@ created with,
 @deffn {Scheme Procedure} make-socket-address AF_INET ipv4addr port
 @deffnx {Scheme Procedure} make-socket-address AF_INET6 ipv6addr port 
[flowinfo [scopeid]]
 @deffnx {Scheme Procedure} make-socket-address AF_UNIX path
address@hidden {Scheme Procedure} make-socket-address AF_NETLINK pid groups
 @deffnx {C Function} scm_make_socket_address (family, address, arglist)
 Return a new socket address object.  The first argument is the address
 family, one of the @code{AF} constants, then the arguments vary
@@ -2964,6 +2965,9 @@ arguments may be given (both integers, default 0).
 
 For @code{AF_UNIX} the argument is a filename (a string).
 
+For @code{AF_NETLINK}, the arguments are a process ID and a multicast
+groups bitmask.  This socket type is only available on Linux.
+
 The C function @code{scm_make_socket_address} takes the @var{family}
 and @var{address} arguments directly, then @var{arglist} is a list of
 further arguments, being the port for IPv4, port and optional flowinfo
@@ -3004,6 +3008,16 @@ For an @code{AF_INET6} socket address object @var{sa}, 
return the
 scope ID value.
 @end deffn
 
address@hidden {Scheme Procedure} sockaddr:pid sa
+For an @code{AF_NETLINK} socket address object @var{sa}, return the
+process ID number.
address@hidden deffn
+
address@hidden {Scheme Procedure} sockaddr:groups sa
+For an @code{AF_NETLINK} socket address object @var{sa}, return the
+multicast groups bitmask.
address@hidden deffn
+
 @tpindex @code{struct sockaddr}
 @tpindex @code{sockaddr}
 The functions below convert to and from the C @code{struct sockaddr}
@@ -3075,6 +3089,7 @@ the system,
 @defvar PF_UNIX
 @defvarx PF_INET
 @defvarx PF_INET6
address@hidden PF_NETLINK
 @end defvar
 
 The possible values for @var{style} are as follows, again where
@@ -3213,6 +3228,7 @@ The return value is unspecified.
 @deffnx {Scheme Procedure} connect sock AF_INET ipv4addr port
 @deffnx {Scheme Procedure} connect sock AF_INET6 ipv6addr port [flowinfo 
[scopeid]]
 @deffnx {Scheme Procedure} connect sock AF_UNIX path
address@hidden {Scheme Procedure} connect sock AF_NETLINK pid groups
 @deffnx {C Function} scm_connect (sock, fam, address, args)
 Initiate a connection on socket port @var{sock} to a given address.
 The destination is either a socket address object, or arguments the
@@ -3229,6 +3245,7 @@ same as @code{make-socket-address} would take to make 
such an object
 @deffnx {Scheme Procedure} bind sock AF_INET ipv4addr port
 @deffnx {Scheme Procedure} bind sock AF_INET6 ipv6addr port [flowinfo 
[scopeid]]
 @deffnx {Scheme Procedure} bind sock AF_UNIX path
address@hidden {Scheme Procedure} bind sock AF_NETLINK pid groups
 @deffnx {C Function} scm_bind (sock, fam, address, args)
 Bind socket port @var{sock} to the given address.  The address is
 either a socket address object, or arguments the same as
diff --git a/libguile/socket.c b/libguile/socket.c
index 5b17a74..3501646 100644
--- a/libguile/socket.c
+++ b/libguile/socket.c
@@ -43,6 +43,11 @@
 #include <netdb.h>
 #include <arpa/inet.h>
 
+#ifdef __linux__
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#endif
+
 #include <gmp.h>
 
 #include "libguile/_scm.h"
@@ -802,6 +807,22 @@ scm_fill_sockaddr (int fam, SCM address, SCM *args, int 
which_arg,
        return (struct sockaddr *) soka;
       }
 #endif
+#ifdef __linux__
+    case AF_NETLINK:
+      {
+        struct sockaddr_nl *soka;
+
+        soka = (struct sockaddr_nl *) scm_malloc (sizeof (struct sockaddr_nl));
+
+        soka->nl_family = AF_NETLINK;
+        soka->nl_pad    = 0;
+        soka->nl_pid    = 0;
+        soka->nl_groups = 0;
+
+        *size = sizeof (struct sockaddr_nl);
+        return (struct sockaddr *) soka;
+      }
+#endif
 #ifdef HAVE_UNIX_DOMAIN_SOCKETS
     case AF_UNIX:
       {
@@ -1024,6 +1045,19 @@ _scm_from_sockaddr (const scm_t_max_sockaddr *address, 
unsigned addr_size,
       }
       break;
 #endif
+#ifdef AF_NETLINK
+    case AF_NETLINK:
+      {
+        const struct sockaddr_nl *nad = (struct sockaddr_nl *) address;
+
+        result = scm_c_make_vector (3, SCM_UNSPECIFIED);
+        SCM_SIMPLE_VECTOR_SET(result, 0, scm_from_short (fam));
+        SCM_SIMPLE_VECTOR_SET(result, 1, scm_from_uint32 (nad->nl_pid));
+        SCM_SIMPLE_VECTOR_SET(result, 2, scm_from_uint32 (nad->nl_groups));
+
+        break;
+      }
+#endif
 #ifdef HAVE_UNIX_DOMAIN_SOCKETS
     case AF_UNIX:
       {
@@ -1140,6 +1174,30 @@ scm_to_sockaddr (SCM address, size_t *address_size)
       }
 #endif
 
+#ifdef __linux__
+    case AF_NETLINK:
+      {
+       if (SCM_SIMPLE_VECTOR_LENGTH (address) != 3)
+         scm_misc_error (FUNC_NAME, "invalid netlink address representation: 
~A",
+                         scm_list_1 (address));
+       else
+         {
+           struct sockaddr_nl c_nl;
+
+            c_nl.nl_family = AF_NETLINK;
+            c_nl.nl_pad = 0;
+            c_nl.nl_pid = scm_to_uint32 (SCM_SIMPLE_VECTOR_REF (address, 1));
+            c_nl.nl_groups = scm_to_uint32 (SCM_SIMPLE_VECTOR_REF (address, 
2));
+
+           *address_size = sizeof (c_nl);
+           c_address = scm_malloc (sizeof (c_nl));
+           memcpy (c_address, &c_nl, sizeof (c_nl));
+         }
+
+       break;
+      }
+#endif
+
 #ifdef HAVE_UNIX_DOMAIN_SOCKETS
     case AF_UNIX:
       {
@@ -1699,6 +1757,9 @@ scm_init_socket ()
 #ifdef AF_INET6
   scm_c_define ("AF_INET6", scm_from_int (AF_INET6));
 #endif
+#ifdef AF_NETLINK
+  scm_c_define ("AF_NETLINK", scm_from_int (AF_NETLINK));
+#endif
 
 #ifdef PF_UNSPEC
   scm_c_define ("PF_UNSPEC", scm_from_int (PF_UNSPEC));
@@ -1712,6 +1773,71 @@ scm_init_socket ()
 #ifdef PF_INET6
   scm_c_define ("PF_INET6", scm_from_int (PF_INET6));
 #endif
+#ifdef PF_NETLINK
+  scm_c_define ("PF_NETLINK", scm_from_int (PF_NETLINK));
+#endif
+
+  /* netlink families.  */
+#ifdef NETLINK_ROUTE
+  scm_c_define ("NETLINK_ROUTE", scm_from_int (NETLINK_ROUTE));
+#endif
+#ifdef NETLINK_USERSOCK
+  scm_c_define ("NETLINK_USERSOCK", scm_from_int (NETLINK_USERSOCK));
+#endif
+#ifdef NETLINK_FIREWALL
+  scm_c_define ("NETLINK_FIREWALL", scm_from_int (NETLINK_FIREWALL));
+#endif
+#ifdef NETLINK_SOCK_DIAG
+  scm_c_define ("NETLINK_SOCK_DIAG", scm_from_int (NETLINK_SOCK_DIAG));
+#endif
+#ifdef NETLINK_NFLOG
+  scm_c_define ("NETLINK_NFLOG", scm_from_int (NETLINK_NFLOG));
+#endif
+#ifdef NETLINK_XFRM
+  scm_c_define ("NETLINK_XFRM", scm_from_int (NETLINK_XFRM));
+#endif
+#ifdef NETLINK_SELINUX
+  scm_c_define ("NETLINK_SELINUX", scm_from_int (NETLINK_SELINUX));
+#endif
+#ifdef NETLINK_ISCSI
+  scm_c_define ("NETLINK_ISCSI", scm_from_int (NETLINK_ISCSI));
+#endif
+#ifdef NETLINK_AUDIT
+  scm_c_define ("NETLINK_AUDIT", scm_from_int (NETLINK_AUDIT));
+#endif
+#ifdef NETLINK_FIB_LOOKUP
+  scm_c_define ("NETLINK_FIB_LOOKUP", scm_from_int (NETLINK_FIB_LOOKUP));
+#endif
+#ifdef NETLINK_CONNECTOR
+  scm_c_define ("NETLINK_CONNECTOR", scm_from_int (NETLINK_CONNECTOR));
+#endif
+#ifdef NETLINK_NETFILTER
+  scm_c_define ("NETLINK_NETFILTER", scm_from_int (NETLINK_NETFILTER));
+#endif
+#ifdef NETLINK_IP6_FW
+  scm_c_define ("NETLINK_IP6_FW", scm_from_int (NETLINK_IP6_FW));
+#endif
+#ifdef NETLINK_DNRTMSG
+  scm_c_define ("NETLINK_DNRTMSG", scm_from_int (NETLINK_DNRTMSG));
+#endif
+#ifdef NETLINK_KOBJECT_UEVENT
+  scm_c_define ("NETLINK_KOBJECT_UEVENT", scm_from_int 
(NETLINK_KOBJECT_UEVENT));
+#endif
+#ifdef NETLINK_GENERIC
+  scm_c_define ("NETLINK_GENERIC", scm_from_int (NETLINK_GENERIC));
+#endif
+#ifdef NETLINK_SCSITRANSPORT
+  scm_c_define ("NETLINK_SCSITRANSPORT", scm_from_int (NETLINK_SCSITRANSPORT));
+#endif
+#ifdef NETLINK_ECRYPTFS
+  scm_c_define ("NETLINK_ECRYPTFS", scm_from_int (NETLINK_ECRYPTFS));
+#endif
+#ifdef NETLINK_RDMA
+  scm_c_define ("NETLINK_RDMA", scm_from_int (NETLINK_RDMA));
+#endif
+#ifdef NETLINK_CRYPTO
+  scm_c_define ("NETLINK_CRYPTO", scm_from_int (NETLINK_CRYPTO));
+#endif
 
   /* standard addresses.  */
 #ifdef INADDR_ANY
@@ -1843,6 +1969,83 @@ scm_init_socket ()
   scm_c_define ("IP_MULTICAST_IF", scm_from_int ( IP_MULTICAST_IF));
 #endif
 
+  /* netlink multicast groups */
+#ifdef RTNLGRP_NONE
+  scm_c_define ("RTNLGRP_NONE", scm_from_int (RTNLGRP_NONE));
+#endif
+#ifdef RTNLGRP_LINK
+  scm_c_define ("RTNLGRP_LINK", scm_from_int (RTNLGRP_LINK));
+#endif
+#ifdef RTNLGRP_NOTIFY
+  scm_c_define ("RTNLGRP_NOTIFY", scm_from_int (RTNLGRP_NOTIFY));
+#endif
+#ifdef RTNLGRP_NEIGH
+  scm_c_define ("RTNLGRP_NEIGH", scm_from_int (RTNLGRP_NEIGH));
+#endif
+#ifdef RTNLGRP_TC
+  scm_c_define ("RTNLGRP_TC", scm_from_int (RTNLGRP_TC));
+#endif
+#ifdef RTNLGRP_IPV4_IFADDR
+  scm_c_define ("RTNLGRP_IPV4_IFADDR", scm_from_int (RTNLGRP_IPV4_IFADDR));
+#endif
+#ifdef RTNLGRP_IPV4_MROUTE
+  scm_c_define ("RTNLGRP_IPV4_MROUTE", scm_from_int (RTNLGRP_IPV4_MROUTE));
+#endif
+#ifdef RTNLGRP_IPV4_ROUTE
+  scm_c_define ("RTNLGRP_IPV4_ROUTE", scm_from_int (RTNLGRP_IPV4_ROUTE));
+#endif
+#ifdef RTNLGRP_IPV4_RULE
+  scm_c_define ("RTNLGRP_IPV4_RULE", scm_from_int (RTNLGRP_IPV4_RULE));
+#endif
+#ifdef RTNLGRP_IPV6_IFADDR
+  scm_c_define ("RTNLGRP_IPV6_IFADDR", scm_from_int (RTNLGRP_IPV6_IFADDR));
+#endif
+#ifdef RTNLGRP_IPV6_MROUTE
+  scm_c_define ("RTNLGRP_IPV6_MROUTE", scm_from_int (RTNLGRP_IPV6_MROUTE));
+#endif
+#ifdef RTNLGRP_IPV6_ROUTE
+  scm_c_define ("RTNLGRP_IPV6_ROUTE", scm_from_int (RTNLGRP_IPV6_ROUTE));
+#endif
+#ifdef RTNLGRP_IPV6_IFINFO
+  scm_c_define ("RTNLGRP_IPV6_IFINFO", scm_from_int (RTNLGRP_IPV6_IFINFO));
+#endif
+#ifdef RTNLGRP_DECnet_IFADDR
+  scm_c_define ("RTNLGRP_DECnet_IFADDR", scm_from_int (RTNLGRP_DECnet_IFADDR));
+#endif
+#ifdef RTNLGRP_DECnet_ROUTE
+  scm_c_define ("RTNLGRP_DECnet_ROUTE", scm_from_int (RTNLGRP_DECnet_ROUTE));
+#endif
+#ifdef RTNLGRP_DECnet_RULE
+  scm_c_define ("RTNLGRP_DECnet_RULE", scm_from_int (RTNLGRP_DECnet_RULE));
+#endif
+#ifdef RTNLGRP_IPV6_PREFIX
+  scm_c_define ("RTNLGRP_IPV6_PREFIX", scm_from_int (RTNLGRP_IPV6_PREFIX));
+#endif
+#ifdef RTNLGRP_IPV6_RULE
+  scm_c_define ("RTNLGRP_IPV6_RULE", scm_from_int (RTNLGRP_IPV6_RULE));
+#endif
+#ifdef RTNLGRP_ND_USEROPT
+  scm_c_define ("RTNLGRP_ND_USEROPT", scm_from_int (RTNLGRP_ND_USEROPT));
+#endif
+#ifdef RTNLGRP_PHONET_IFADDR
+  scm_c_define ("RTNLGRP_PHONET_IFADDR", scm_from_int (RTNLGRP_PHONET_IFADDR));
+#endif
+#ifdef RTNLGRP_PHONET_ROUTE
+  scm_c_define ("RTNLGRP_PHONET_ROUTE", scm_from_int (RTNLGRP_PHONET_ROUTE));
+#endif
+#ifdef RTNLGRP_DCB
+  scm_c_define ("RTNLGRP_DCB", scm_from_int (RTNLGRP_DCB));
+#endif
+#ifdef RTNLGRP_IPV4_NETCONF
+  scm_c_define ("RTNLGRP_IPV4_NETCONF", scm_from_int (RTNLGRP_IPV4_NETCONF));
+#endif
+#ifdef RTNLGRP_IPV6_NETCONF
+  scm_c_define ("RTNLGRP_IPV6_NETCONF", scm_from_int (RTNLGRP_IPV6_NETCONF));
+#endif
+#ifdef RTNLGRP_MDB
+  scm_c_define ("RTNLGRP_MDB", scm_from_int (RTNLGRP_MDB));
+#endif
+
   scm_add_feature ("socket");
 
 #include "libguile/socket.x"
diff --git a/module/ice-9/networking.scm b/module/ice-9/networking.scm
index f9ff394..1146d80 100644
--- a/module/ice-9/networking.scm
+++ b/module/ice-9/networking.scm
@@ -85,6 +85,8 @@
 (define (sockaddr:port obj) (vector-ref obj 2))
 (define (sockaddr:flowinfo obj) (vector-ref obj 3))
 (define (sockaddr:scopeid obj) (vector-ref obj 4))
+(define (sockaddr:pid obj) (vector-ref obj 1))
+(define (sockaddr:groups obj) (vector-ref obj 2))
 
 (define (addrinfo:flags obj) (vector-ref obj 0))
 (define (addrinfo:fam obj) (vector-ref obj 1))
-- 
2.1.4

-- 
David Thompson
Web Developer - Free Software Foundation - http://fsf.org
GPG Key: 0FF1D807
Support the FSF: https://fsf.org/donate

reply via email to

[Prev in Thread] Current Thread [Next in Thread]