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 *
19 * This program is free software; you can redistribute it and/or
20 * modify it under the terms of the GNU General Public License
21 * as published by the Free Software Foundation; either version
22 * 2 of the License, or (at your option) any later version.
23 */
24 #include <asm/segment.h>
25 #include <asm/system.h>
26 #include <linux/types.h>
27 #include <linux/kernel.h>
28 #include <linux/sched.h>
29 #include <linux/string.h>
30 #include <linux/socket.h>
31 #include <linux/in.h>
32 #include "inet.h"
33 #include "dev.h"
34 #include "ip.h"
35 #include "protocol.h"
36 #include "tcp.h"
37 #include "skbuff.h"
38 #include "sock.h"
39 #include "icmp.h"
40 #include "udp.h"
41
42
43 static struct inet_protocol tcp_protocol = {
44 tcp_rcv, /* TCP handler */
45 NULL, /* No fragment handler (and won't be for a long time) */
46 tcp_err, /* TCP error control */
47 NULL, /* next */
48 IPPROTO_TCP, /* protocol ID */
49 0, /* copy */
50 NULL, /* data */
51 "TCP" /* name */
52 };
53
54
55 static struct inet_protocol udp_protocol = {
56 udp_rcv, /* UDP handler */
57 NULL, /* Will be UDP fraglist handler */
58 udp_err, /* UDP error control */
59 &tcp_protocol, /* next */
60 IPPROTO_UDP, /* protocol ID */
61 0, /* copy */
62 NULL, /* data */
63 "UDP" /* name */
64 };
65
66
67 static struct inet_protocol icmp_protocol = {
68 icmp_rcv, /* ICMP handler */
69 NULL, /* ICMP never fragments anyway */
70 NULL, /* ICMP error control */
71 &udp_protocol, /* next */
72 IPPROTO_ICMP, /* protocol ID */
73 0, /* copy */
74 NULL, /* data */
75 "ICMP" /* name */
76 };
77
78
79 struct inet_protocol *inet_protocol_base = &icmp_protocol;
80 struct inet_protocol *inet_protos[MAX_INET_PROTOS] = {
81 NULL
82 };
83
84
85 struct inet_protocol *
86 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)
*/
87 {
88 unsigned char hash;
89 struct inet_protocol *p;
90
91 DPRINTF((DBG_PROTO, "get_protocol (%d)\n ", prot));
92 hash = prot & (MAX_INET_PROTOS - 1);
93 for (p = inet_protos[hash] ; p != NULL; p=p->next) {
94 DPRINTF((DBG_PROTO, "trying protocol %d\n", p->protocol));
95 if (p->protocol == prot) return((struct inet_protocol *) p);
96 }
97 return(NULL);
98 }
99
100
101 void
102 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)
*/
103 {
104 unsigned char hash;
105 struct inet_protocol *p2;
106
107 hash = prot->protocol & (MAX_INET_PROTOS - 1);
108 prot ->next = inet_protos[hash];
109 inet_protos[hash] = prot;
110 prot->copy = 0;
111
112 /* Set the copy bit if we need to. */
113 p2 = (struct inet_protocol *) prot->next;
114 while(p2 != NULL) {
115 if (p2->protocol == prot->protocol) {
116 prot->copy = 1;
117 break;
118 }
119 p2 = (struct inet_protocol *) prot->next;
120 }
121 }
122
123
124 int
125 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)
*/
126 {
127 struct inet_protocol *p;
128 struct inet_protocol *lp = NULL;
129 unsigned char hash;
130
131 hash = prot->protocol & (MAX_INET_PROTOS - 1);
132 if (prot == inet_protos[hash]) {
133 inet_protos[hash] = (struct inet_protocol *) inet_protos[hash]->next;
134 return(0);
135 }
136
137 p = (struct inet_protocol *) inet_protos[hash];
138 while(p != NULL) {
139 /*
140 * We have to worry if the protocol being deleted is
141 * the last one on the list, then we may need to reset
142 * someones copied bit.
143 */
144 if (p->next != NULL && p->next == prot) {
145 /*
146 * if we are the last one with this protocol and
147 * there is a previous one, reset its copy bit.
148 */
149 if (p->copy == 0 && lp != NULL) lp->copy = 0;
150 p->next = prot->next;
151 return(0);
152 }
153
154 if (p->next != NULL && p->next->protocol == prot->protocol) {
155 lp = p;
156 }
157
158 p = (struct inet_protocol *) p->next;
159 }
160 return(-1);
161 }