1

I want to set some local sysctl parameters with my program and I followed the directions given here: http://www.linux.it/~rubini/docs/sysctl/

As an example, here's what I'm doing to set the value for /proc/sys/net/ipv6/conf/tun0/accept_ra. I just configured my tun0 interface prior to this call. (I verified that my interface is up and I was able to assign an IP address as well)

int path_len = 5;
int tun0_accept_ra_path[] =  { CTL_NET,
                               NET_IPV6,
                               NET_IPV6_CONF,
                               ifr6.ifr6_ifindex, // This ifindex comes from an interface configured above
                               NET_IPV6_ACCEPT_RA };
int tun0_accept_ra_value = 0;
if (sysctl(tun0_accept_ra_path,
           path_len,
           NULL,
           0,
           &tun0_accept_ra_value,
           sizeof(tun0_accept_ra_value)) < 0) {
  printf("set sysctl 'accept_ra' failed. errno: %d\n", errno);
}

I get: set sysctl 'accept_ra' failed. errno: 38 Function not implemented

Any thoughts as to what could be wrong? I'm running as sudo so I don't think I should have access privilege issues.

I'm running Debian GNU/Linux 7.0 (wheezy) on a raspberry pi.

SuPra
  • 8,488
  • 4
  • 37
  • 30
  • 2
    Quoth my man page: "Glibc does not provide a wrapper for this system call; call it using `syscall(2)`. Or rather... **don't** call it: use of this system call has long been discouraged, and it is so unloved that it is likely to disappear in a future kernel version. Since Linux 2.6.24, uses of this system call result in warnings in the kernel log. Remove it from your programs now; use the /proc/sys interface instead. This system call is available only if the kernel was configured with the CONFIG_SYSCTL_SYSCALL option." – Daniel Fischer Jul 24 '13 at 21:52
  • Thank you! Feeling silly about missing this, but I'm glad I've been made privy to it now. – SuPra Jul 25 '13 at 14:23

1 Answers1

7

The tutorial you used is too old! if you want a reference for this system call you should check out this link : http://man7.org/linux/man-pages/man2/sysctl.2.html

You get SIGSYS error because the sysctl does not exist. The correct name for that system is *_syscall* and glibc does not provide a wrapper becuase this syscall should not be called (it will be removed from the next Linux versions). You can be achieve the same result using the /proc interface.

If you want to keep your solution, you should change the code as follows ( I have not tested ,sorry):

#include <sys/syscall.h> 

int path_len = 5;
int tun0_accept_ra_path[] =  { CTL_NET,
                               NET_IPV6,
                               NET_IPV6_CONF,
                               ifr6.ifr6_ifindex, 
                               NET_IPV6_ACCEPT_RA };
int tun0_accept_ra_value = 0;
if (syscall(__NR_sysctl, 
           tun0_accept_ra_path,
           path_len,
           NULL,
           0,
           &tun0_accept_ra_value,
           sizeof(tun0_accept_ra_value)) < 0) {
  printf("set sysctl 'accept_ra' failed. errno: %d\n", errno);
}

A better solution may be :

int tun0_accept_ra_value = 0;

if ((fd=open("/proc/sys/net/ipv6/conf/tun0/accept_ra", O_RDWR)) < 0) 
   perror("OPEN"); 

if (write (fd, &tun0_accept_ra_value, sizeof(int)) < 0)
   perror("WRITE"); 

close(fd); 

I hope I have been useful.

Giuseppe Pes
  • 7,772
  • 3
  • 52
  • 90
  • Thanks a lot! I should have checked that using this syscall is discouraged. I'm just writing to the file directly now and that works fine. I'd probably also use the O_TRUNC flag up there to make sure to over-write. – SuPra Jul 25 '13 at 15:20