1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
|
/*
* 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.
*
* INET protocol dispatch tables.
*
* Version: @(#)protocol.c 1.0.5 05/25/93
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
*
* Fixes:
* Alan Cox : Ahah! udp icmp errors don't work because
* udp_err is never called!
* Alan Cox : Added new fields for init and ready for
* proper fragmentation (_NO_ 4K limits!)
* Richard Colella : Hang on hash collision
*
* 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 <asm/segment.h>
#include <asm/system.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/config.h>
#include <linux/socket.h>
#include <linux/in.h>
#include <linux/inet.h>
#include <linux/netdevice.h>
#include <linux/timer.h>
#include <net/ip.h>
#include <net/protocol.h>
#include <net/tcp.h>
#include <linux/skbuff.h>
#include <net/sock.h>
#include <net/icmp.h>
#include <net/udp.h>
#include <net/ipip.h>
#include <linux/igmp.h>
#ifdef CONFIG_NET_IPIP
static struct inet_protocol ipip_protocol =
{
ipip_rcv, /* IPIP handler */
NULL, /* TUNNEL error control */
0, /* next */
IPPROTO_IPIP, /* protocol ID */
0, /* copy */
NULL, /* data */
"IPIP" /* name */
};
#endif
static struct inet_protocol tcp_protocol =
{
tcp_rcv, /* TCP handler */
tcp_err, /* TCP error control */
#if defined(CONFIG_NET_IPIP)
&ipip_protocol,
#else
NULL, /* next */
#endif
IPPROTO_TCP, /* protocol ID */
0, /* copy */
NULL, /* data */
"TCP" /* name */
};
static struct inet_protocol udp_protocol =
{
udp_rcv, /* UDP handler */
udp_err, /* UDP error control */
&tcp_protocol, /* next */
IPPROTO_UDP, /* protocol ID */
0, /* copy */
NULL, /* data */
"UDP" /* name */
};
static struct inet_protocol icmp_protocol =
{
icmp_rcv, /* ICMP handler */
NULL, /* ICMP error control */
&udp_protocol, /* next */
IPPROTO_ICMP, /* protocol ID */
0, /* copy */
NULL, /* data */
"ICMP" /* name */
};
#ifndef CONFIG_IP_MULTICAST
struct inet_protocol *inet_protocol_base = &icmp_protocol;
#else
static struct inet_protocol igmp_protocol =
{
igmp_rcv, /* IGMP handler */
NULL, /* IGMP error control */
&icmp_protocol, /* next */
IPPROTO_IGMP, /* protocol ID */
0, /* copy */
NULL, /* data */
"IGMP" /* name */
};
struct inet_protocol *inet_protocol_base = &igmp_protocol;
#endif
struct inet_protocol *inet_protos[MAX_INET_PROTOS] =
{
NULL
};
/*
* Find a protocol in the protocol tables given its
* IP type.
*/
struct inet_protocol *inet_get_protocol(unsigned char prot)
{
unsigned char hash;
struct inet_protocol *p;
hash = prot & (MAX_INET_PROTOS - 1);
for (p = inet_protos[hash] ; p != NULL; p=p->next)
{
if (p->protocol == prot)
return((struct inet_protocol *) p);
}
return(NULL);
}
/*
* Add a protocol handler to the hash tables
*/
void inet_add_protocol(struct inet_protocol *prot)
{
unsigned char hash;
struct inet_protocol *p2;
hash = prot->protocol & (MAX_INET_PROTOS - 1);
prot ->next = inet_protos[hash];
inet_protos[hash] = prot;
prot->copy = 0;
/*
* Set the copy bit if we need to.
*/
p2 = (struct inet_protocol *) prot->next;
while(p2 != NULL)
{
if (p2->protocol == prot->protocol)
{
prot->copy = 1;
break;
}
p2 = (struct inet_protocol *) p2->next;
}
}
/*
* Remove a protocol from the hash tables.
*/
int inet_del_protocol(struct inet_protocol *prot)
{
struct inet_protocol *p;
struct inet_protocol *lp = NULL;
unsigned char hash;
hash = prot->protocol & (MAX_INET_PROTOS - 1);
if (prot == inet_protos[hash])
{
inet_protos[hash] = (struct inet_protocol *) inet_protos[hash]->next;
return(0);
}
p = (struct inet_protocol *) inet_protos[hash];
while(p != NULL)
{
/*
* We have to worry if the protocol being deleted is
* the last one on the list, then we may need to reset
* someone's copied bit.
*/
if (p->next != NULL && p->next == prot)
{
/*
* if we are the last one with this protocol and
* there is a previous one, reset its copy bit.
*/
if (p->copy == 0 && lp != NULL)
lp->copy = 0;
p->next = prot->next;
return(0);
}
if (p->next != NULL && p->next->protocol == prot->protocol)
lp = p;
p = (struct inet_protocol *) p->next;
}
return(-1);
}
|