summaryrefslogtreecommitdiff
path: root/pfinet/linux-inet/af_inet.c
diff options
context:
space:
mode:
authorRoland McGrath <roland@gnu.org>2000-02-04 06:32:39 +0000
committerRoland McGrath <roland@gnu.org>2000-02-04 06:32:39 +0000
commitdb9a26cbd125ec106e040ea6084911f9bc0c0198 (patch)
tree8394aedf0addf9de2afd46d00c192d20d9eb9092 /pfinet/linux-inet/af_inet.c
parent8880a73970b23f10c720011cb910c0e0e1e02975 (diff)
2000-02-03 Roland McGrath <roland@baalperazim.frob.com>
Complete overhaul of pfinet based on the IPv4 networking code from the Linux 2.2.12 kernel sources. This page describes a single unified set of interdependent changes, but there are so many changes that I have broken up the log entry into paragraphs based on rough topical divisions of the work involved. Subset of verbatim Linux 2.2.12 sources imported on a vendor branch. * linux-src: New directory, see README for details. * README: New file, describes linux-src layout and procedures for tracking Linux source updates. Light modifications to linux-src files to avoid really bending over backwards with the glue macros. All modifications to files in linux-src are conditionalized by #ifdef _HURD_. * linux-src/include/linux/net.h [_HURD_] (struct socket): New members refcnt and identity; elide members fasync_list, file. * linux-src/include/linux/rtnetlink.h [! CONFIG_RTNETLINK] (rtnl_shlock, rtnl_shunlock) [! _HURD_]: Conditionalize contents on this, making these no-ops #ifdef _HURD_. * linux-src/net/core/dev.c [_HURD_] (dev_ioctl): Don't define the function, instead #define it to 0. * linux-src/net/ipv4/af_inet.c [_HURD_] (inet_ioctl): Likewise. * linux-src/net/ipv4/arp.c [_HURD_] (arp_ioctl): Likewise. * linux-src/net/ipv4/udp.c [_HURD_] (udp_ioctl): Likewise. * linux-src/net/ipv4/tcp.c [_HURD_] (tcp_ioctl): Likewise. [_HURD_] (tcp_tiocinq): New function, TIOCINQ code from tcp_ioctl. * linux-src/net/ipv4/devinet.c [_HURD_] (devinet_ioctl): Don't define the function, instead #define it to 0. [_HURD_] (configure_device): New function, cobbled from SIOCSIFADDR and SIOCSIFNETMASK code from devinet_ioctl. * glue-include/asm, glue-include/linux: New directories. These contain glue kludge headers that replace all of the Linux <asm/*.h> headers except checksum.h, and several of the Linux <linux/*.h> headers (the remainder come from linux-src/include/linux and are mostly unmodified). * glue-include/asm/atomic.h: New file, glue replacement header. * glue-include/asm/bitops.h: New file, glue replacement header. * glue-include/asm/byteorder.h: New file, glue replacement header. * glue-include/asm/checksum.h: New file, glue replacement header. * glue-include/asm/errno.h: New file, glue replacement header. * glue-include/asm/hardirq.h: New file, glue replacement header. * glue-include/asm/init.h: New file, glue replacement header. * glue-include/asm/segment.h: New file, glue replacement header. * glue-include/asm/spinlock.h: New file, glue replacement header. * glue-include/asm/system.h: New file, glue replacement header. * glue-include/asm/types.h: New file, glue replacement header. * glue-include/asm/uaccess.h: New file, glue replacement header. * glue-include/linux/autoconf.h: New file, glue replacement header. * glue-include/linux/binfmts.h: New file, glue replacement header. * glue-include/linux/config.h: New file, glue replacement header. * glue-include/linux/errno.h: New file, glue replacement header. * glue-include/linux/fcntl.h: New file, glue replacement header. * glue-include/linux/fs.h: New file, glue replacement header. * glue-include/linux/in.h: New file, glue replacement header. * glue-include/linux/in6.h: New file, glue replacement header. * glue-include/linux/interrupt.h: New file, glue replacement header. * glue-include/linux/ioctl.h: New file, glue replacement header. * glue-include/linux/ipv6.h: New file, glue replacement header. * glue-include/linux/kernel.h: New file, glue replacement header. * glue-include/linux/limits.h: New file, glue replacement header. * glue-include/linux/major.h: New file, glue replacement header. * glue-include/linux/malloc.h: New file, glue replacement header. * glue-include/linux/mm.h: New file, glue replacement header. * glue-include/linux/param.h: New file, glue replacement header. * glue-include/linux/personality.h: New file, glue replacement header. * glue-include/linux/poll.h: New file, glue replacement header. * glue-include/linux/proc_fs.h: New file, glue replacement header. * glue-include/linux/sched.h: New file, glue replacement header. * glue-include/linux/slab.h: New file, glue replacement header. * glue-include/linux/socket.h: New file, glue replacement header. * glue-include/linux/sockios.h: New file, glue replacement header. * glue-include/linux/stat.h: New file, glue replacement header. * glue-include/linux/string.h: New file, glue replacement header. * glue-include/linux/termios.h: New file, glue replacement header. * glue-include/linux/time.h: New file, glue replacement header. * glue-include/linux/timer.h: New file, glue replacement header. * glue-include/linux/timex.h: New file, glue replacement header. * glue-include/linux/types.h: New file, glue replacement header. * glue-include/linux/un.h: New file, glue replacement header. * glue-include/linux/version.h: New file, glue replacement header. * glue-include/linux/wait.h: New file, glue replacement header. * kmem_cache.c: New file. Glue code replaces Linux kmem_cache_t et al. * stubs.c: New file. No-op functions and stub variables for a few things the Linux networking code needs to link. * Makefile (core-srcs, arch-lib-srcs, ethernet-srcs, ipv4-srcs): New variables, listing sources used from linux-src subdirectories. (LINUXSRCS): Define using those. (SRCS): Remove devices.c; add kmem_cache.c, stubs.c. (UNUSEDSRC): Variable removed. (vpath %.c): Remove vpath for $(srcdir)/linux-inet directory. Add vpaths for $(srcdir)/linux-src subdirectories. (CPPFLAGS): Add -D_HURD_SYSTYPE defining it to $(asm_syntax) as a double-quoted string. Add -I's for glue-include and linux-src/include. * pfinet.h: Include <sys/socket.h>, and not <linux/netdevice.h>. (master_device): Remove decl. (global_lock, packet_queue_lock): Remove common defns. (global_lock, net_bh_lock): Declare them as externs. (struct sockaddr): Remove len member, make address member just a struct sockaddr rather than a 0-length array. (setup_loopback_device, become_task_protid, become_task): Remove decls. (ethernet_initialize): Declare it. (input_work_thread): Remove decl. (net_bh_thread): Declare it. (tcp_readable): Remove decl. (tcp_tiocinq): Declare it. * config.h: Rewritten based on Linux 2.2.12 set of CONFIG_* options. (CONFIG_NET, CONFIG_INET, CONFIG_SKB_LARGE): These are the only Linux config options we set. (CONFIG_IP_NOSIOCRT): New macro (not a proper config option, but used conveniently in the code). * ethernet.c (ethernet_set_multi): Take only one parameter. Remove assert, since we always get passed IGMP_ALL_HOSTS. (ethernet_thread): Make static. (ethernet_demuxer): Use __mutex_lock in place of mutex_lock, so as to get cthreads instead of linux/spinlock.h glue macros. Lock net_bh_lock instead of global_lock. Set SKB->protocol with eth_type_trans before calling netif_rx. (ethernet_initialize): New function, one-time initialization broken out of ethernet_open. (ethernet_open): Ports setup moved to ethernet_initialize. Don't use `errno' to avoid glue conflicts. Use get_privileged_ports here to get the master device port, and deallocate it after calling device_open. (ethernet_xmit): Use assert_perror. Only one arg to dev_kfree_skb now. (setup_ethernet_device): Change initializations for structure changes. Call dev_init_buffers and register_netdevice on the device. * timer-emul.c (all functions): Use __mutex_lock instead of mutex_lock. Adjust for renaming of `prevp' member to `prev' in struct timer_list. (mod_timer): New function. * socket.c (proto_ops): Variable removed. (net_families): New variable replaces it. (sock_register): Rewritten for new calling convention, set net_families rather than proto_ops. (make_sock_user, clean_socketport, sock_alloc, sock_release): Functions moved here from misc.c. * sched.c (packet_queue_lock): Variable removed. (net_bh_lock, net_bh_wakeup): New variables. (current): Variable removed (now a macro in the glue headers). (interruptible_sleep_on, wake_up_interruptible): Functions removed. They are replaced by inlines in the glue headers. (become_task, become_task_protid): Functions removed; they are replaced by macros in glue-include/linux/sched.h. (net_bh_worker): New function. * loopback.c: Completely rewritten, mostly copied from linux-2.2.12's drivers/net/loopback.c source file. * io-ops.c (all functions): Use __mutex_lock in place of mutex_lock. (S_io_write): Call ops->sendmsg instead of ops->write, which no longer exists. If O_NONBLOCK is set, set MSG_DONTWAIT in msg_flags. (S_io_read): Call ops->recvmsg instead of ops->read, which no longer exists If O_NONBLOCK is set, pass MSG_DONTWAIT. (S_io_readable): Use USER->sock->data in place of USER->sock->sk. For SOCK_STREAM and SOCK_SEQPACKET types, call tcp_tiocinq. (S_io_set_all_openmodes, S_io_get_openmodes, S_io_set_some_openmodes, S_io_clear_some_openmodes): Member USER->sock->userflags is now renamed USER->sock->flags. (S_io_select): Completely rewritten using ops->poll. (select_wait): Function removed. (S_io_stat): Set st_mode to reflect S_IFSOCK. * socket-ops.c (all functions): Use __mutex_lock instead of mutex_lock. (S_socket_create): Don't set SOCK->ops or call SOCK->ops->create. Instead, call net_families[PF_INET]->create. (S_socket_listen): Remove extra checks; just call ops->listen. (S_socket_accept): Remove extra checks before ops->accept call. Avoid use of goto. (S_socket_connect): Remove extra checks; just call ops->connect. (S_socket_bind): Adjust for struct sock_addr changes. (S_socket_create_address): Likewise. (S_socket_whatis_address): Likewise. (S_socket_connect2): Don't diddle data structures after ops->socketpair call. (S_socket_getopt): Use sock_getsockopt if LEVEL is SOL_SOCKET. Accept any data size, not just sizeof (int). (S_socket_setopt): Use sock_setsockopt if LEVEL is SOL_SOCKET. (S_socket_send): Always use ops->sendmsg instead of ops->send or ops->sendto, which no longer exist. If O_NONBLOCK is set, set MSG_DONTWAIT in msg_flags. (S_socket_recv): Always use ops->recvmsg instead of ops->recv, which no longer exists. If O_NONBLOCK is set, set MSG_DONTWAIT in flags. Check for error from S_socket_create_address. * main.c (find_device): Don't try to set ether_dev.pa_mask (it's gone). (main): Don't call init_devices. Call ethernet_initialize. Start net_bh_worker instead of input_work_thread. Don't call setup_loopback_device. Instead, take global_lock, do prepare_current, and then call sk_init, skb_init, inet_proto_init, and net_dev_init. Keep global_lock held while calling argp_parse. Call arrange_shutdown_notification only after all that. Fix error call for "contacting parent" to pass ERR instead of errno. * options.c (ADDR): #undef before defining macro. (parse_opt): #if 0 out EDESTADDRREQ check (I don't understand it). To apply settings, call configure_devices. (ADD_ADDR_OPT): #if 0 --address and --netmask options. Needs fixed. * misc.c (make_sock_user, clean_socketport, sock_alloc, sock_release): Functions moved to socket.c. (sock_release_peer): Function removed. (make_sockaddr_port): Use struct sockaddr_storage to size buffer. Fix size calculation for new struct sock_addr layout. Initialize sa_family and sa_len of new struct sock_addr. Remove the old Linux (2.0.??) network stack and the glue code for it. * linux-inet, asm, linux: Directories and all files removed. Some of the new files in glue-include came from the old glue headers in the asm and linux directories, but most were substantially modified. * devices.c: File removed. The equivalent glue is now elsewhere.
Diffstat (limited to 'pfinet/linux-inet/af_inet.c')
-rw-r--r--pfinet/linux-inet/af_inet.c1578
1 files changed, 0 insertions, 1578 deletions
diff --git a/pfinet/linux-inet/af_inet.c b/pfinet/linux-inet/af_inet.c
deleted file mode 100644
index d20c8bfb..00000000
--- a/pfinet/linux-inet/af_inet.c
+++ /dev/null
@@ -1,1578 +0,0 @@
-/*
- * INET An implementation of the TCP/IP protocol suite for the LINUX
- * operating system. INET is implemented using the BSD Socket
- * interface as the means of communication with the user level.
- *
- * AF_INET protocol family socket handler.
- *
- * Version: @(#)af_inet.c (from sock.c) 1.0.17 06/02/93
- *
- * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
- * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
- * Florian La Roche, <flla@stud.uni-sb.de>
- * Alan Cox, <A.Cox@swansea.ac.uk>
- *
- * Changes (see also sock.c)
- *
- * A.N.Kuznetsov : Socket death error in accept().
- * John Richardson : Fix non blocking error in connect()
- * so sockets that fail to connect
- * don't return -EINPROGRESS.
- * Alan Cox : Asynchronous I/O support
- * Alan Cox : Keep correct socket pointer on sock structures
- * when accept() ed
- * Alan Cox : Semantics of SO_LINGER aren't state moved
- * to close when you look carefully. With
- * this fixed and the accept bug fixed
- * some RPC stuff seems happier.
- * Niibe Yutaka : 4.4BSD style write async I/O
- * Alan Cox,
- * Tony Gale : Fixed reuse semantics.
- * Alan Cox : bind() shouldn't abort existing but dead
- * sockets. Stops FTP netin:.. I hope.
- * Alan Cox : bind() works correctly for RAW sockets. Note
- * that FreeBSD at least is broken in this respect
- * so be careful with compatibility tests...
- *
- * This program 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 of the License, or (at your option) any later version.
- */
-
-#include <linux/config.h>
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/socket.h>
-#include <linux/in.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/string.h>
-#include <linux/sockios.h>
-#include <linux/net.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-
-#include <asm/segment.h>
-#include <asm/system.h>
-
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include "ip.h"
-#include "protocol.h"
-#include "arp.h"
-#include "rarp.h"
-#include "route.h"
-#include "tcp.h"
-#include "udp.h"
-#include <linux/skbuff.h>
-#include "sock.h"
-#include "raw.h"
-#include "icmp.h"
-
-#define min(a,b) ((a)<(b)?(a):(b))
-
-extern struct proto packet_prot;
-
-
-/*
- * See if a socket number is in use.
- */
-
-static int sk_inuse(struct proto *prot, int num)
-{
- struct sock *sk;
-
- for(sk = prot->sock_array[num & (SOCK_ARRAY_SIZE -1 )];
- sk != NULL; sk=sk->next)
- {
- if (sk->num == num)
- return(1);
- }
- return(0);
-}
-
-
-/*
- * Pick a new socket number
- */
-
-unsigned short get_new_socknum(struct proto *prot, unsigned short base)
-{
- static int start=0;
-
- /*
- * Used to cycle through the port numbers so the
- * chances of a confused connection drop.
- */
-
- int i, j;
- int best = 0;
- int size = 32767; /* a big num. */
- struct sock *sk;
-
- if (base == 0)
- base = PROT_SOCK+1+(start % 1024);
- if (base <= PROT_SOCK)
- {
- base += PROT_SOCK+(start % 1024);
- }
-
- /* Now look through the entire array and try to find an empty ptr. */
- for(i=0; i < SOCK_ARRAY_SIZE; i++)
- {
- j = 0;
- sk = prot->sock_array[(i+base+1) &(SOCK_ARRAY_SIZE -1)];
- while(sk != NULL)
- {
- sk = sk->next;
- j++;
- }
- if (j == 0)
- {
- start =(i+1+start )%1024;
- return(i+base+1);
- }
- if (j < size)
- {
- best = i;
- size = j;
- }
- }
-
- /* Now make sure the one we want is not in use. */
-
- while(sk_inuse(prot, base +best+1))
- {
- best += SOCK_ARRAY_SIZE;
- }
- return(best+base+1);
-}
-
-/*
- * Add a socket into the socket tables by number.
- */
-
-void put_sock(unsigned short num, struct sock *sk)
-{
- struct sock *sk1;
- struct sock *sk2;
- int mask;
- unsigned long flags;
-
- sk->num = num;
- sk->next = NULL;
- num = num &(SOCK_ARRAY_SIZE -1);
-
- /* We can't have an interrupt re-enter here. */
- save_flags(flags);
- cli();
-
- sk->prot->inuse += 1;
- if (sk->prot->highestinuse < sk->prot->inuse)
- sk->prot->highestinuse = sk->prot->inuse;
-
- if (sk->prot->sock_array[num] == NULL)
- {
- sk->prot->sock_array[num] = sk;
- restore_flags(flags);
- return;
- }
- restore_flags(flags);
- for(mask = 0xff000000; mask != 0xffffffff; mask = (mask >> 8) | mask)
- {
- if ((mask & sk->saddr) &&
- (mask & sk->saddr) != (mask & 0xffffffff))
- {
- mask = mask << 8;
- break;
- }
- }
- cli();
- sk1 = sk->prot->sock_array[num];
- for(sk2 = sk1; sk2 != NULL; sk2=sk2->next)
- {
- if (!(sk2->saddr & mask))
- {
- if (sk2 == sk1)
- {
- sk->next = sk->prot->sock_array[num];
- sk->prot->sock_array[num] = sk;
- sti();
- return;
- }
- sk->next = sk2;
- sk1->next= sk;
- sti();
- return;
- }
- sk1 = sk2;
- }
-
- /* Goes at the end. */
- sk->next = NULL;
- sk1->next = sk;
- sti();
-}
-
-/*
- * Remove a socket from the socket tables.
- */
-
-static void remove_sock(struct sock *sk1)
-{
- struct sock *sk2;
- unsigned long flags;
-
- if (!sk1->prot)
- {
- printk("sock.c: remove_sock: sk1->prot == NULL\n");
- return;
- }
-
- /* We can't have this changing out from under us. */
- save_flags(flags);
- cli();
- sk2 = sk1->prot->sock_array[sk1->num &(SOCK_ARRAY_SIZE -1)];
- if (sk2 == sk1)
- {
- sk1->prot->inuse -= 1;
- sk1->prot->sock_array[sk1->num &(SOCK_ARRAY_SIZE -1)] = sk1->next;
- restore_flags(flags);
- return;
- }
-
- while(sk2 && sk2->next != sk1)
- {
- sk2 = sk2->next;
- }
-
- if (sk2)
- {
- sk1->prot->inuse -= 1;
- sk2->next = sk1->next;
- restore_flags(flags);
- return;
- }
- restore_flags(flags);
-}
-
-/*
- * Destroy an AF_INET socket
- */
-
-void destroy_sock(struct sock *sk)
-{
- struct sk_buff *skb;
-
- sk->inuse = 1; /* just to be safe. */
-
- /* In case it's sleeping somewhere. */
- if (!sk->dead)
- sk->write_space(sk);
-
- remove_sock(sk);
-
- /* Now we can no longer get new packets. */
- delete_timer(sk);
- /* Nor send them */
- del_timer(&sk->retransmit_timer);
-
- while ((skb = tcp_dequeue_partial(sk)) != NULL) {
- IS_SKB(skb);
- kfree_skb(skb, FREE_WRITE);
- }
-
- /* Cleanup up the write buffer. */
- while((skb = skb_dequeue(&sk->write_queue)) != NULL) {
- IS_SKB(skb);
- kfree_skb(skb, FREE_WRITE);
- }
-
- /*
- * Don't discard received data until the user side kills its
- * half of the socket.
- */
-
- if (sk->dead)
- {
- while((skb=skb_dequeue(&sk->receive_queue))!=NULL)
- {
- /*
- * This will take care of closing sockets that were
- * listening and didn't accept everything.
- */
- if (skb->sk != NULL && skb->sk != sk)
- {
- IS_SKB(skb);
- skb->sk->dead = 1;
- skb->sk->prot->close(skb->sk, 0);
- }
- IS_SKB(skb);
- kfree_skb(skb, FREE_READ);
- }
- }
-
- /* Now we need to clean up the send head. */
- cli();
- for(skb = sk->send_head; skb != NULL; )
- {
- struct sk_buff *skb2;
-
- /*
- * We need to remove skb from the transmit queue,
- * or maybe the arp queue.
- */
- if (skb->next && skb->prev) {
-/* printk("destroy_sock: unlinked skb\n");*/
- IS_SKB(skb);
- skb_unlink(skb);
- }
- skb->dev = NULL;
- skb2 = skb->link3;
- kfree_skb(skb, FREE_WRITE);
- skb = skb2;
- }
- sk->send_head = NULL;
- sti();
-
- /* And now the backlog. */
- while((skb=skb_dequeue(&sk->back_log))!=NULL)
- {
- /* this should never happen. */
-/* printk("cleaning back_log\n");*/
- kfree_skb(skb, FREE_READ);
- }
-
- /* Now if it has a half accepted/ closed socket. */
- if (sk->pair)
- {
- sk->pair->dead = 1;
- sk->pair->prot->close(sk->pair, 0);
- sk->pair = NULL;
- }
-
- /*
- * Now if everything is gone we can free the socket
- * structure, otherwise we need to keep it around until
- * everything is gone.
- */
-
- if (sk->dead && sk->rmem_alloc == 0 && sk->wmem_alloc == 0)
- {
- kfree_s((void *)sk,sizeof(*sk));
- }
- else
- {
- /* this should never happen. */
- /* actually it can if an ack has just been sent. */
- sk->destroy = 1;
- sk->ack_backlog = 0;
- sk->inuse = 0;
- reset_timer(sk, TIME_DESTROY, SOCK_DESTROY_TIME);
- }
-}
-
-/*
- * The routines beyond this point handle the behaviour of an AF_INET
- * socket object. Mostly it punts to the subprotocols of IP to do
- * the work.
- */
-
-static int inet_fcntl(struct socket *sock, unsigned int cmd, unsigned long arg)
-{
- struct sock *sk;
-
- sk = (struct sock *) sock->data;
-
- switch(cmd)
- {
- case F_SETOWN:
- /*
- * This is a little restrictive, but it's the only
- * way to make sure that you can't send a sigurg to
- * another process.
- */
- if (!suser() && current->pgrp != -arg &&
- current->pid != arg) return(-EPERM);
- sk->proc = arg;
- return(0);
- case F_GETOWN:
- return(sk->proc);
- default:
- return(-EINVAL);
- }
-}
-
-/*
- * Set socket options on an inet socket.
- */
-
-static int inet_setsockopt(struct socket *sock, int level, int optname,
- char *optval, int optlen)
-{
- struct sock *sk = (struct sock *) sock->data;
- if (level == SOL_SOCKET)
- return sock_setsockopt(sk,level,optname,optval,optlen);
- if (sk->prot->setsockopt==NULL)
- return(-EOPNOTSUPP);
- else
- return sk->prot->setsockopt(sk,level,optname,optval,optlen);
-}
-
-/*
- * Get a socket option on an AF_INET socket.
- */
-
-static int inet_getsockopt(struct socket *sock, int level, int optname,
- char *optval, int *optlen)
-{
- struct sock *sk = (struct sock *) sock->data;
- if (level == SOL_SOCKET)
- return sock_getsockopt(sk,level,optname,optval,optlen);
- if(sk->prot->getsockopt==NULL)
- return(-EOPNOTSUPP);
- else
- return sk->prot->getsockopt(sk,level,optname,optval,optlen);
-}
-
-/*
- * Automatically bind an unbound socket.
- */
-
-static int inet_autobind(struct sock *sk)
-{
- /* We may need to bind the socket. */
- if (sk->num == 0)
- {
- sk->num = get_new_socknum(sk->prot, 0);
- if (sk->num == 0)
- return(-EAGAIN);
- put_sock(sk->num, sk);
- sk->dummy_th.source = ntohs(sk->num);
- }
- return 0;
-}
-
-/*
- * Move a socket into listening state.
- */
-
-static int inet_listen(struct socket *sock, int backlog)
-{
- struct sock *sk = (struct sock *) sock->data;
-
- if(inet_autobind(sk)!=0)
- return -EAGAIN;
-
- /* We might as well re use these. */
- /*
- * note that the backlog is "unsigned char", so truncate it
- * somewhere. We might as well truncate it to what everybody
- * else does..
- */
- if (backlog > 5)
- backlog = 5;
- sk->max_ack_backlog = backlog;
- if (sk->state != TCP_LISTEN)
- {
- sk->ack_backlog = 0;
- sk->state = TCP_LISTEN;
- }
- return(0);
-}
-
-/*
- * Default callbacks for user INET sockets. These just wake up
- * the user owning the socket.
- */
-
-static void def_callback1(struct sock *sk)
-{
- if(!sk->dead)
- wake_up_interruptible(sk->sleep);
-}
-
-static void def_callback2(struct sock *sk,int len)
-{
- if(!sk->dead)
- {
- wake_up_interruptible(sk->sleep);
- sock_wake_async(sk->socket, 1);
- }
-}
-
-static void def_callback3(struct sock *sk)
-{
- if(!sk->dead)
- {
- wake_up_interruptible(sk->sleep);
- sock_wake_async(sk->socket, 2);
- }
-}
-
-/*
- * Create an inet socket.
- *
- * FIXME: Gcc would generate much better code if we set the parameters
- * up in in-memory structure order. Gcc68K even more so
- */
-
-static int inet_create(struct socket *sock, int protocol)
-{
- struct sock *sk;
- struct proto *prot;
- int err;
-
- sk = (struct sock *) kmalloc(sizeof(*sk), GFP_KERNEL);
- if (sk == NULL)
- return(-ENOBUFS);
- sk->num = 0;
- sk->reuse = 0;
- switch(sock->type)
- {
- case SOCK_STREAM:
- case SOCK_SEQPACKET:
- if (protocol && protocol != IPPROTO_TCP)
- {
- kfree_s((void *)sk, sizeof(*sk));
- return(-EPROTONOSUPPORT);
- }
- protocol = IPPROTO_TCP;
- sk->no_check = TCP_NO_CHECK;
- prot = &tcp_prot;
- break;
-
- case SOCK_DGRAM:
- if (protocol && protocol != IPPROTO_UDP)
- {
- kfree_s((void *)sk, sizeof(*sk));
- return(-EPROTONOSUPPORT);
- }
- protocol = IPPROTO_UDP;
- sk->no_check = UDP_NO_CHECK;
- prot=&udp_prot;
- break;
-
- case SOCK_RAW:
- if (!suser())
- {
- kfree_s((void *)sk, sizeof(*sk));
- return(-EPERM);
- }
- if (!protocol)
- {
- kfree_s((void *)sk, sizeof(*sk));
- return(-EPROTONOSUPPORT);
- }
- prot = &raw_prot;
- sk->reuse = 1;
- sk->no_check = 0; /*
- * Doesn't matter no checksum is
- * performed anyway.
- */
- sk->num = protocol;
- break;
-
-#ifndef _HURD_
- case SOCK_PACKET:
- if (!suser())
- {
- kfree_s((void *)sk, sizeof(*sk));
- return(-EPERM);
- }
- if (!protocol)
- {
- kfree_s((void *)sk, sizeof(*sk));
- return(-EPROTONOSUPPORT);
- }
- prot = &packet_prot;
- sk->reuse = 1;
- sk->no_check = 0; /* Doesn't matter no checksum is
- * performed anyway.
- */
- sk->num = protocol;
- break;
-#endif
-
- default:
- kfree_s((void *)sk, sizeof(*sk));
- return(-ESOCKTNOSUPPORT);
- }
- sk->socket = sock;
-#ifdef CONFIG_TCP_NAGLE_OFF
- sk->nonagle = 1;
-#else
- sk->nonagle = 0;
-#endif
- sk->type = sock->type;
- sk->stamp.tv_sec=0;
- sk->protocol = protocol;
- sk->wmem_alloc = 0;
- sk->rmem_alloc = 0;
- sk->sndbuf = SK_WMEM_MAX;
- sk->rcvbuf = SK_RMEM_MAX;
- sk->pair = NULL;
- sk->opt = NULL;
- sk->write_seq = 0;
- sk->acked_seq = 0;
- sk->copied_seq = 0;
- sk->fin_seq = 0;
- sk->urg_seq = 0;
- sk->urg_data = 0;
- sk->proc = 0;
- sk->rtt = 0; /*TCP_WRITE_TIME << 3;*/
- sk->rto = TCP_TIMEOUT_INIT; /*TCP_WRITE_TIME*/
- sk->mdev = 0;
- sk->backoff = 0;
- sk->packets_out = 0;
- sk->cong_window = 1; /* start with only sending one packet at a time. */
- sk->cong_count = 0;
- sk->ssthresh = 0;
- sk->max_window = 0;
- sk->urginline = 0;
- sk->intr = 0;
- sk->linger = 0;
- sk->destroy = 0;
- sk->priority = 1;
- sk->shutdown = 0;
- sk->keepopen = 0;
- sk->zapped = 0;
- sk->done = 0;
- sk->ack_backlog = 0;
- sk->window = 0;
- sk->bytes_rcv = 0;
- sk->state = TCP_CLOSE;
- sk->dead = 0;
- sk->ack_timed = 0;
- sk->partial = NULL;
- sk->user_mss = 0;
- sk->debug = 0;
-
- /* this is how many unacked bytes we will accept for this socket. */
- sk->max_unacked = 2048; /* needs to be at most 2 full packets. */
-
- /* how many packets we should send before forcing an ack.
- if this is set to zero it is the same as sk->delay_acks = 0 */
- sk->max_ack_backlog = 0;
- sk->inuse = 0;
- sk->delay_acks = 0;
- skb_queue_head_init(&sk->write_queue);
- skb_queue_head_init(&sk->receive_queue);
- sk->mtu = 576;
- sk->prot = prot;
- sk->sleep = sock->wait;
- sk->daddr = 0;
- sk->saddr = 0 /* ip_my_addr() */;
- sk->err = 0;
- sk->next = NULL;
- sk->pair = NULL;
- sk->send_tail = NULL;
- sk->send_head = NULL;
- sk->timeout = 0;
- sk->broadcast = 0;
- sk->localroute = 0;
- init_timer(&sk->timer);
- init_timer(&sk->retransmit_timer);
- sk->timer.data = (unsigned long)sk;
- sk->timer.function = &net_timer;
- skb_queue_head_init(&sk->back_log);
- sk->blog = 0;
- sock->data =(void *) sk;
- sk->dummy_th.doff = sizeof(sk->dummy_th)/4;
- sk->dummy_th.res1=0;
- sk->dummy_th.res2=0;
- sk->dummy_th.urg_ptr = 0;
- sk->dummy_th.fin = 0;
- sk->dummy_th.syn = 0;
- sk->dummy_th.rst = 0;
- sk->dummy_th.psh = 0;
- sk->dummy_th.ack = 0;
- sk->dummy_th.urg = 0;
- sk->dummy_th.dest = 0;
- sk->ip_tos=0;
- sk->ip_ttl=64;
-#ifdef CONFIG_IP_MULTICAST
- sk->ip_mc_loop=1;
- sk->ip_mc_ttl=1;
- *sk->ip_mc_name=0;
- sk->ip_mc_list=NULL;
-#endif
-
- sk->state_change = def_callback1;
- sk->data_ready = def_callback2;
- sk->write_space = def_callback3;
- sk->error_report = def_callback1;
-
- if (sk->num)
- {
- /*
- * It assumes that any protocol which allows
- * the user to assign a number at socket
- * creation time automatically
- * shares.
- */
- put_sock(sk->num, sk);
- sk->dummy_th.source = ntohs(sk->num);
- }
-
- if (sk->prot->init)
- {
- err = sk->prot->init(sk);
- if (err != 0)
- {
- destroy_sock(sk);
- return(err);
- }
- }
- return(0);
-}
-
-
-/*
- * Duplicate a socket.
- */
-
-static int inet_dup(struct socket *newsock, struct socket *oldsock)
-{
- return(inet_create(newsock,((struct sock *)(oldsock->data))->protocol));
-}
-
-/*
- * Return 1 if we still have things to send in our buffers.
- */
-static inline int closing(struct sock * sk)
-{
- switch (sk->state) {
- case TCP_FIN_WAIT1:
- case TCP_CLOSING:
- case TCP_LAST_ACK:
- return 1;
- }
- return 0;
-}
-
-
-/*
- * The peer socket should always be NULL (or else). When we call this
- * function we are destroying the object and from then on nobody
- * should refer to it.
- */
-
-static int inet_release(struct socket *sock, struct socket *peer)
-{
- struct sock *sk = (struct sock *) sock->data;
- if (sk == NULL)
- return(0);
-
- sk->state_change(sk);
-
- /* Start closing the connection. This may take a while. */
-
-#ifdef CONFIG_IP_MULTICAST
- /* Applications forget to leave groups before exiting */
- ip_mc_drop_socket(sk);
-#endif
- /*
- * If linger is set, we don't return until the close
- * is complete. Other wise we return immediately. The
- * actually closing is done the same either way.
- *
- * If the close is due to the process exiting, we never
- * linger..
- */
-
- if (sk->linger == 0 || (current->flags & PF_EXITING))
- {
- sk->prot->close(sk,0);
- sk->dead = 1;
- }
- else
- {
- sk->prot->close(sk, 0);
- cli();
- if (sk->lingertime)
- current->timeout = jiffies + HZ*sk->lingertime;
- while(closing(sk) && current->timeout>0)
- {
- interruptible_sleep_on(sk->sleep);
- if (current->signal & ~current->blocked)
- {
- break;
-#if 0
- /* not working now - closes can't be restarted */
- sti();
- current->timeout=0;
- return(-ERESTARTSYS);
-#endif
- }
- }
- current->timeout=0;
- sti();
- sk->dead = 1;
- }
- sk->inuse = 1;
-
- /* This will destroy it. */
- release_sock(sk);
- sock->data = NULL;
- sk->socket = NULL;
- return(0);
-}
-
-
-/* this needs to be changed to disallow
- the rebinding of sockets. What error
- should it return? */
-
-static int inet_bind(struct socket *sock, struct sockaddr *uaddr,
- int addr_len)
-{
- struct sockaddr_in *addr=(struct sockaddr_in *)uaddr;
- struct sock *sk=(struct sock *)sock->data, *sk2;
- unsigned short snum = 0 /* Stoopid compiler.. this IS ok */;
- int chk_addr_ret;
-
- /* check this error. */
- if (sk->state != TCP_CLOSE)
- return(-EIO);
- if(addr_len<sizeof(struct sockaddr_in))
- return -EINVAL;
-
- if(sock->type != SOCK_RAW)
- {
- if (sk->num != 0)
- return(-EINVAL);
-
- snum = ntohs(addr->sin_port);
-
- /*
- * We can't just leave the socket bound wherever it is, it might
- * be bound to a privileged port. However, since there seems to
- * be a bug here, we will leave it if the port is not privileged.
- */
- if (snum == 0)
- {
- snum = get_new_socknum(sk->prot, 0);
- }
- if (snum < PROT_SOCK && !suser())
- return(-EACCES);
- }
-
- chk_addr_ret = ip_chk_addr(addr->sin_addr.s_addr);
- if (addr->sin_addr.s_addr != 0 && chk_addr_ret != IS_MYADDR && chk_addr_ret != IS_MULTICAST)
- return(-EADDRNOTAVAIL); /* Source address MUST be ours! */
-
- if (chk_addr_ret || addr->sin_addr.s_addr == 0)
- sk->saddr = addr->sin_addr.s_addr;
-
- if(sock->type != SOCK_RAW)
- {
- /* Make sure we are allowed to bind here. */
- cli();
- for(sk2 = sk->prot->sock_array[snum & (SOCK_ARRAY_SIZE -1)];
- sk2 != NULL; sk2 = sk2->next)
- {
- /* should be below! */
- if (sk2->num != snum)
- continue;
- if (!sk->reuse)
- {
- sti();
- return(-EADDRINUSE);
- }
-
- if (sk2->num != snum)
- continue; /* more than one */
- if (sk2->saddr != sk->saddr)
- continue; /* socket per slot ! -FB */
- if (!sk2->reuse || sk2->state==TCP_LISTEN)
- {
- sti();
- return(-EADDRINUSE);
- }
- }
- sti();
-
- remove_sock(sk);
- put_sock(snum, sk);
- sk->dummy_th.source = ntohs(sk->num);
- sk->daddr = 0;
- sk->dummy_th.dest = 0;
- }
- return(0);
-}
-
-/*
- * Handle sk->err properly. The cli/sti matter.
- */
-
-static int inet_error(struct sock *sk)
-{
- unsigned long flags;
- int err;
- save_flags(flags);
- cli();
- err=sk->err;
- sk->err=0;
- restore_flags(flags);
- return -err;
-}
-
-/*
- * Connect to a remote host. There is regrettably still a little
- * TCP 'magic' in here.
- */
-
-static int inet_connect(struct socket *sock, struct sockaddr * uaddr,
- int addr_len, int flags)
-{
- struct sock *sk=(struct sock *)sock->data;
- int err;
- sock->conn = NULL;
-
- if (sock->state == SS_CONNECTING && tcp_connected(sk->state))
- {
- sock->state = SS_CONNECTED;
- /* Connection completing after a connect/EINPROGRESS/select/connect */
- return 0; /* Rock and roll */
- }
-
- if (sock->state == SS_CONNECTING && sk->protocol == IPPROTO_TCP && (flags & O_NONBLOCK))
- return -EALREADY; /* Connecting is currently in progress */
-
- if (sock->state != SS_CONNECTING)
- {
- /* We may need to bind the socket. */
- if(inet_autobind(sk)!=0)
- return(-EAGAIN);
- if (sk->prot->connect == NULL)
- return(-EOPNOTSUPP);
- err = sk->prot->connect(sk, (struct sockaddr_in *)uaddr, addr_len);
- if (err < 0)
- return(err);
- sock->state = SS_CONNECTING;
- }
-
- if (sk->state > TCP_FIN_WAIT2 && sock->state==SS_CONNECTING)
- {
- sock->state=SS_UNCONNECTED;
- cli();
- err=sk->err;
- sk->err=0;
- sti();
- return -err;
- }
-
- if (sk->state != TCP_ESTABLISHED &&(flags & O_NONBLOCK))
- return(-EINPROGRESS);
-
- cli(); /* avoid the race condition */
- while(sk->state == TCP_SYN_SENT || sk->state == TCP_SYN_RECV)
- {
- interruptible_sleep_on(sk->sleep);
- if (current->signal & ~current->blocked)
- {
- sti();
- return(-ERESTARTSYS);
- }
- /* This fixes a nasty in the tcp/ip code. There is a hideous hassle with
- icmp error packets wanting to close a tcp or udp socket. */
- if(sk->err && sk->protocol == IPPROTO_TCP)
- {
- sti();
- sock->state = SS_UNCONNECTED;
- err = -sk->err;
- sk->err=0;
- return err; /* set by tcp_err() */
- }
- }
- sti();
- sock->state = SS_CONNECTED;
-
- if (sk->state != TCP_ESTABLISHED && sk->err)
- {
- sock->state = SS_UNCONNECTED;
- err=sk->err;
- sk->err=0;
- return(-err);
- }
- return(0);
-}
-
-
-static int inet_socketpair(struct socket *sock1, struct socket *sock2)
-{
- return(-EOPNOTSUPP);
-}
-
-
-/*
- * Accept a pending connection. The TCP layer now gives BSD semantics.
- */
-
-static int inet_accept(struct socket *sock, struct socket *newsock, int flags)
-{
- struct sock *sk1, *sk2;
- int err;
-
- sk1 = (struct sock *) sock->data;
-
- /*
- * We've been passed an extra socket.
- * We need to free it up because the tcp module creates
- * its own when it accepts one.
- */
- if (newsock->data)
- {
- struct sock *sk=(struct sock *)newsock->data;
- newsock->data=NULL;
- sk->dead = 1;
- destroy_sock(sk);
- }
-
- if (sk1->prot->accept == NULL)
- return(-EOPNOTSUPP);
-
- /* Restore the state if we have been interrupted, and then returned. */
- if (sk1->pair != NULL )
- {
- sk2 = sk1->pair;
- sk1->pair = NULL;
- }
- else
- {
- sk2 = sk1->prot->accept(sk1,flags);
- if (sk2 == NULL)
- {
- if (sk1->err <= 0)
- printk("Warning sock.c:sk1->err <= 0. Returning non-error.\n");
- err=sk1->err;
- sk1->err=0;
- return(-err);
- }
- }
- newsock->data = (void *)sk2;
- sk2->sleep = newsock->wait;
- sk2->socket = newsock;
- newsock->conn = NULL;
- if (flags & O_NONBLOCK)
- return(0);
-
- cli(); /* avoid the race. */
- while(sk2->state == TCP_SYN_RECV)
- {
- interruptible_sleep_on(sk2->sleep);
- if (current->signal & ~current->blocked)
- {
- sti();
- sk1->pair = sk2;
- sk2->sleep = NULL;
- sk2->socket=NULL;
- newsock->data = NULL;
- return(-ERESTARTSYS);
- }
- }
- sti();
-
- if (sk2->state != TCP_ESTABLISHED && sk2->err > 0)
- {
- err = -sk2->err;
- sk2->err=0;
- sk2->dead=1; /* ANK */
- destroy_sock(sk2);
- newsock->data = NULL;
- return(err);
- }
- newsock->state = SS_CONNECTED;
- return(0);
-}
-
-
-/*
- * This does both peername and sockname.
- */
-
-static int inet_getname(struct socket *sock, struct sockaddr *uaddr,
- int *uaddr_len, int peer)
-{
- struct sockaddr_in *sin=(struct sockaddr_in *)uaddr;
- struct sock *sk;
-
- sin->sin_family = AF_INET;
- sk = (struct sock *) sock->data;
- if (peer)
- {
- if (!tcp_connected(sk->state))
- return(-ENOTCONN);
- sin->sin_port = sk->dummy_th.dest;
- sin->sin_addr.s_addr = sk->daddr;
- }
- else
- {
- sin->sin_port = sk->dummy_th.source;
- if (sk->saddr == 0)
- sin->sin_addr.s_addr = ip_my_addr();
- else
- sin->sin_addr.s_addr = sk->saddr;
- }
- *uaddr_len = sizeof(*sin);
- return(0);
-}
-
-
-/*
- * The assorted BSD I/O operations
- */
-
-static int inet_recvfrom(struct socket *sock, void *ubuf, int size, int noblock,
- unsigned flags, struct sockaddr *sin, int *addr_len )
-{
- struct sock *sk = (struct sock *) sock->data;
-
- if (sk->prot->recvfrom == NULL)
- return(-EOPNOTSUPP);
- if(sk->err)
- return inet_error(sk);
- /* We may need to bind the socket. */
- if(inet_autobind(sk)!=0)
- return(-EAGAIN);
- return(sk->prot->recvfrom(sk, (unsigned char *) ubuf, size, noblock, flags,
- (struct sockaddr_in*)sin, addr_len));
-}
-
-
-static int inet_recv(struct socket *sock, void *ubuf, int size, int noblock,
- unsigned flags)
-{
- /* BSD explicitly states these are the same - so we do it this way to be sure */
- return inet_recvfrom(sock,ubuf,size,noblock,flags,NULL,NULL);
-}
-
-static int inet_read(struct socket *sock, char *ubuf, int size, int noblock)
-{
- struct sock *sk = (struct sock *) sock->data;
-
- if(sk->err)
- return inet_error(sk);
- /* We may need to bind the socket. */
- if(inet_autobind(sk))
- return(-EAGAIN);
- return(sk->prot->read(sk, (unsigned char *) ubuf, size, noblock, 0));
-}
-
-static int inet_send(struct socket *sock, void *ubuf, int size, int noblock,
- unsigned flags)
-{
- struct sock *sk = (struct sock *) sock->data;
- if (sk->shutdown & SEND_SHUTDOWN)
- {
- send_sig(SIGPIPE, current, 1);
- return(-EPIPE);
- }
- if(sk->err)
- return inet_error(sk);
- /* We may need to bind the socket. */
- if(inet_autobind(sk)!=0)
- return(-EAGAIN);
- return(sk->prot->write(sk, (unsigned char *) ubuf, size, noblock, flags));
-}
-
-static int inet_write(struct socket *sock, char *ubuf, int size, int noblock)
-{
- return inet_send(sock,ubuf,size,noblock,0);
-}
-
-static int inet_sendto(struct socket *sock, void *ubuf, int size, int noblock,
- unsigned flags, struct sockaddr *sin, int addr_len)
-{
- struct sock *sk = (struct sock *) sock->data;
- if (sk->shutdown & SEND_SHUTDOWN)
- {
- send_sig(SIGPIPE, current, 1);
- return(-EPIPE);
- }
- if (sk->prot->sendto == NULL)
- return(-EOPNOTSUPP);
- if(sk->err)
- return inet_error(sk);
- /* We may need to bind the socket. */
- if(inet_autobind(sk)!=0)
- return -EAGAIN;
- return(sk->prot->sendto(sk, (unsigned char *) ubuf, size, noblock, flags,
- (struct sockaddr_in *)sin, addr_len));
-}
-
-
-static int inet_shutdown(struct socket *sock, int how)
-{
- struct sock *sk=(struct sock*)sock->data;
-
- /*
- * This should really check to make sure
- * the socket is a TCP socket. (WHY AC...)
- */
- how++; /* maps 0->1 has the advantage of making bit 1 rcvs and
- 1->2 bit 2 snds.
- 2->3 */
- if ((how & ~SHUTDOWN_MASK) || how==0) /* MAXINT->0 */
- return(-EINVAL);
- if (sock->state == SS_CONNECTING && sk->state == TCP_ESTABLISHED)
- sock->state = SS_CONNECTED;
- if (!tcp_connected(sk->state))
- return(-ENOTCONN);
- sk->shutdown |= how;
- if (sk->prot->shutdown)
- sk->prot->shutdown(sk, how);
- return(0);
-}
-
-
-static int inet_select(struct socket *sock, int sel_type, select_table *wait )
-{
- struct sock *sk=(struct sock *) sock->data;
- if (sk->prot->select == NULL)
- {
- return(0);
- }
- return(sk->prot->select(sk, sel_type, wait));
-}
-
-#ifndef _HURD_
-
-/*
- * ioctl() calls you can issue on an INET socket. Most of these are
- * device configuration and stuff and very rarely used. Some ioctls
- * pass on to the socket itself.
- *
- * NOTE: I like the idea of a module for the config stuff. ie ifconfig
- * loads the devconfigure module does its configuring and unloads it.
- * There's a good 20K of config code hanging around the kernel.
- */
-
-static int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
-{
- struct sock *sk=(struct sock *)sock->data;
- int err;
-
- switch(cmd)
- {
- case FIOSETOWN:
- case SIOCSPGRP:
- err=verify_area(VERIFY_READ,(int *)arg,sizeof(long));
- if(err)
- return err;
- sk->proc = get_fs_long((int *) arg);
- return(0);
- case FIOGETOWN:
- case SIOCGPGRP:
- err=verify_area(VERIFY_WRITE,(void *) arg, sizeof(long));
- if(err)
- return err;
- put_fs_long(sk->proc,(int *)arg);
- return(0);
- case SIOCGSTAMP:
- if(sk->stamp.tv_sec==0)
- return -ENOENT;
- err=verify_area(VERIFY_WRITE,(void *)arg,sizeof(struct timeval));
- if(err)
- return err;
- memcpy_tofs((void *)arg,&sk->stamp,sizeof(struct timeval));
- return 0;
- case SIOCADDRT: case SIOCADDRTOLD:
- case SIOCDELRT: case SIOCDELRTOLD:
- return(ip_rt_ioctl(cmd,(void *) arg));
- case SIOCDARP:
- case SIOCGARP:
- case SIOCSARP:
- return(arp_ioctl(cmd,(void *) arg));
-#ifdef CONFIG_INET_RARP
- case SIOCDRARP:
- case SIOCGRARP:
- case SIOCSRARP:
- return(rarp_ioctl(cmd,(void *) arg));
-#endif
- case SIOCGIFCONF:
- case SIOCGIFFLAGS:
- case SIOCSIFFLAGS:
- case SIOCGIFADDR:
- case SIOCSIFADDR:
-
-/* begin multicast support change */
- case SIOCADDMULTI:
- case SIOCDELMULTI:
-/* end multicast support change */
-
- case SIOCGIFDSTADDR:
- case SIOCSIFDSTADDR:
- case SIOCGIFBRDADDR:
- case SIOCSIFBRDADDR:
- case SIOCGIFNETMASK:
- case SIOCSIFNETMASK:
- case SIOCGIFMETRIC:
- case SIOCSIFMETRIC:
- case SIOCGIFMEM:
- case SIOCSIFMEM:
- case SIOCGIFMTU:
- case SIOCSIFMTU:
- case SIOCSIFLINK:
- case SIOCGIFHWADDR:
- case SIOCSIFHWADDR:
- case OLD_SIOCGIFHWADDR:
- case SIOCSIFMAP:
- case SIOCGIFMAP:
- case SIOCSIFSLAVE:
- case SIOCGIFSLAVE:
- return(dev_ioctl(cmd,(void *) arg));
-
- default:
- if ((cmd >= SIOCDEVPRIVATE) &&
- (cmd <= (SIOCDEVPRIVATE + 15)))
- return(dev_ioctl(cmd,(void *) arg));
-
- if (sk->prot->ioctl==NULL)
- return(-EINVAL);
- return(sk->prot->ioctl(sk, cmd, arg));
- }
- /*NOTREACHED*/
- return(0);
-
-}
-#else /* _HURD_ */
-static int inet_ioctl (struct socket *sock,
- unsigned int cm,
- unsigned long arg)
-{
- return EOPNOTSUPP;
-}
-#endif
-
-
-/*
- * This routine must find a socket given a TCP or UDP header.
- * Everything is assumed to be in net order.
- *
- * We give priority to more closely bound ports: if some socket
- * is bound to a particular foreign address, it will get the packet
- * rather than somebody listening to any address..
- */
-
-struct sock *get_sock(struct proto *prot, unsigned short num,
- unsigned long raddr,
- unsigned short rnum, unsigned long laddr)
-{
- struct sock *s;
- struct sock *result = NULL;
- int badness = -1;
- unsigned short hnum;
-
- hnum = ntohs(num);
-
- /*
- * SOCK_ARRAY_SIZE must be a power of two. This will work better
- * than a prime unless 3 or more sockets end up using the same
- * array entry. This should not be a problem because most
- * well known sockets don't overlap that much, and for
- * the other ones, we can just be careful about picking our
- * socket number when we choose an arbitrary one.
- */
-
- for(s = prot->sock_array[hnum & (SOCK_ARRAY_SIZE - 1)];
- s != NULL; s = s->next)
- {
- int score = 0;
-
- if (s->num != hnum)
- continue;
-
- if(s->dead && (s->state == TCP_CLOSE))
- continue;
- /* local address matches? */
- if (s->saddr) {
- if (s->saddr != laddr)
- continue;
- score++;
- }
- /* remote address matches? */
- if (s->daddr) {
- if (s->daddr != raddr)
- continue;
- score++;
- }
- /* remote port matches? */
- if (s->dummy_th.dest) {
- if (s->dummy_th.dest != rnum)
- continue;
- score++;
- }
- /* perfect match? */
- if (score == 3)
- return s;
- /* no, check if this is the best so far.. */
- if (score <= badness)
- continue;
- result = s;
- badness = score;
- }
- return result;
-}
-
-/*
- * Deliver a datagram to raw sockets.
- */
-
-struct sock *get_sock_raw(struct sock *sk,
- unsigned short num,
- unsigned long raddr,
- unsigned long laddr)
-{
- struct sock *s;
-
- s=sk;
-
- for(; s != NULL; s = s->next)
- {
- if (s->num != num)
- continue;
- if(s->dead && (s->state == TCP_CLOSE))
- continue;
- if(s->daddr && s->daddr!=raddr)
- continue;
- if(s->saddr && s->saddr!=laddr)
- continue;
- return(s);
- }
- return(NULL);
-}
-
-#ifdef CONFIG_IP_MULTICAST
-/*
- * Deliver a datagram to broadcast/multicast sockets.
- */
-
-struct sock *get_sock_mcast(struct sock *sk,
- unsigned short num,
- unsigned long raddr,
- unsigned short rnum, unsigned long laddr)
-{
- struct sock *s;
- unsigned short hnum;
-
- hnum = ntohs(num);
-
- /*
- * SOCK_ARRAY_SIZE must be a power of two. This will work better
- * than a prime unless 3 or more sockets end up using the same
- * array entry. This should not be a problem because most
- * well known sockets don't overlap that much, and for
- * the other ones, we can just be careful about picking our
- * socket number when we choose an arbitrary one.
- */
-
- s=sk;
-
- for(; s != NULL; s = s->next)
- {
- if (s->num != hnum)
- continue;
- if(s->dead && (s->state == TCP_CLOSE))
- continue;
- if(s->daddr && s->daddr!=raddr)
- continue;
- if (s->dummy_th.dest != rnum && s->dummy_th.dest != 0)
- continue;
- if(s->saddr && s->saddr!=laddr)
- continue;
- return(s);
- }
- return(NULL);
-}
-
-#endif
-
-static struct proto_ops inet_proto_ops = {
- AF_INET,
-
- inet_create,
- inet_dup,
- inet_release,
- inet_bind,
- inet_connect,
- inet_socketpair,
- inet_accept,
- inet_getname,
- inet_read,
- inet_write,
- inet_select,
- inet_ioctl,
- inet_listen,
- inet_send,
- inet_recv,
- inet_sendto,
- inet_recvfrom,
- inet_shutdown,
- inet_setsockopt,
- inet_getsockopt,
- inet_fcntl,
-};
-
-extern unsigned long seq_offset;
-
-/*
- * Called by socket.c on kernel startup.
- */
-
-void inet_proto_init(struct net_proto *pro)
-{
- struct inet_protocol *p;
- int i;
-
-
- printk("Swansea University Computer Society TCP/IP for NET3.019\n");
-
- /*
- * Tell SOCKET that we are alive...
- */
-
- (void) sock_register(inet_proto_ops.family, &inet_proto_ops);
-
- seq_offset = CURRENT_TIME*250;
-
- /*
- * Add all the protocols.
- */
-
- for(i = 0; i < SOCK_ARRAY_SIZE; i++)
- {
- tcp_prot.sock_array[i] = NULL;
- udp_prot.sock_array[i] = NULL;
- raw_prot.sock_array[i] = NULL;
- }
- tcp_prot.inuse = 0;
- tcp_prot.highestinuse = 0;
- udp_prot.inuse = 0;
- udp_prot.highestinuse = 0;
- raw_prot.inuse = 0;
- raw_prot.highestinuse = 0;
-
- printk("IP Protocols: ");
- for(p = inet_protocol_base; p != NULL;)
- {
- struct inet_protocol *tmp = (struct inet_protocol *) p->next;
- inet_add_protocol(p);
- printk("%s%s",p->name,tmp?", ":"\n");
- p = tmp;
- }
- /*
- * Set the ARP module up
- */
- arp_init();
- /*
- * Set the IP module up
- */
- ip_init();
-}
-