diff options
Diffstat (limited to 'pfinet/iioctl-ops.c')
-rw-r--r-- | pfinet/iioctl-ops.c | 369 |
1 files changed, 369 insertions, 0 deletions
diff --git a/pfinet/iioctl-ops.c b/pfinet/iioctl-ops.c new file mode 100644 index 00000000..0f82f622 --- /dev/null +++ b/pfinet/iioctl-ops.c @@ -0,0 +1,369 @@ +/* + Copyright (C) 2000 Free Software Foundation, Inc. + Written by Marcus Brinkmann. + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + The GNU Hurd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ + +#include "pfinet.h" + +#include <linux/netdevice.h> +#include <linux/notifier.h> + +#include "iioctl_S.h" +#include <netinet/in.h> +#include <fcntl.h> +#include <string.h> +#include <unistd.h> +#include <mach/notify.h> +#include <sys/mman.h> +#include <hurd/fshelp.h> + +#include <sys/ioctl.h> +#include <net/if.h> + +extern struct notifier_block *netdev_chain; + +/* devinet.c */ +extern error_t configure_device (struct device *dev, uint32_t addr, + uint32_t netmask, uint32_t peer, + uint32_t broadcast); +extern void inquire_device (struct device *dev, uint32_t *addr, + uint32_t *netmask, uint32_t *peer, + uint32_t *broadcast); + +/* Truncate name, take the global lock and find device with this name. */ +struct device *get_dev (char *name) +{ + char ifname[16]; + struct device *dev; + + memcpy (ifname, name, IFNAMSIZ-1); + ifname[IFNAMSIZ-1] = 0; + + __mutex_lock (&global_lock); + + for (dev = dev_base; dev; dev = dev->next) + if (strcmp (dev->name, ifname) == 0) + break; + + return dev; +} + +enum siocgif_type +{ + ADDR, + NETMASK, + DSTADDR, + BRDADDR +}; + +#define SIOCGIF(name, type) \ + kern_return_t \ + S_iioctl_siocgif##name (io_t port, \ + ifname_t ifnam, \ + sockaddr_t *addr) \ + { \ + return siocgifXaddr (port, ifnam, addr, type); \ + } + +/* Get some sockaddr type of info. */ +static kern_return_t +siocgifXaddr (io_t port, + ifname_t ifnam, + sockaddr_t *addr, + enum siocgif_type type) +{ + error_t err = 0; + struct device *dev; + struct sockaddr_in *sin = (struct sockaddr_in *) addr; + uint32_t addrs[4]; + + if (!port) + return EOPNOTSUPP; + + dev = get_dev (ifnam); + if (!dev) + err = ENODEV; + else + { + sin->sin_family = AF_INET; + + inquire_device (dev, &addrs[0], &addrs[1], &addrs[2], &addrs[3]); + sin->sin_addr.s_addr = addrs[type]; + } + __mutex_unlock (&global_lock); + return err; +} + +#define SIOCSIF(name, type) \ + kern_return_t \ + S_iioctl_siocsif##name (io_t port, \ + ifname_t ifnam, \ + sockaddr_t addr) \ + { \ + return siocsifXaddr (port, ifnam, &addr, type); \ + } + +/* Set some sockaddr type of info. */ +static kern_return_t +siocsifXaddr (io_t port, + ifname_t ifnam, + sockaddr_t *addr, + enum siocgif_type type) +{ + struct sock_user *user = begin_using_socket_port(port); + error_t err = 0; + struct device *dev; + struct sockaddr_in *sin = (struct sockaddr_in *) addr; + uint32_t addrs[4]; + + if (!user) + return EOPNOTSUPP; + + dev = get_dev (ifnam); + + /* Only root is allowed to change the interface configuration. + XXX Check the underlying node as well. */ + if (!user->isroot) + err = EPERM; + else if (!dev) + err = ENODEV; + else if (sin->sin_family != AF_INET) + err = EINVAL; + else + { + inquire_device (dev, &addrs[0], &addrs[1], &addrs[2], &addrs[3]); + addrs[type] = sin->sin_addr.s_addr; + err = configure_device (dev, addrs[0], addrs[1], addrs[2], addrs[3]); + } + + __mutex_unlock (&global_lock); + end_using_socket_port (user); + return err; +} + +/* 12 SIOCSIFADDR -- Set address of a network interface. */ +SIOCSIF (addr, ADDR); + +/* 14 SIOCSIFDSTADDR -- Set point-to-point (peer) address of a network interface. */ +SIOCSIF (dstaddr, DSTADDR); + +/* 16 SIOCSIFFLAGS -- Set flags of a network interface. */ +kern_return_t +S_iioctl_siocsifflags (io_t port, + ifname_t ifnam, + short flags) +{ + struct sock_user *user = begin_using_socket_port (port); + error_t err = 0; + struct device *dev; + + if (!user) + return EOPNOTSUPP; + + dev = get_dev (ifnam); + + /* Only root is allowed to change the interface configuration. + XXX Check the underlying node as well. */ + if (!user->isroot) + err = EPERM; + else if (!dev) + err = ENODEV; + else + err = dev_change_flags(dev, flags); + + __mutex_unlock (&global_lock); + end_using_socket_port (user); + return err; +} + +/* 17 SIOCGIFFLAGS -- Get flags of a network interface. */ +kern_return_t +S_iioctl_siocgifflags (io_t port, + char *name, + short *flags) +{ + error_t err = 0; + struct device *dev; + + dev = get_dev (name); + if (!dev) + err = ENODEV; + else + { + *flags = dev->flags; + } + __mutex_unlock (&global_lock); + return err; +} + +/* 19 SIOCSIFBRDADDR -- Set broadcast address of a network interface. */ +SIOCSIF (brdaddr, BRDADDR); + +/* 22 SIOCSIFNETMASK -- Set netmask of a network interface. */ +SIOCSIF (netmask, NETMASK); + +/* 23 SIOCGIFMETRIC -- Get metric of a network interface. */ +kern_return_t +S_iioctl_siocgifmetric (io_t port, + ifname_t ifnam, + int *metric) +{ + error_t err = 0; + struct device *dev; + + dev = get_dev (ifnam); + if (!dev) + err = ENODEV; + else + { + *metric = 0; /* Not supported. */ + } + __mutex_unlock (&global_lock); + return err; +} + +/* 24 SIOCSIFMETRIC -- Set metric of a network interface. */ +kern_return_t +S_iioctl_siocsifmetric (io_t port, + ifname_t ifnam, + int metric) +{ + return EOPNOTSUPP; +} + +/* 25 SIOCDIFADDR -- Delete interface address. */ +kern_return_t +S_iioctl_siocdifaddr (io_t port, + ifname_t ifnam, + sockaddr_t addr) +{ + return EOPNOTSUPP; +} + +/* 33 SIOCGIFADDR -- Get address of a network interface. */ +SIOCGIF (addr, ADDR); + +/* 34 SIOCGIFDSTADDR -- Get point-to-point address of a network interface. */ +SIOCGIF (dstaddr, DSTADDR); + +/* 35 SIOCGIFBRDADDR -- Get broadcast address of a network interface. */ +SIOCGIF (brdaddr, BRDADDR); + +/* 37 SIOCGIFNETMASK -- Get netmask of a network interface. */ +SIOCGIF (netmask, NETMASK); + +/* 51 SIOCGIFMTU -- Get mtu of a network interface. */ +error_t +S_iioctl_siocgifmtu (io_t port, + ifname_t ifnam, + int *mtu) +{ + error_t err = 0; + struct device *dev; + + dev = get_dev (ifnam); + if (!dev) + err = ENODEV; + else + { + *mtu = dev->mtu; + } + __mutex_unlock (&global_lock); + return err; +} + +/* 51 SIOCSIFMTU -- Set mtu of a network interface. */ +error_t +S_iioctl_siocsifmtu (io_t port, + ifname_t ifnam, + int mtu) +{ + struct sock_user *user = begin_using_socket_port (port); + error_t err = 0; + struct device *dev; + + if (!user) + return EOPNOTSUPP; + + dev = get_dev (ifnam); + + /* Only root is allowed to change the interface configuration. + XXX Check the underlying node as well. */ + if (!user->isroot) + err = EPERM; + if (!dev) + err = ENODEV; + else if (mtu <= 0) + err = EINVAL; + else + { + if (dev->change_mtu) + dev->change_mtu (dev, mtu); + else + dev->mtu = mtu; + + notifier_call_chain (&netdev_chain, NETDEV_CHANGEMTU, dev); + } + + __mutex_unlock (&global_lock); + end_using_socket_port (user); + return err; +} + +/* 100 SIOCGIFINDEX -- Get index number of a network interface. */ +error_t +S_iioctl_siocgifindex (io_t port, + ifname_t ifnam, + int *index) +{ + error_t err = 0; + struct device *dev; + + dev = get_dev (ifnam); + if (!dev) + err = ENODEV; + else + { + *index = dev->ifindex; + } + __mutex_unlock (&global_lock); + return err; +} + +/* 101 SIOCGIFNAME -- Get name of a network interface from index number. */ +error_t +S_iioctl_siocgifname (io_t port, + ifname_t ifnam, + int *index) +{ + error_t err = 0; + struct device *dev; + + __mutex_lock (&global_lock); + dev = dev_get_by_index (*index); + if (!dev) + err = ENODEV; + else + { + strncpy (ifnam, dev->name, IFNAMSIZ); + ifnam[IFNAMSIZ-1] = '\0'; + } + __mutex_unlock (&global_lock); + + return err; +} |