make oldconfig will rebuild these...
[linux-2.4.21-pre4.git] / drivers / net / loopback.c
1 /*
2  * INET         An implementation of the TCP/IP protocol suite for the LINUX
3  *              operating system.  INET is implemented using the  BSD Socket
4  *              interface as the means of communication with the user level.
5  *
6  *              Pseudo-driver for the loopback interface.
7  *
8  * Version:     @(#)loopback.c  1.0.4b  08/16/93
9  *
10  * Authors:     Ross Biro, <bir7@leland.Stanford.Edu>
11  *              Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
12  *              Donald Becker, <becker@scyld.com>
13  *
14  *              Alan Cox        :       Fixed oddments for NET3.014
15  *              Alan Cox        :       Rejig for NET3.029 snap #3
16  *              Alan Cox        :       Fixed NET3.029 bugs and sped up
17  *              Larry McVoy     :       Tiny tweak to double performance
18  *              Alan Cox        :       Backed out LMV's tweak - the linux mm
19  *                                      can't take it...
20  *              Michael Griffith:       Don't bother computing the checksums
21  *                                      on packets received on the loopback
22  *                                      interface.
23  *              Alexey Kuznetsov:       Potential hang under some extreme
24  *                                      cases removed.
25  *
26  *              This program is free software; you can redistribute it and/or
27  *              modify it under the terms of the GNU General Public License
28  *              as published by the Free Software Foundation; either version
29  *              2 of the License, or (at your option) any later version.
30  */
31 #include <linux/kernel.h>
32 #include <linux/sched.h>
33 #include <linux/interrupt.h>
34 #include <linux/fs.h>
35 #include <linux/types.h>
36 #include <linux/string.h>
37 #include <linux/socket.h>
38 #include <linux/errno.h>
39 #include <linux/fcntl.h>
40 #include <linux/in.h>
41 #include <linux/init.h>
42
43 #include <asm/system.h>
44 #include <asm/uaccess.h>
45 #include <asm/io.h>
46
47 #include <linux/inet.h>
48 #include <linux/netdevice.h>
49 #include <linux/etherdevice.h>
50 #include <linux/skbuff.h>
51 #include <net/sock.h>
52 #include <linux/if_ether.h>     /* For the statistics structure. */
53 #include <linux/if_arp.h>       /* For ARPHRD_ETHER */
54
55 #define LOOPBACK_OVERHEAD (128 + MAX_HEADER + 16 + 16)
56
57 /*
58  * The higher levels take care of making this non-reentrant (it's
59  * called with bh's disabled).
60  */
61 static int loopback_xmit(struct sk_buff *skb, struct net_device *dev)
62 {
63         struct net_device_stats *stats = (struct net_device_stats *)dev->priv;
64
65         /*
66          *      Optimise so buffers with skb->free=1 are not copied but
67          *      instead are lobbed from tx queue to rx queue 
68          */
69
70         if(atomic_read(&skb->users) != 1)
71         {
72                 struct sk_buff *skb2=skb;
73                 skb=skb_clone(skb, GFP_ATOMIC);         /* Clone the buffer */
74                 if(skb==NULL) {
75                         kfree_skb(skb2);
76                         return 0;
77                 }
78                 kfree_skb(skb2);
79         }
80         else
81                 skb_orphan(skb);
82
83         skb->protocol=eth_type_trans(skb,dev);
84         skb->dev=dev;
85 #ifndef LOOPBACK_MUST_CHECKSUM
86         skb->ip_summed = CHECKSUM_UNNECESSARY;
87 #endif
88
89         dev->last_rx = jiffies;
90         stats->rx_bytes+=skb->len;
91         stats->tx_bytes+=skb->len;
92         stats->rx_packets++;
93         stats->tx_packets++;
94
95         netif_rx(skb);
96
97         return(0);
98 }
99
100 static struct net_device_stats *get_stats(struct net_device *dev)
101 {
102         return (struct net_device_stats *)dev->priv;
103 }
104
105 /* Initialize the rest of the LOOPBACK device. */
106 int __init loopback_init(struct net_device *dev)
107 {
108         dev->mtu                = (16 * 1024) + 20 + 20 + 12;
109         dev->hard_start_xmit    = loopback_xmit;
110         dev->hard_header        = eth_header;
111         dev->hard_header_cache  = eth_header_cache;
112         dev->header_cache_update= eth_header_cache_update;
113         dev->hard_header_len    = ETH_HLEN;             /* 14                   */
114         dev->addr_len           = ETH_ALEN;             /* 6                    */
115         dev->tx_queue_len       = 0;
116         dev->type               = ARPHRD_LOOPBACK;      /* 0x0001               */
117         dev->rebuild_header     = eth_rebuild_header;
118         dev->flags              = IFF_LOOPBACK;
119         dev->features           = NETIF_F_SG|NETIF_F_FRAGLIST|NETIF_F_NO_CSUM|NETIF_F_HIGHDMA;
120         dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL);
121         if (dev->priv == NULL)
122                         return -ENOMEM;
123         memset(dev->priv, 0, sizeof(struct net_device_stats));
124         dev->get_stats = get_stats;
125
126         /*
127          *      Fill in the generic fields of the device structure. 
128          */
129    
130         return(0);
131 };