1 /*
2 ip.c
3 Copyright 1995 Philip Homburg
4 */
5 #include "inet.h"
6 #include "buf.h"
7 #include "event.h"
8 #include "type.h"
9 #include "arp.h"
10 #include "assert.h"
11 #include "clock.h"
12 #include "eth.h"
13 #include "icmp.h"
14 #include "icmp_lib.h"
15 #include "io.h"
16 #include "ip.h"
17 #include "ip_int.h"
18 #include "ipr.h"
19 #include "sr.h"
20 THIS_FILE
21 FORWARD void ip_close ARGS(( int fd ));
22 FORWARD int ip_cancel ARGS(( int fd, int which_operation ));
23 FORWARD void ip_buffree ARGS(( int priority ));
24 #ifdef BUF_CONSISTENCY_CHECK
25 FORWARD void ip_bufcheck ARGS(( void ));
26 #endif
27 FORWARD void ip_bad_callback ARGS(( struct ip_port *ip_port ));
ip_port_table is the port table for the ip interface.
The ip_port_table is the data structure which stores information for each network
interface. There is a 1-1 correspondence between the network interfaces and the
elements of the ip_port_table. Each network interface in ip_port_table should
belong to a different network.
28 PUBLIC ip_port_t ip_port_table[IP_PORT_NR];
The ip_port is defined in inet/generic/ip_int.h.
ip_minor: minor device number of ip device.
ip_ipaddr: ip address of the associated network interface.
ip_netmask: net mask of the ip address. The net mask of the ip address is determined
from the class type (class A, B, C, D, E) of the ip address. Which class type determines
which net mask if defined in the proper RFC.
ip_subnetmask: subnet mask of the ip address. Subnet mask define the subnet which the network interface belong to.
ip_frame_id: used as the datagram id number for an outgoing datagram.
ip_mss: maximum segment size - maximum packet size of packet.
ip_dev_main: set by network interface to the appropriate function which does some initialization and other things.
ip_dev_set_ipaddr: pointer to a function which is called when the ip address is set. If any calls are waiting for
an ip address the calls are returned.
ip_dev_send: pointer to a function which is called when writing a packet to be sent.
ip_loopb_head:
ip_loopb_event:
ip_proto_any: head of linked list of fds which receive messages on any protocol.
ip_proto: hash table of fds which receive messages on a particular port.
ip_fd_table is the fd table for the ip interface.
29 PUBLIC ip_fd_t ip_fd_table[IP_FD_NR];
The ip_ass_table is used to reassemble fragmented packets which are parts of the same datagram.
30 PUBLIC ip_ass_t ip_ass_table[IP_ASS_NR];
The ip_ass_t is defined in inet/generic/ip_int.h.
ia_frags: points to a packet which is the head of linked list of packets. The linked list is
a list of packets which are part of the same datagram.
ia_min_ttl: time to live for datagram. If (ia_first_time + ia_min_ttl) < (time when every
packet for the packet has arrived - and hence can be reassembled) the datagram is dumped.
ia_port: pointer to port in ip_port_table.
ia_first_time: initialized to 0. Time when first packet for the datagram arrived.
ia_srcaddr: source ip address for packet(s) of datagram.
ia_dstaddr: destination ip address for packet(s) of datagram.
ia_proto: protocol of packet(s) of datagram.
ia_id: datagram id number for datagram. Every packet for the same datagram should have the same datagram id number.
ip_init() is called in inet.c to perform initialization.
31 PUBLIC void ip_init()
32 {
33 int i, j, result;
34 ip_ass_t *ip_ass;
35 ip_fd_t *ip_fd;
36 ip_port_t *ip_port;
37 assert (BUF_S >= sizeof(struct nwio_ethopt));
38 assert (BUF_S >= IP_MAX_HDR_SIZE + ETH_HDR_SIZE);
39 assert (BUF_S >= sizeof(nwio_ipopt_t));
40 assert (BUF_S >= sizeof(nwio_route_t));
41 #if ZERO
42 for (i=0, ip_ass= ip_ass_table; i<IP_ASS_NR; i++, ip_ass++)
43 {
44 ip_ass->ia_frags= 0;
45 ip_ass->ia_first_time= 0;
46 ip_ass->ia_port= 0;
47 }
48 for (i=0, ip_fd= ip_fd_table; i<IP_FD_NR; i++, ip_fd++)
49 {
50 ip_fd->if_flags= IFF_EMPTY;
51 ip_fd->if_rdbuf_head= 0;
52 }
53 #endif
54 for (i=0, ip_port= ip_port_table; i<IP_PORT_NR; i++, ip_port++)
55 {
56 #if ZERO
57 ip_port->ip_flags= IPF_EMPTY;
58 #endif
59 ip_port->ip_dev_main= (ip_dev_t)ip_bad_callback;
60 ip_port->ip_dev_set_ipaddr= (ip_dev_t)ip_bad_callback;
61 ip_port->ip_dev_send= (ip_dev_send_t)ip_bad_callback;
62 ip_port->ip_minor= ip_conf[i].ic_minor;
63 ip_port->ip_dl_type= ip_conf[i].ic_devtype;
64 ip_port->ip_mss= IP_DEF_MSS;
65 switch(ip_port->ip_dl_type)
66 {
IPDL_ETH = Ethernet interface.
67 case IPDL_ETH:
68 ip_port->ip_dl.dl_eth.de_port= ip_conf[i].ic_port;
Calls the function ipeth_init to initialize the functions for the array of ip_port_t
structures (the table is called ip_port) which it uses to send messages and set ip addresses
ie ip_dev_set_ipaddr, ip_dev_send, ip_dev_main.
69 result= ipeth_init(ip_port);
70 if (result == -1)
71 continue;
72 assert(result == NW_OK);
73 break;
74 #if ENABLE_PSIP
IPDL_PSIP = Pseudo-IP interface.
75 case IPDL_PSIP:
76 ip_port->ip_dl.dl_ps.ps_port= ip_conf[i].ic_port;
Calls the function ipps_init to initialize the functions for the array of ip_port_t
structures (the table is called ip_port) which it uses to send messages and set ip addresses
ie ip_dev_set_ipaddr, ip_dev_send, ip_dev_main.
77 result= ipps_init(ip_port);
78 if (result == -1)
79 continue;
80 assert(result == NW_OK);
81 break;
82 #endif
83 default:
84 ip_panic(( "unknown ip_dl_type %d",
85 ip_port->ip_dl_type ));
86 break;
87 }
88 #if ZERO
89 ip_port->ip_loopb_head= NULL;
90 ip_port->ip_loopb_tail= NULL;
91 ev_init(&ip_port->ip_loopb_event);
92 #endif
93 ip_port->ip_flags |= IPF_CONFIGURED;
94 #if ZERO
95 ip_port->ip_proto_any= NULL;
96 for (j= 0; j<IP_PROTO_HASH_NR; j++)
97 ip_port->ip_proto[j]= NULL;
98 #endif
99 }
100 #ifndef BUF_CONSISTENCY_CHECK
101 bf_logon(ip_buffree);
102 #else
103 bf_logon(ip_buffree, ip_bufcheck);
104 #endif
105 icmp_init();
106 ipr_init();
107 for (i=0, ip_port= ip_port_table; i<IP_PORT_NR; i++, ip_port++)
108 {
109 if (!(ip_port->ip_flags & IPF_CONFIGURED))
110 continue;
ip_init initializes the ip_frame_id field with the current time. The ip_frame_id is
used as the datagram id number for the outgoing datagram.
111 ip_port->ip_frame_id= (u16_t)get_time();
ip_init then calls sr_add_minor to so that the user call ip directly in a system call
by using ip’s minor device number.
112 result= sr_add_minor(ip_port->ip_minor,
113 ip_port-ip_port_table, ip_open, ip_close,
114 ip_read, ip_write, ip_ioctl, ip_cancel);
115 assert (result>=0);
116 (*ip_port->ip_dev_main)(ip_port);
117 }
118 }
ip_cancel() cancels a system call on a IP device.
119 PRIVATE int ip_cancel (fd, which_operation)
120 int fd;
121 int which_operation;
122 {
123 ip_fd_t *ip_fd;
124 acc_t *repl_res;
125 int result;
126 ip_fd= &ip_fd_table[fd];
127 switch (which_operation)
128 {
129 case SR_CANCEL_IOCTL:
130 assert (ip_fd->if_flags & IFF_GIPCONF_IP);
131 ip_fd->if_flags &= ~IFF_GIPCONF_IP;
132 repl_res= (*ip_fd->if_get_userdata)(ip_fd->if_srfd,
133 (size_t)EINTR, (size_t)0, TRUE);
134 assert (!repl_res);
135 break;
136 case SR_CANCEL_READ:
137 assert (ip_fd->if_flags & IFF_READ_IP);
138 ip_fd->if_flags &= ~IFF_READ_IP;
139 result= (*ip_fd->if_put_userdata)(ip_fd->if_srfd,
140 (size_t)EINTR, (acc_t *)0, FALSE);
141 assert (!result);
142 break;
143 #if 0
144 case SR_CANCEL_WRITE:
145 assert(0);
146 assert (ip_fd->if_flags & IFF_WRITE_MASK);
147 ip_fd->if_flags &= ~IFF_WRITE_MASK;
148 repl_res= (*ip_fd->if_get_userdata)(ip_fd->if_srfd,
149 (size_t)EINTR, (size_t)0, FALSE);
150 assert (!repl_res);
151 break;
152 #endif
153 default:
154 ip_panic(( "unknown cancel request" ));
155 break;
156 }
157 return NW_OK;
158 }
ip_open() implements the open system call on a IP device.
ip_open() is used in 2 differene ways: 1) by sr.c to get protocol specific information
for the ip channel if the ip device was opened directly by the user ie (eg by calling
Open(“/dev/ip”, whatever_mode_you_want) 2) by another protocol using the ip protocol
(eg udp) calling it eg ip_open being called in udp_main by the udp protocol. ip_open
returns an index in to the ip fd table array for the ip channel.
159 PUBLIC int ip_open (port, srfd, get_userdata, put_userdata, put_pkt)
160 int port;
161 int srfd;
162 get_userdata_t get_userdata;
163 put_userdata_t put_userdata;
164 put_pkt_t put_pkt;
165 {
166 int i;
167 ip_fd_t *ip_fd;
168 ip_port_t *ip_port;
169 ip_port= &ip_port_table[port];
170 if (!(ip_port->ip_flags & IPF_CONFIGURED))
171 return ENXIO;
172 for (i=0; i<IP_FD_NR && (ip_fd_table[i].if_flags & IFF_INUSE);
173 i++);
174 if (i>=IP_FD_NR)
175 {
176 DBLOCK(1, printf("out of fds\n"));
177 return EOUTOFBUFS;
178 }
179 ip_fd= &ip_fd_table[i];
180 ip_fd->if_flags= IFF_INUSE;
181 ip_fd->if_ipopt.nwio_flags= NWIO_DEFAULT;
182 ip_fd->if_ipopt.nwio_tos= 0;
183 ip_fd->if_ipopt.nwio_df= FALSE;
184 ip_fd->if_ipopt.nwio_ttl= 255;
185 ip_fd->if_ipopt.nwio_hdropt.iho_opt_siz= 0;
186 ip_fd->if_port= ip_port;
187 ip_fd->if_srfd= srfd;
188 assert(ip_fd->if_rdbuf_head == NULL);
189 ip_fd->if_get_userdata= get_userdata;
190 ip_fd->if_put_userdata= put_userdata;
191 ip_fd->if_put_pkt= put_pkt;
192 return i;
193 }
ip_close implements the close system call on a ip file descriptor fd.
194 PRIVATE void ip_close (fd)
195 int fd;
196 {
197 ip_fd_t *ip_fd;
198 acc_t *pack;
199 ip_fd= &ip_fd_table[fd];
200 assert ((ip_fd->if_flags & IFF_INUSE) &&
201 !(ip_fd->if_flags & IFF_BUSY));
202 if (ip_fd->if_flags & IFF_OPTSET)
Removes the ip channell from the ip fd table.
203 ip_unhash_proto(ip_fd);
204 while (ip_fd->if_rdbuf_head)
205 {
206 pack= ip_fd->if_rdbuf_head;
207 ip_fd->if_rdbuf_head= pack->acc_ext_link;
208 bf_afree(pack);
209 }
210 ip_fd->if_flags= IFF_EMPTY;
211 }
ip_buffree is used by buf.c to release buffers.
212 PRIVATE void ip_buffree(priority)
213 int priority;
214 {
215 int i;
216 ip_port_t *ip_port;
217 ip_fd_t *ip_fd;
218 ip_ass_t *ip_ass;
219 acc_t *pack, *next_pack;
220 for (i= 0, ip_port= ip_port_table; i<IP_PORT_NR; i++, ip_port++)
221 {
222 if (ip_port->ip_dl_type == IPDL_ETH)
223 {
224 /* Can't free de_frame.
225 * bf_check_acc(ip_port->ip_dl.dl_eth.de_frame);
226 */
227 if (priority == IP_PRI_PORTBUFS)
228 {
229 next_pack= ip_port->ip_dl.dl_eth.de_arp_head;
230 while(next_pack != NULL)
231 {
232 pack= next_pack;
233 next_pack= pack->acc_ext_link;
234 bf_afree(pack);
235 }
236 ip_port->ip_dl.dl_eth.de_arp_head= next_pack;
237 next_pack= ip_port->ip_dl.dl_eth.de_q_head;
238 while(next_pack != NULL)
239 {
240 pack= next_pack;
241 next_pack= pack->acc_ext_link;
242 bf_afree(pack);
243 }
244 ip_port->ip_dl.dl_eth.de_q_head= next_pack;
245 }
246 }
247 else if (ip_port->ip_dl_type == IPDL_PSIP)
248 {
249 if (priority == IP_PRI_PORTBUFS)
250 {
251 next_pack= ip_port->ip_dl.dl_ps.ps_send_head;
252 while(next_pack != NULL)
253 {
254 pack= next_pack;
255 next_pack= pack->acc_ext_link;
256 bf_afree(pack);
257 }
258 ip_port->ip_dl.dl_ps.ps_send_head= next_pack;
259 }
260 }
261 if (priority == IP_PRI_PORTBUFS)
262 {
263 next_pack= ip_port->ip_loopb_head;
264 while(next_pack && next_pack->acc_ext_link)
265 {
266 pack= next_pack;
267 next_pack= pack->acc_ext_link;
268 bf_afree(pack);
269 }
270 if (next_pack)
271 {
272 if (ev_in_queue(&ip_port->ip_loopb_event))
273 {
274 #if !CRAMPED
275 printf(
276 "not freeing ip_loopb_head, ip_loopb_event enqueued\n");
277 #endif
278 }
279 else
280 {
281 bf_afree(next_pack);
282 next_pack= NULL;
283 }
284 }
285 ip_port->ip_loopb_head= next_pack;
286 }
287 }
288 if (priority == IP_PRI_FDBUFS_EXTRA)
289 {
290 for (i= 0, ip_fd= ip_fd_table; i<IP_FD_NR; i++, ip_fd++)
291 {
292 while (ip_fd->if_rdbuf_head &&
293 ip_fd->if_rdbuf_head->acc_ext_link)
294 {
295 pack= ip_fd->if_rdbuf_head;
296 ip_fd->if_rdbuf_head= pack->acc_ext_link;
297 bf_afree(pack);
298 }
299 }
300 }
301 if (priority == IP_PRI_FDBUFS)
302 {
303 for (i= 0, ip_fd= ip_fd_table; i<IP_FD_NR; i++, ip_fd++)
304 {
305 while (ip_fd->if_rdbuf_head)
306 {
307 pack= ip_fd->if_rdbuf_head;
308 ip_fd->if_rdbuf_head= pack->acc_ext_link;
309 bf_afree(pack);
310 }
311 }
312 }
313 if (priority == IP_PRI_ASSBUFS)
314 {
315 for (i= 0, ip_ass= ip_ass_table; i<IP_ASS_NR; i++, ip_ass++)
316 {
317 next_pack= ip_ass->ia_frags;
318 while(ip_ass->ia_frags != NULL)
319 {
320 pack= ip_ass->ia_frags;
321 ip_ass->ia_frags= pack->acc_ext_link;
322 bf_afree(pack);
323 }
324 ip_ass->ia_first_time= 0;
325 }
326 }
327 }
328 #ifdef BUF_CONSISTENCY_CHECK
329 PRIVATE void ip_bufcheck()
330 {
331 int i;
332 ip_port_t *ip_port;
333 ip_fd_t *ip_fd;
334 ip_ass_t *ip_ass;
335 acc_t *pack;
336 for (i= 0, ip_port= ip_port_table; i<IP_PORT_NR; i++, ip_port++)
337 {
338 if (ip_port->ip_dl_type == IPDL_ETH)
339 {
340 bf_check_acc(ip_port->ip_dl.dl_eth.de_frame);
341 for (pack= ip_port->ip_dl.dl_eth.de_q_head; pack;
342 pack= pack->acc_ext_link)
343 {
344 bf_check_acc(pack);
345 }
346 for (pack= ip_port->ip_dl.dl_eth.de_arp_head; pack;
347 pack= pack->acc_ext_link)
348 {
349 bf_check_acc(pack);
350 }
351 }
352 else if (ip_port->ip_dl_type == IPDL_PSIP)
353 {
354 for (pack= ip_port->ip_dl.dl_ps.ps_send_head; pack;
355 pack= pack->acc_ext_link)
356 {
357 bf_check_acc(pack);
358 }
359 }
360 for (pack= ip_port->ip_loopb_head; pack;
361 pack= pack->acc_ext_link)
362 {
363 bf_check_acc(pack);
364 }
365 }
366 for (i= 0, ip_fd= ip_fd_table; i<IP_FD_NR; i++, ip_fd++)
367 {
368 for (pack= ip_fd->if_rdbuf_head; pack;
369 pack= pack->acc_ext_link)
370 {
371 bf_check_acc(pack);
372 }
373 }
374 for (i= 0, ip_ass= ip_ass_table; i<IP_ASS_NR; i++, ip_ass++)
375 {
376 for (pack= ip_ass->ia_frags; pack; pack= pack->acc_ext_link)
377 bf_check_acc(pack);
378 }
379 }
380 #endif /* BUF_CONSISTENCY_CHECK */
381 PRIVATE void ip_bad_callback(ip_port)
382 struct ip_port *ip_port;
383 {
384 ip_panic(( "no callback filled in for port %d",
385 ip_port-ip_port_table ));
386 }
387 /*
388 * $PchId: ip.c,v 1.7 1996/12/17 07:54:47 philip Exp $
389 */
ip.c implements the IP interface.