summaryrefslogtreecommitdiff
path: root/pfinet/iioctl-ops.c
diff options
context:
space:
mode:
Diffstat (limited to 'pfinet/iioctl-ops.c')
-rw-r--r--pfinet/iioctl-ops.c369
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;
+}