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