1 | /*
|
---|
2 | ip_read.c
|
---|
3 |
|
---|
4 | Copyright 1995 Philip Homburg
|
---|
5 | */
|
---|
6 |
|
---|
7 | #include "inet.h"
|
---|
8 | #include "buf.h"
|
---|
9 | #include "clock.h"
|
---|
10 | #include "event.h"
|
---|
11 | #include "type.h"
|
---|
12 |
|
---|
13 | #include "assert.h"
|
---|
14 | #include "icmp_lib.h"
|
---|
15 | #include "io.h"
|
---|
16 | #include "ip.h"
|
---|
17 | #include "ip_int.h"
|
---|
18 | #include "ipr.h"
|
---|
19 |
|
---|
20 | THIS_FILE
|
---|
21 |
|
---|
22 | FORWARD ip_ass_t *find_ass_ent ARGS(( ip_port_t *ip_port, U16_t id,
|
---|
23 | int proto, ipaddr_t src, ipaddr_t dst ));
|
---|
24 | FORWARD acc_t *merge_frags ARGS(( acc_t *first, acc_t *second ));
|
---|
25 | FORWARD int ip_frag_chk ARGS(( acc_t *pack ));
|
---|
26 | FORWARD acc_t *reassemble ARGS(( ip_port_t *ip_port, acc_t *pack,
|
---|
27 | ip_hdr_t *ip_hdr ));
|
---|
28 | FORWARD void route_packets ARGS(( event_t *ev, ev_arg_t ev_arg ));
|
---|
29 | FORWARD int broadcast_dst ARGS(( ip_port_t *ip_port, ipaddr_t dest ));
|
---|
30 |
|
---|
31 | PUBLIC int ip_read (fd, count)
|
---|
32 | int fd;
|
---|
33 | size_t count;
|
---|
34 | {
|
---|
35 | ip_fd_t *ip_fd;
|
---|
36 | acc_t *pack;
|
---|
37 |
|
---|
38 | ip_fd= &ip_fd_table[fd];
|
---|
39 | if (!(ip_fd->if_flags & IFF_OPTSET))
|
---|
40 | {
|
---|
41 | return (*ip_fd->if_put_userdata)(ip_fd->if_srfd, EBADMODE,
|
---|
42 | (acc_t *)0, FALSE);
|
---|
43 | }
|
---|
44 |
|
---|
45 | ip_fd->if_rd_count= count;
|
---|
46 |
|
---|
47 | ip_fd->if_flags |= IFF_READ_IP;
|
---|
48 | if (ip_fd->if_rdbuf_head)
|
---|
49 | {
|
---|
50 | if (get_time() <= ip_fd->if_exp_time)
|
---|
51 | {
|
---|
52 | pack= ip_fd->if_rdbuf_head;
|
---|
53 | ip_fd->if_rdbuf_head= pack->acc_ext_link;
|
---|
54 | ip_packet2user (ip_fd, pack, ip_fd->if_exp_time,
|
---|
55 | bf_bufsize(pack));
|
---|
56 | assert(!(ip_fd->if_flags & IFF_READ_IP));
|
---|
57 | return NW_OK;
|
---|
58 | }
|
---|
59 | while (ip_fd->if_rdbuf_head)
|
---|
60 | {
|
---|
61 | pack= ip_fd->if_rdbuf_head;
|
---|
62 | ip_fd->if_rdbuf_head= pack->acc_ext_link;
|
---|
63 | bf_afree(pack);
|
---|
64 | }
|
---|
65 | }
|
---|
66 | return NW_SUSPEND;
|
---|
67 | }
|
---|
68 |
|
---|
69 | PRIVATE acc_t *reassemble (ip_port, pack, pack_hdr)
|
---|
70 | ip_port_t *ip_port;
|
---|
71 | acc_t *pack;
|
---|
72 | ip_hdr_t *pack_hdr;
|
---|
73 | {
|
---|
74 | ip_ass_t *ass_ent;
|
---|
75 | size_t pack_hdr_len, pack_data_len, pack_offset, tmp_offset;
|
---|
76 | u16_t pack_flags_fragoff;
|
---|
77 | acc_t *prev_acc, *curr_acc, *next_acc, *head_acc, *tmp_acc;
|
---|
78 | ip_hdr_t *tmp_hdr;
|
---|
79 | time_t first_time;
|
---|
80 |
|
---|
81 | ass_ent= find_ass_ent (ip_port, pack_hdr->ih_id,
|
---|
82 | pack_hdr->ih_proto, pack_hdr->ih_src, pack_hdr->ih_dst);
|
---|
83 |
|
---|
84 | pack_flags_fragoff= ntohs(pack_hdr->ih_flags_fragoff);
|
---|
85 | pack_hdr_len= (pack_hdr->ih_vers_ihl & IH_IHL_MASK) * 4;
|
---|
86 | pack_data_len= ntohs(pack_hdr->ih_length)-pack_hdr_len;
|
---|
87 | pack_offset= (pack_flags_fragoff & IH_FRAGOFF_MASK)*8;
|
---|
88 | pack->acc_ext_link= NULL;
|
---|
89 |
|
---|
90 | head_acc= ass_ent->ia_frags;
|
---|
91 | ass_ent->ia_frags= NULL;
|
---|
92 | if (head_acc == NULL)
|
---|
93 | {
|
---|
94 | ass_ent->ia_frags= pack;
|
---|
95 | return NULL;
|
---|
96 | }
|
---|
97 |
|
---|
98 | prev_acc= NULL;
|
---|
99 | curr_acc= NULL;
|
---|
100 | next_acc= head_acc;
|
---|
101 |
|
---|
102 | while(next_acc)
|
---|
103 | {
|
---|
104 | tmp_hdr= (ip_hdr_t *)ptr2acc_data(next_acc);
|
---|
105 | tmp_offset= (ntohs(tmp_hdr->ih_flags_fragoff) &
|
---|
106 | IH_FRAGOFF_MASK)*8;
|
---|
107 |
|
---|
108 | if (pack_offset < tmp_offset)
|
---|
109 | break;
|
---|
110 |
|
---|
111 | prev_acc= curr_acc;
|
---|
112 | curr_acc= next_acc;
|
---|
113 | next_acc= next_acc->acc_ext_link;
|
---|
114 | }
|
---|
115 | if (curr_acc == NULL)
|
---|
116 | {
|
---|
117 | assert(prev_acc == NULL);
|
---|
118 | assert(next_acc != NULL);
|
---|
119 |
|
---|
120 | curr_acc= merge_frags(pack, next_acc);
|
---|
121 | head_acc= curr_acc;
|
---|
122 | }
|
---|
123 | else
|
---|
124 | {
|
---|
125 | curr_acc= merge_frags(curr_acc, pack);
|
---|
126 | if (next_acc != NULL)
|
---|
127 | curr_acc= merge_frags(curr_acc, next_acc);
|
---|
128 | if (prev_acc != NULL)
|
---|
129 | prev_acc->acc_ext_link= curr_acc;
|
---|
130 | else
|
---|
131 | head_acc= curr_acc;
|
---|
132 | }
|
---|
133 | ass_ent->ia_frags= head_acc;
|
---|
134 |
|
---|
135 | pack= ass_ent->ia_frags;
|
---|
136 | pack_hdr= (ip_hdr_t *)ptr2acc_data(pack);
|
---|
137 | pack_flags_fragoff= ntohs(pack_hdr->ih_flags_fragoff);
|
---|
138 |
|
---|
139 | if (!(pack_flags_fragoff & (IH_FRAGOFF_MASK|IH_MORE_FRAGS)))
|
---|
140 | /* it's now a complete packet */
|
---|
141 | {
|
---|
142 | first_time= ass_ent->ia_first_time;
|
---|
143 |
|
---|
144 | ass_ent->ia_frags= 0;
|
---|
145 | ass_ent->ia_first_time= 0;
|
---|
146 |
|
---|
147 | while (pack->acc_ext_link)
|
---|
148 | {
|
---|
149 | tmp_acc= pack->acc_ext_link;
|
---|
150 | pack->acc_ext_link= tmp_acc->acc_ext_link;
|
---|
151 | bf_afree(tmp_acc);
|
---|
152 | }
|
---|
153 | if ((ass_ent->ia_min_ttl) * HZ + first_time <
|
---|
154 | get_time())
|
---|
155 | {
|
---|
156 | if (broadcast_dst(ip_port, pack_hdr->ih_dst))
|
---|
157 | {
|
---|
158 | DBLOCK(1, printf(
|
---|
159 | "ip_read'reassemble: reassembly timeout for broadcast packet\n"););
|
---|
160 | bf_afree(pack); pack= NULL;
|
---|
161 | return NULL;
|
---|
162 | }
|
---|
163 | icmp_snd_time_exceeded(ip_port->ip_port, pack,
|
---|
164 | ICMP_FRAG_REASSEM);
|
---|
165 | }
|
---|
166 | else
|
---|
167 | return pack;
|
---|
168 | }
|
---|
169 | return NULL;
|
---|
170 | }
|
---|
171 |
|
---|
172 | PRIVATE acc_t *merge_frags (first, second)
|
---|
173 | acc_t *first, *second;
|
---|
174 | {
|
---|
175 | ip_hdr_t *first_hdr, *second_hdr;
|
---|
176 | size_t first_hdr_size, second_hdr_size, first_datasize, second_datasize,
|
---|
177 | first_offset, second_offset;
|
---|
178 | acc_t *cut_second, *tmp_acc;
|
---|
179 |
|
---|
180 | if (!second)
|
---|
181 | {
|
---|
182 | first->acc_ext_link= NULL;
|
---|
183 | return first;
|
---|
184 | }
|
---|
185 |
|
---|
186 | assert (first->acc_length >= IP_MIN_HDR_SIZE);
|
---|
187 | assert (second->acc_length >= IP_MIN_HDR_SIZE);
|
---|
188 |
|
---|
189 | first_hdr= (ip_hdr_t *)ptr2acc_data(first);
|
---|
190 | first_offset= (ntohs(first_hdr->ih_flags_fragoff) &
|
---|
191 | IH_FRAGOFF_MASK) * 8;
|
---|
192 | first_hdr_size= (first_hdr->ih_vers_ihl & IH_IHL_MASK) * 4;
|
---|
193 | first_datasize= ntohs(first_hdr->ih_length) - first_hdr_size;
|
---|
194 |
|
---|
195 | second_hdr= (ip_hdr_t *)ptr2acc_data(second);
|
---|
196 | second_offset= (ntohs(second_hdr->ih_flags_fragoff) &
|
---|
197 | IH_FRAGOFF_MASK) * 8;
|
---|
198 | second_hdr_size= (second_hdr->ih_vers_ihl & IH_IHL_MASK) * 4;
|
---|
199 | second_datasize= ntohs(second_hdr->ih_length) - second_hdr_size;
|
---|
200 |
|
---|
201 | assert (first_hdr_size + first_datasize == bf_bufsize(first));
|
---|
202 | assert (second_hdr_size + second_datasize == bf_bufsize(second));
|
---|
203 | assert (second_offset >= first_offset);
|
---|
204 |
|
---|
205 | if (second_offset > first_offset+first_datasize)
|
---|
206 | {
|
---|
207 | DBLOCK(1, printf("ip fragments out of order\n"));
|
---|
208 | first->acc_ext_link= second;
|
---|
209 | return first;
|
---|
210 | }
|
---|
211 |
|
---|
212 | if (second_offset + second_datasize <= first_offset +
|
---|
213 | first_datasize)
|
---|
214 | {
|
---|
215 | /* May cause problems if we try to merge. */
|
---|
216 | bf_afree(first);
|
---|
217 | return second;
|
---|
218 | }
|
---|
219 |
|
---|
220 | if (!(second_hdr->ih_flags_fragoff & HTONS(IH_MORE_FRAGS)))
|
---|
221 | first_hdr->ih_flags_fragoff &= ~HTONS(IH_MORE_FRAGS);
|
---|
222 |
|
---|
223 | second_datasize= second_offset+second_datasize-(first_offset+
|
---|
224 | first_datasize);
|
---|
225 | cut_second= bf_cut(second, second_hdr_size + first_offset+
|
---|
226 | first_datasize-second_offset, second_datasize);
|
---|
227 | tmp_acc= second->acc_ext_link;
|
---|
228 | bf_afree(second);
|
---|
229 | second= tmp_acc;
|
---|
230 |
|
---|
231 | first_datasize += second_datasize;
|
---|
232 | first_hdr->ih_length= htons(first_hdr_size + first_datasize);
|
---|
233 |
|
---|
234 | first= bf_append (first, cut_second);
|
---|
235 | first->acc_ext_link= second;
|
---|
236 |
|
---|
237 | assert (first_hdr_size + first_datasize == bf_bufsize(first));
|
---|
238 |
|
---|
239 | return first;
|
---|
240 | }
|
---|
241 |
|
---|
242 | PRIVATE ip_ass_t *find_ass_ent (ip_port, id, proto, src, dst)
|
---|
243 | ip_port_t *ip_port;
|
---|
244 | u16_t id;
|
---|
245 | ipproto_t proto;
|
---|
246 | ipaddr_t src;
|
---|
247 | ipaddr_t dst;
|
---|
248 | {
|
---|
249 | ip_ass_t *new_ass_ent, *tmp_ass_ent;
|
---|
250 | int i;
|
---|
251 | acc_t *tmp_acc, *curr_acc;
|
---|
252 |
|
---|
253 | new_ass_ent= 0;
|
---|
254 |
|
---|
255 | for (i=0, tmp_ass_ent= ip_ass_table; i<IP_ASS_NR; i++,
|
---|
256 | tmp_ass_ent++)
|
---|
257 | {
|
---|
258 | if (!tmp_ass_ent->ia_frags && tmp_ass_ent->ia_first_time)
|
---|
259 | {
|
---|
260 | DBLOCK(1,
|
---|
261 | printf("strange ip_ass entry (can be a race condition)\n"));
|
---|
262 | continue;
|
---|
263 | }
|
---|
264 |
|
---|
265 | if ((tmp_ass_ent->ia_srcaddr == src) &&
|
---|
266 | (tmp_ass_ent->ia_dstaddr == dst) &&
|
---|
267 | (tmp_ass_ent->ia_proto == proto) &&
|
---|
268 | (tmp_ass_ent->ia_id == id) &&
|
---|
269 | (tmp_ass_ent->ia_port == ip_port))
|
---|
270 | {
|
---|
271 | return tmp_ass_ent;
|
---|
272 | }
|
---|
273 | if (!new_ass_ent || tmp_ass_ent->ia_first_time <
|
---|
274 | new_ass_ent->ia_first_time)
|
---|
275 | {
|
---|
276 | new_ass_ent= tmp_ass_ent;
|
---|
277 | }
|
---|
278 | }
|
---|
279 |
|
---|
280 | if (new_ass_ent->ia_frags)
|
---|
281 | {
|
---|
282 | DBLOCK(2, printf("old frags id= %u, proto= %u, src= ",
|
---|
283 | ntohs(new_ass_ent->ia_id),
|
---|
284 | new_ass_ent->ia_proto);
|
---|
285 | writeIpAddr(new_ass_ent->ia_srcaddr); printf(" dst= ");
|
---|
286 | writeIpAddr(new_ass_ent->ia_dstaddr); printf(": ");
|
---|
287 | ip_print_frags(new_ass_ent->ia_frags); printf("\n"));
|
---|
288 | curr_acc= new_ass_ent->ia_frags->acc_ext_link;
|
---|
289 | while (curr_acc)
|
---|
290 | {
|
---|
291 | tmp_acc= curr_acc->acc_ext_link;
|
---|
292 | bf_afree(curr_acc);
|
---|
293 | curr_acc= tmp_acc;
|
---|
294 | }
|
---|
295 | curr_acc= new_ass_ent->ia_frags;
|
---|
296 | new_ass_ent->ia_frags= 0;
|
---|
297 | if (broadcast_dst(ip_port, new_ass_ent->ia_dstaddr))
|
---|
298 | {
|
---|
299 | DBLOCK(1, printf(
|
---|
300 | "ip_read'find_ass_ent: reassembly timeout for broadcast packet\n"));
|
---|
301 | bf_afree(curr_acc); curr_acc= NULL;
|
---|
302 | }
|
---|
303 | else
|
---|
304 | {
|
---|
305 | icmp_snd_time_exceeded(ip_port->ip_port,
|
---|
306 | curr_acc, ICMP_FRAG_REASSEM);
|
---|
307 | }
|
---|
308 | }
|
---|
309 | new_ass_ent->ia_min_ttl= IP_MAX_TTL;
|
---|
310 | new_ass_ent->ia_port= ip_port;
|
---|
311 | new_ass_ent->ia_first_time= get_time();
|
---|
312 | new_ass_ent->ia_srcaddr= src;
|
---|
313 | new_ass_ent->ia_dstaddr= dst;
|
---|
314 | new_ass_ent->ia_proto= proto;
|
---|
315 | new_ass_ent->ia_id= id;
|
---|
316 |
|
---|
317 | return new_ass_ent;
|
---|
318 | }
|
---|
319 |
|
---|
320 | PRIVATE int ip_frag_chk(pack)
|
---|
321 | acc_t *pack;
|
---|
322 | {
|
---|
323 | ip_hdr_t *ip_hdr;
|
---|
324 | int hdr_len;
|
---|
325 |
|
---|
326 | if (pack->acc_length < sizeof(ip_hdr_t))
|
---|
327 | {
|
---|
328 | DBLOCK(1, printf("wrong length\n"));
|
---|
329 | return FALSE;
|
---|
330 | }
|
---|
331 |
|
---|
332 | ip_hdr= (ip_hdr_t *)ptr2acc_data(pack);
|
---|
333 |
|
---|
334 | hdr_len= (ip_hdr->ih_vers_ihl & IH_IHL_MASK) * 4;
|
---|
335 | if (pack->acc_length < hdr_len)
|
---|
336 | {
|
---|
337 | DBLOCK(1, printf("wrong length\n"));
|
---|
338 |
|
---|
339 | return FALSE;
|
---|
340 | }
|
---|
341 |
|
---|
342 | if (((ip_hdr->ih_vers_ihl >> 4) & IH_VERSION_MASK) !=
|
---|
343 | IP_VERSION)
|
---|
344 | {
|
---|
345 | DBLOCK(1, printf("wrong version (ih_vers_ihl=0x%x)\n",
|
---|
346 | ip_hdr->ih_vers_ihl));
|
---|
347 | return FALSE;
|
---|
348 | }
|
---|
349 | if (ntohs(ip_hdr->ih_length) != bf_bufsize(pack))
|
---|
350 | {
|
---|
351 | DBLOCK(1, printf("wrong size\n"));
|
---|
352 |
|
---|
353 | return FALSE;
|
---|
354 | }
|
---|
355 | if ((u16_t)~oneC_sum(0, (u16_t *)ip_hdr, hdr_len))
|
---|
356 | {
|
---|
357 | DBLOCK(1, printf("packet with wrong checksum (= %x)\n",
|
---|
358 | (u16_t)~oneC_sum(0, (u16_t *)ip_hdr, hdr_len)));
|
---|
359 | return FALSE;
|
---|
360 | }
|
---|
361 | if (hdr_len>IP_MIN_HDR_SIZE && ip_chk_hdropt((u8_t *)
|
---|
362 | (ptr2acc_data(pack) + IP_MIN_HDR_SIZE),
|
---|
363 | hdr_len-IP_MIN_HDR_SIZE))
|
---|
364 | {
|
---|
365 | DBLOCK(1, printf("packet with wrong options\n"));
|
---|
366 | return FALSE;
|
---|
367 | }
|
---|
368 | return TRUE;
|
---|
369 | }
|
---|
370 |
|
---|
371 | PUBLIC void ip_packet2user (ip_fd, pack, exp_time, data_len)
|
---|
372 | ip_fd_t *ip_fd;
|
---|
373 | acc_t *pack;
|
---|
374 | time_t exp_time;
|
---|
375 | size_t data_len;
|
---|
376 | {
|
---|
377 | acc_t *tmp_pack;
|
---|
378 | ip_hdr_t *ip_hdr;
|
---|
379 | int result, ip_hdr_len;
|
---|
380 | size_t transf_size;
|
---|
381 |
|
---|
382 | assert (ip_fd->if_flags & IFF_INUSE);
|
---|
383 | if (!(ip_fd->if_flags & IFF_READ_IP))
|
---|
384 | {
|
---|
385 | if (pack->acc_linkC != 1)
|
---|
386 | {
|
---|
387 | tmp_pack= bf_dupacc(pack);
|
---|
388 | bf_afree(pack);
|
---|
389 | pack= tmp_pack;
|
---|
390 | tmp_pack= NULL;
|
---|
391 | }
|
---|
392 | pack->acc_ext_link= NULL;
|
---|
393 | if (ip_fd->if_rdbuf_head == NULL)
|
---|
394 | {
|
---|
395 | ip_fd->if_rdbuf_head= pack;
|
---|
396 | ip_fd->if_exp_time= exp_time;
|
---|
397 | }
|
---|
398 | else
|
---|
399 | ip_fd->if_rdbuf_tail->acc_ext_link= pack;
|
---|
400 | ip_fd->if_rdbuf_tail= pack;
|
---|
401 | return;
|
---|
402 | }
|
---|
403 |
|
---|
404 | assert (pack->acc_length >= IP_MIN_HDR_SIZE);
|
---|
405 | ip_hdr= (ip_hdr_t *)ptr2acc_data(pack);
|
---|
406 |
|
---|
407 | if (ip_fd->if_ipopt.nwio_flags & NWIO_RWDATONLY)
|
---|
408 | {
|
---|
409 | ip_hdr_len= (ip_hdr->ih_vers_ihl & IH_IHL_MASK) * 4;
|
---|
410 |
|
---|
411 | assert (data_len > ip_hdr_len);
|
---|
412 | data_len -= ip_hdr_len;
|
---|
413 | pack= bf_delhead(pack, ip_hdr_len);
|
---|
414 | }
|
---|
415 |
|
---|
416 | if (data_len > ip_fd->if_rd_count)
|
---|
417 | {
|
---|
418 | tmp_pack= bf_cut (pack, 0, ip_fd->if_rd_count);
|
---|
419 | bf_afree(pack);
|
---|
420 | pack= tmp_pack;
|
---|
421 | transf_size= ip_fd->if_rd_count;
|
---|
422 | }
|
---|
423 | else
|
---|
424 | transf_size= data_len;
|
---|
425 |
|
---|
426 | if (ip_fd->if_put_pkt)
|
---|
427 | {
|
---|
428 | (*ip_fd->if_put_pkt)(ip_fd->if_srfd, pack, transf_size);
|
---|
429 | return;
|
---|
430 | }
|
---|
431 |
|
---|
432 | result= (*ip_fd->if_put_userdata)(ip_fd->if_srfd,
|
---|
433 | (size_t)0, pack, FALSE);
|
---|
434 | if (result >= 0)
|
---|
435 | {
|
---|
436 | if (data_len > transf_size)
|
---|
437 | result= EPACKSIZE;
|
---|
438 | else
|
---|
439 | result= transf_size;
|
---|
440 | }
|
---|
441 |
|
---|
442 | ip_fd->if_flags &= ~IFF_READ_IP;
|
---|
443 | result= (*ip_fd->if_put_userdata)(ip_fd->if_srfd, result,
|
---|
444 | (acc_t *)0, FALSE);
|
---|
445 | assert (result >= 0);
|
---|
446 | }
|
---|
447 |
|
---|
448 | PUBLIC void ip_port_arrive (ip_port, pack, ip_hdr)
|
---|
449 | ip_port_t *ip_port;
|
---|
450 | acc_t *pack;
|
---|
451 | ip_hdr_t *ip_hdr;
|
---|
452 | {
|
---|
453 | ip_fd_t *ip_fd, *first_fd, *share_fd;
|
---|
454 | unsigned long ip_pack_stat;
|
---|
455 | unsigned size;
|
---|
456 | int i;
|
---|
457 | int hash, proto;
|
---|
458 | time_t exp_time;
|
---|
459 |
|
---|
460 | assert (pack->acc_linkC>0);
|
---|
461 | assert (pack->acc_length >= IP_MIN_HDR_SIZE);
|
---|
462 |
|
---|
463 | if (ntohs(ip_hdr->ih_flags_fragoff) & (IH_FRAGOFF_MASK|IH_MORE_FRAGS))
|
---|
464 | {
|
---|
465 | pack= reassemble (ip_port, pack, ip_hdr);
|
---|
466 | if (!pack)
|
---|
467 | return;
|
---|
468 | assert (pack->acc_length >= IP_MIN_HDR_SIZE);
|
---|
469 | ip_hdr= (ip_hdr_t *)ptr2acc_data(pack);
|
---|
470 | assert (!(ntohs(ip_hdr->ih_flags_fragoff) &
|
---|
471 | (IH_FRAGOFF_MASK|IH_MORE_FRAGS)));
|
---|
472 | }
|
---|
473 | size= ntohs(ip_hdr->ih_length);
|
---|
474 | if (size > bf_bufsize(pack))
|
---|
475 | {
|
---|
476 | /* Should discard packet */
|
---|
477 | assert(0);
|
---|
478 | bf_afree(pack); pack= NULL;
|
---|
479 | return;
|
---|
480 | }
|
---|
481 |
|
---|
482 | exp_time= get_time() + (ip_hdr->ih_ttl+1) * HZ;
|
---|
483 |
|
---|
484 | if (ip_hdr->ih_dst == ip_port->ip_ipaddr)
|
---|
485 | ip_pack_stat= NWIO_EN_LOC;
|
---|
486 | else
|
---|
487 | ip_pack_stat= NWIO_EN_BROAD;
|
---|
488 |
|
---|
489 | proto= ip_hdr->ih_proto;
|
---|
490 | hash= proto & (IP_PROTO_HASH_NR-1);
|
---|
491 |
|
---|
492 | first_fd= NULL;
|
---|
493 | for (i= 0; i<2; i++)
|
---|
494 | {
|
---|
495 | share_fd= NULL;
|
---|
496 |
|
---|
497 | ip_fd= (i == 0) ? ip_port->ip_proto_any :
|
---|
498 | ip_port->ip_proto[hash];
|
---|
499 | for (; ip_fd; ip_fd= ip_fd->if_proto_next)
|
---|
500 | {
|
---|
501 | if (i && ip_fd->if_ipopt.nwio_proto != proto)
|
---|
502 | continue;
|
---|
503 | if (!(ip_fd->if_ipopt.nwio_flags & ip_pack_stat))
|
---|
504 | continue;
|
---|
505 | if ((ip_fd->if_ipopt.nwio_flags & NWIO_REMSPEC) &&
|
---|
506 | ip_hdr->ih_src != ip_fd->if_ipopt.nwio_rem)
|
---|
507 | {
|
---|
508 | continue;
|
---|
509 | }
|
---|
510 | if ((ip_fd->if_ipopt.nwio_flags & NWIO_ACC_MASK) ==
|
---|
511 | NWIO_SHARED)
|
---|
512 | {
|
---|
513 | if (!share_fd)
|
---|
514 | {
|
---|
515 | share_fd= ip_fd;
|
---|
516 | continue;
|
---|
517 | }
|
---|
518 | if (!ip_fd->if_rdbuf_head)
|
---|
519 | share_fd= ip_fd;
|
---|
520 | continue;
|
---|
521 | }
|
---|
522 | if (!first_fd)
|
---|
523 | {
|
---|
524 | first_fd= ip_fd;
|
---|
525 | continue;
|
---|
526 | }
|
---|
527 | pack->acc_linkC++;
|
---|
528 | ip_packet2user(ip_fd, pack, exp_time, size);
|
---|
529 |
|
---|
530 | }
|
---|
531 | if (share_fd)
|
---|
532 | {
|
---|
533 | pack->acc_linkC++;
|
---|
534 | ip_packet2user(share_fd, pack, exp_time, size);
|
---|
535 | }
|
---|
536 | }
|
---|
537 | if (first_fd)
|
---|
538 | {
|
---|
539 | if (first_fd->if_put_pkt &&
|
---|
540 | (first_fd->if_flags & IFF_READ_IP) &&
|
---|
541 | !(first_fd->if_ipopt.nwio_flags & NWIO_RWDATONLY))
|
---|
542 | {
|
---|
543 | (*first_fd->if_put_pkt)(first_fd->if_srfd, pack,
|
---|
544 | size);
|
---|
545 | }
|
---|
546 | else
|
---|
547 | ip_packet2user(first_fd, pack, exp_time, size);
|
---|
548 | }
|
---|
549 | else
|
---|
550 | {
|
---|
551 | if (ip_pack_stat == NWIO_EN_LOC)
|
---|
552 | {
|
---|
553 | DBLOCK(0x01,
|
---|
554 | printf("ip_port_arrive: dropping packet for proto %d\n",
|
---|
555 | proto));
|
---|
556 | }
|
---|
557 | else
|
---|
558 | {
|
---|
559 | DBLOCK(0x20, printf("dropping packet for proto %d\n",
|
---|
560 | proto));
|
---|
561 | }
|
---|
562 | bf_afree(pack);
|
---|
563 | }
|
---|
564 | }
|
---|
565 |
|
---|
566 | PUBLIC void ip_arrived(ip_port, pack)
|
---|
567 | ip_port_t *ip_port;
|
---|
568 | acc_t *pack;
|
---|
569 | {
|
---|
570 | ip_hdr_t *ip_hdr;
|
---|
571 | ipaddr_t dest;
|
---|
572 | int ip_frag_len, ip_hdr_len, highbyte;
|
---|
573 | size_t pack_size;
|
---|
574 | acc_t *tmp_pack, *hdr_pack;
|
---|
575 | ev_arg_t ev_arg;
|
---|
576 |
|
---|
577 | pack_size= bf_bufsize(pack);
|
---|
578 |
|
---|
579 | if (pack_size < IP_MIN_HDR_SIZE)
|
---|
580 | {
|
---|
581 | DBLOCK(1, printf("wrong acc_length\n"));
|
---|
582 | bf_afree(pack);
|
---|
583 | return;
|
---|
584 | }
|
---|
585 | pack= bf_align(pack, IP_MIN_HDR_SIZE, 4);
|
---|
586 | pack= bf_packIffLess(pack, IP_MIN_HDR_SIZE);
|
---|
587 | assert (pack->acc_length >= IP_MIN_HDR_SIZE);
|
---|
588 |
|
---|
589 | ip_hdr= (ip_hdr_t *)ptr2acc_data(pack);
|
---|
590 | ip_hdr_len= (ip_hdr->ih_vers_ihl & IH_IHL_MASK) << 2;
|
---|
591 | if (ip_hdr_len>IP_MIN_HDR_SIZE)
|
---|
592 | {
|
---|
593 | pack= bf_packIffLess(pack, ip_hdr_len);
|
---|
594 | ip_hdr= (ip_hdr_t *)ptr2acc_data(pack);
|
---|
595 | }
|
---|
596 | ip_frag_len= ntohs(ip_hdr->ih_length);
|
---|
597 | if (ip_frag_len != pack_size)
|
---|
598 | {
|
---|
599 | if (pack_size < ip_frag_len)
|
---|
600 | {
|
---|
601 | /* Sent ICMP? */
|
---|
602 | DBLOCK(1, printf("wrong acc_length\n"));
|
---|
603 | bf_afree(pack);
|
---|
604 | return;
|
---|
605 | }
|
---|
606 | assert(ip_frag_len<pack_size);
|
---|
607 | tmp_pack= pack;
|
---|
608 | pack= bf_cut(tmp_pack, 0, ip_frag_len);
|
---|
609 | bf_afree(tmp_pack);
|
---|
610 | pack_size= ip_frag_len;
|
---|
611 | }
|
---|
612 |
|
---|
613 | if (!ip_frag_chk(pack))
|
---|
614 | {
|
---|
615 | DBLOCK(1, printf("fragment not allright\n"));
|
---|
616 | bf_afree(pack);
|
---|
617 | return;
|
---|
618 | }
|
---|
619 |
|
---|
620 | /* Decide about local delivery or routing. Local delivery can happen
|
---|
621 | * when the destination is the local ip address, or one of the
|
---|
622 | * broadcast addresses and the packet happens to be delivered
|
---|
623 | * point-to-point.
|
---|
624 | */
|
---|
625 |
|
---|
626 | dest= ip_hdr->ih_dst;
|
---|
627 |
|
---|
628 | if (dest == ip_port->ip_ipaddr)
|
---|
629 | {
|
---|
630 | ip_port_arrive (ip_port, pack, ip_hdr);
|
---|
631 | return;
|
---|
632 | }
|
---|
633 | if (broadcast_dst(ip_port, dest))
|
---|
634 | {
|
---|
635 | ip_port_arrive (ip_port, pack, ip_hdr);
|
---|
636 | return;
|
---|
637 | }
|
---|
638 |
|
---|
639 | if (pack->acc_linkC != 1 || pack->acc_buffer->buf_linkC != 1)
|
---|
640 | {
|
---|
641 | /* Get a private copy of the IP header */
|
---|
642 | hdr_pack= bf_memreq(ip_hdr_len);
|
---|
643 | memcpy(ptr2acc_data(hdr_pack), ip_hdr, ip_hdr_len);
|
---|
644 | pack= bf_delhead(pack, ip_hdr_len);
|
---|
645 | hdr_pack->acc_next= pack;
|
---|
646 | pack= hdr_pack; hdr_pack= NULL;
|
---|
647 | ip_hdr= (ip_hdr_t *)ptr2acc_data(pack);
|
---|
648 | }
|
---|
649 | assert(pack->acc_linkC == 1);
|
---|
650 | assert(pack->acc_buffer->buf_linkC == 1);
|
---|
651 |
|
---|
652 | /* Try to decrement the ttl field with one. */
|
---|
653 | if (ip_hdr->ih_ttl < 2)
|
---|
654 | {
|
---|
655 | icmp_snd_time_exceeded(ip_port->ip_port, pack,
|
---|
656 | ICMP_TTL_EXC);
|
---|
657 | return;
|
---|
658 | }
|
---|
659 | ip_hdr->ih_ttl--;
|
---|
660 | ip_hdr_chksum(ip_hdr, ip_hdr_len);
|
---|
661 |
|
---|
662 | /* Avoid routing to bad destinations. */
|
---|
663 | highbyte= ntohl(dest) >> 24;
|
---|
664 | if (highbyte == 0 || highbyte == 127 ||
|
---|
665 | (highbyte == 169 && (((ntohl(dest) >> 16) & 0xff) == 254)) ||
|
---|
666 | highbyte >= 0xe0)
|
---|
667 | {
|
---|
668 | /* Bogus destination address */
|
---|
669 | bf_afree(pack);
|
---|
670 | return;
|
---|
671 | }
|
---|
672 |
|
---|
673 | /* Further processing from an event handler */
|
---|
674 | if (pack->acc_linkC != 1)
|
---|
675 | {
|
---|
676 | tmp_pack= bf_dupacc(pack);
|
---|
677 | bf_afree(pack);
|
---|
678 | pack= tmp_pack;
|
---|
679 | tmp_pack= NULL;
|
---|
680 | }
|
---|
681 | pack->acc_ext_link= NULL;
|
---|
682 | if (ip_port->ip_routeq_head)
|
---|
683 | {
|
---|
684 | ip_port->ip_routeq_tail->acc_ext_link= pack;
|
---|
685 | ip_port->ip_routeq_tail= pack;
|
---|
686 | return;
|
---|
687 | }
|
---|
688 |
|
---|
689 | ip_port->ip_routeq_head= pack;
|
---|
690 | ip_port->ip_routeq_tail= pack;
|
---|
691 | ev_arg.ev_ptr= ip_port;
|
---|
692 | ev_enqueue(&ip_port->ip_routeq_event, route_packets, ev_arg);
|
---|
693 | }
|
---|
694 |
|
---|
695 | PUBLIC void ip_arrived_broadcast(ip_port, pack)
|
---|
696 | ip_port_t *ip_port;
|
---|
697 | acc_t *pack;
|
---|
698 | {
|
---|
699 | ip_hdr_t *ip_hdr;
|
---|
700 | int ip_frag_len, ip_hdr_len;
|
---|
701 | size_t pack_size;
|
---|
702 | acc_t *tmp_pack;
|
---|
703 |
|
---|
704 | pack_size= bf_bufsize(pack);
|
---|
705 |
|
---|
706 | if (pack_size < IP_MIN_HDR_SIZE)
|
---|
707 | {
|
---|
708 | DBLOCK(1, printf("wrong acc_length\n"));
|
---|
709 | bf_afree(pack);
|
---|
710 | return;
|
---|
711 | }
|
---|
712 | pack= bf_align(pack, IP_MIN_HDR_SIZE, 4);
|
---|
713 | pack= bf_packIffLess(pack, IP_MIN_HDR_SIZE);
|
---|
714 | assert (pack->acc_length >= IP_MIN_HDR_SIZE);
|
---|
715 |
|
---|
716 | ip_hdr= (ip_hdr_t *)ptr2acc_data(pack);
|
---|
717 |
|
---|
718 | DIFBLOCK(0x20, (ip_hdr->ih_dst & HTONL(0xf0000000)) == HTONL(0xe0000000),
|
---|
719 | printf("got multicast packet\n"));
|
---|
720 |
|
---|
721 | ip_hdr_len= (ip_hdr->ih_vers_ihl & IH_IHL_MASK) << 2;
|
---|
722 | if (ip_hdr_len>IP_MIN_HDR_SIZE)
|
---|
723 | {
|
---|
724 | pack= bf_align(pack, IP_MIN_HDR_SIZE, 4);
|
---|
725 | pack= bf_packIffLess(pack, ip_hdr_len);
|
---|
726 | ip_hdr= (ip_hdr_t *)ptr2acc_data(pack);
|
---|
727 | }
|
---|
728 | ip_frag_len= ntohs(ip_hdr->ih_length);
|
---|
729 | if (ip_frag_len<pack_size)
|
---|
730 | {
|
---|
731 | tmp_pack= pack;
|
---|
732 | pack= bf_cut(tmp_pack, 0, ip_frag_len);
|
---|
733 | bf_afree(tmp_pack);
|
---|
734 | }
|
---|
735 |
|
---|
736 | if (!ip_frag_chk(pack))
|
---|
737 | {
|
---|
738 | DBLOCK(1, printf("fragment not allright\n"));
|
---|
739 | bf_afree(pack);
|
---|
740 | return;
|
---|
741 | }
|
---|
742 |
|
---|
743 | if (!broadcast_dst(ip_port, ip_hdr->ih_dst))
|
---|
744 | {
|
---|
745 | #if 0
|
---|
746 | printf(
|
---|
747 | "ip[%d]: broadcast packet for ip-nonbroadcast addr, src=",
|
---|
748 | ip_port->ip_port);
|
---|
749 | writeIpAddr(ip_hdr->ih_src);
|
---|
750 | printf(" dst=");
|
---|
751 | writeIpAddr(ip_hdr->ih_dst);
|
---|
752 | printf("\n");
|
---|
753 | #endif
|
---|
754 | bf_afree(pack);
|
---|
755 | return;
|
---|
756 | }
|
---|
757 |
|
---|
758 | ip_port_arrive (ip_port, pack, ip_hdr);
|
---|
759 | }
|
---|
760 |
|
---|
761 | PRIVATE void route_packets(ev, ev_arg)
|
---|
762 | event_t *ev;
|
---|
763 | ev_arg_t ev_arg;
|
---|
764 | {
|
---|
765 | ip_port_t *ip_port;
|
---|
766 | ipaddr_t dest;
|
---|
767 | acc_t *pack;
|
---|
768 | iroute_t *iroute;
|
---|
769 | ip_port_t *next_port;
|
---|
770 | int r, type;
|
---|
771 | ip_hdr_t *ip_hdr;
|
---|
772 | size_t req_mtu;
|
---|
773 |
|
---|
774 | ip_port= ev_arg.ev_ptr;
|
---|
775 | assert(&ip_port->ip_routeq_event == ev);
|
---|
776 |
|
---|
777 | while (pack= ip_port->ip_routeq_head, pack != NULL)
|
---|
778 | {
|
---|
779 | ip_port->ip_routeq_head= pack->acc_ext_link;
|
---|
780 |
|
---|
781 | ip_hdr= (ip_hdr_t *)ptr2acc_data(pack);
|
---|
782 | dest= ip_hdr->ih_dst;
|
---|
783 |
|
---|
784 | iroute= iroute_frag(ip_port->ip_port, dest);
|
---|
785 | if (iroute == NULL || iroute->irt_dist == IRTD_UNREACHABLE)
|
---|
786 | {
|
---|
787 | /* Also unreachable */
|
---|
788 | /* Finding out if we send a network unreachable is too
|
---|
789 | * much trouble.
|
---|
790 | */
|
---|
791 | if (iroute == NULL)
|
---|
792 | {
|
---|
793 | printf("ip[%d]: no route to ",
|
---|
794 | ip_port-ip_port_table);
|
---|
795 | writeIpAddr(dest);
|
---|
796 | printf("\n");
|
---|
797 | }
|
---|
798 | icmp_snd_unreachable(ip_port->ip_port, pack,
|
---|
799 | ICMP_HOST_UNRCH);
|
---|
800 | continue;
|
---|
801 | }
|
---|
802 | next_port= &ip_port_table[iroute->irt_port];
|
---|
803 |
|
---|
804 | if (ip_hdr->ih_flags_fragoff & HTONS(IH_DONT_FRAG))
|
---|
805 | {
|
---|
806 | req_mtu= bf_bufsize(pack);
|
---|
807 | if (req_mtu > next_port->ip_mtu ||
|
---|
808 | (iroute->irt_mtu && req_mtu>iroute->irt_mtu))
|
---|
809 | {
|
---|
810 | icmp_snd_mtu(ip_port->ip_port, pack,
|
---|
811 | next_port->ip_mtu);
|
---|
812 | continue;
|
---|
813 | }
|
---|
814 | }
|
---|
815 |
|
---|
816 | if (next_port != ip_port)
|
---|
817 | {
|
---|
818 | if (iroute->irt_gateway != 0)
|
---|
819 | {
|
---|
820 | /* Just send the packet to the next gateway */
|
---|
821 | pack->acc_linkC++; /* Extra ref for ICMP */
|
---|
822 | r= next_port->ip_dev_send(next_port,
|
---|
823 | iroute->irt_gateway,
|
---|
824 | pack, IP_LT_NORMAL);
|
---|
825 | if (r == EDSTNOTRCH)
|
---|
826 | {
|
---|
827 | printf("ip[%d]: gw ",
|
---|
828 | ip_port-ip_port_table);
|
---|
829 | writeIpAddr(iroute->irt_gateway);
|
---|
830 | printf(" on ip[%d] is down for dest ",
|
---|
831 | next_port-ip_port_table);
|
---|
832 | writeIpAddr(dest);
|
---|
833 | printf("\n");
|
---|
834 | icmp_snd_unreachable(next_port-
|
---|
835 | ip_port_table, pack,
|
---|
836 | ICMP_HOST_UNRCH);
|
---|
837 | pack= NULL;
|
---|
838 | }
|
---|
839 | else
|
---|
840 | {
|
---|
841 | assert(r == 0);
|
---|
842 | bf_afree(pack); pack= NULL;
|
---|
843 | }
|
---|
844 | continue;
|
---|
845 | }
|
---|
846 | /* The packet is for the attached network. Special
|
---|
847 | * addresses are the ip address of the interface and
|
---|
848 | * net.0 if no IP_42BSD_BCAST.
|
---|
849 | */
|
---|
850 | if (dest == next_port->ip_ipaddr)
|
---|
851 | {
|
---|
852 | ip_port_arrive (next_port, pack, ip_hdr);
|
---|
853 | continue;
|
---|
854 | }
|
---|
855 | if (dest == iroute->irt_dest)
|
---|
856 | {
|
---|
857 | /* Never forward obsolete directed broadcasts */
|
---|
858 | #if IP_42BSD_BCAST && 0
|
---|
859 | type= IP_LT_BROADCAST;
|
---|
860 | #else
|
---|
861 | /* Bogus destination address */
|
---|
862 | DBLOCK(1, printf(
|
---|
863 | "ip[%d]: dropping old-fashioned directed broadcast ",
|
---|
864 | ip_port-ip_port_table);
|
---|
865 | writeIpAddr(dest);
|
---|
866 | printf("\n"););
|
---|
867 | icmp_snd_unreachable(next_port-ip_port_table,
|
---|
868 | pack, ICMP_HOST_UNRCH);
|
---|
869 | continue;
|
---|
870 | #endif
|
---|
871 | }
|
---|
872 | else if (dest == (iroute->irt_dest |
|
---|
873 | ~iroute->irt_subnetmask))
|
---|
874 | {
|
---|
875 | if (!ip_forward_directed_bcast)
|
---|
876 | {
|
---|
877 | /* Do not forward directed broadcasts */
|
---|
878 | DBLOCK(1, printf(
|
---|
879 | "ip[%d]: dropping directed broadcast ",
|
---|
880 | ip_port-ip_port_table);
|
---|
881 | writeIpAddr(dest);
|
---|
882 | printf("\n"););
|
---|
883 | icmp_snd_unreachable(next_port-
|
---|
884 | ip_port_table, pack,
|
---|
885 | ICMP_HOST_UNRCH);
|
---|
886 | continue;
|
---|
887 | }
|
---|
888 | else
|
---|
889 | type= IP_LT_BROADCAST;
|
---|
890 | }
|
---|
891 | else
|
---|
892 | type= IP_LT_NORMAL;
|
---|
893 |
|
---|
894 | /* Just send the packet to it's destination */
|
---|
895 | pack->acc_linkC++; /* Extra ref for ICMP */
|
---|
896 | r= next_port->ip_dev_send(next_port, dest, pack, type);
|
---|
897 | if (r == EDSTNOTRCH)
|
---|
898 | {
|
---|
899 | DBLOCK(1, printf("ip[%d]: next hop ",
|
---|
900 | ip_port-ip_port_table);
|
---|
901 | writeIpAddr(dest);
|
---|
902 | printf(" on ip[%d] is down\n",
|
---|
903 | next_port-ip_port_table););
|
---|
904 | icmp_snd_unreachable(next_port-ip_port_table,
|
---|
905 | pack, ICMP_HOST_UNRCH);
|
---|
906 | pack= NULL;
|
---|
907 | }
|
---|
908 | else
|
---|
909 | {
|
---|
910 | assert(r == 0 || (printf("r = %d\n", r), 0));
|
---|
911 | bf_afree(pack); pack= NULL;
|
---|
912 | }
|
---|
913 | continue;
|
---|
914 | }
|
---|
915 |
|
---|
916 | /* Now we know that the packet should be routed over the same
|
---|
917 | * network as it came from. If there is a next hop gateway,
|
---|
918 | * we can send the packet to that gateway and send a redirect
|
---|
919 | * ICMP to the sender if the sender is on the attached
|
---|
920 | * network. If there is no gateway complain.
|
---|
921 | */
|
---|
922 | if (iroute->irt_gateway == 0)
|
---|
923 | {
|
---|
924 | printf("ip_arrived: packet should not be here, src=");
|
---|
925 | writeIpAddr(ip_hdr->ih_src);
|
---|
926 | printf(" dst=");
|
---|
927 | writeIpAddr(ip_hdr->ih_dst);
|
---|
928 | printf("\n");
|
---|
929 | bf_afree(pack);
|
---|
930 | continue;
|
---|
931 | }
|
---|
932 | if (((ip_hdr->ih_src ^ ip_port->ip_ipaddr) &
|
---|
933 | ip_port->ip_subnetmask) == 0)
|
---|
934 | {
|
---|
935 | /* Finding out if we can send a network redirect
|
---|
936 | * instead of a host redirect is too much trouble.
|
---|
937 | */
|
---|
938 | pack->acc_linkC++;
|
---|
939 | icmp_snd_redirect(ip_port->ip_port, pack,
|
---|
940 | ICMP_REDIRECT_HOST, iroute->irt_gateway);
|
---|
941 | }
|
---|
942 | else
|
---|
943 | {
|
---|
944 | printf("ip_arrived: packet is wrongly routed, src=");
|
---|
945 | writeIpAddr(ip_hdr->ih_src);
|
---|
946 | printf(" dst=");
|
---|
947 | writeIpAddr(ip_hdr->ih_dst);
|
---|
948 | printf("\n");
|
---|
949 | printf("in port %d, output %d, dest net ",
|
---|
950 | ip_port->ip_port,
|
---|
951 | iroute->irt_port);
|
---|
952 | writeIpAddr(iroute->irt_dest);
|
---|
953 | printf("/");
|
---|
954 | writeIpAddr(iroute->irt_subnetmask);
|
---|
955 | printf(" next hop ");
|
---|
956 | writeIpAddr(iroute->irt_gateway);
|
---|
957 | printf("\n");
|
---|
958 | bf_afree(pack);
|
---|
959 | continue;
|
---|
960 | }
|
---|
961 | /* No code for unreachable ICMPs here. The sender should
|
---|
962 | * process the ICMP redirect and figure it out.
|
---|
963 | */
|
---|
964 | ip_port->ip_dev_send(ip_port, iroute->irt_gateway, pack,
|
---|
965 | IP_LT_NORMAL);
|
---|
966 | }
|
---|
967 | }
|
---|
968 |
|
---|
969 | PRIVATE int broadcast_dst(ip_port, dest)
|
---|
970 | ip_port_t *ip_port;
|
---|
971 | ipaddr_t dest;
|
---|
972 | {
|
---|
973 | ipaddr_t my_ipaddr, netmask, classmask;
|
---|
974 |
|
---|
975 | /* Treat class D (multicast) address as broadcasts. */
|
---|
976 | if ((dest & HTONL(0xF0000000)) == HTONL(0xE0000000))
|
---|
977 | {
|
---|
978 | return 1;
|
---|
979 | }
|
---|
980 |
|
---|
981 | /* Accept without complaint if netmask not yet configured. */
|
---|
982 | if (!(ip_port->ip_flags & IPF_NETMASKSET))
|
---|
983 | {
|
---|
984 | return 1;
|
---|
985 | }
|
---|
986 | /* Two possibilities, 0 (iff IP_42BSD_BCAST) and -1 */
|
---|
987 | if (dest == HTONL((ipaddr_t)-1))
|
---|
988 | return 1;
|
---|
989 | #if IP_42BSD_BCAST
|
---|
990 | if (dest == HTONL((ipaddr_t)0))
|
---|
991 | return 1;
|
---|
992 | #endif
|
---|
993 | netmask= ip_port->ip_subnetmask;
|
---|
994 | my_ipaddr= ip_port->ip_ipaddr;
|
---|
995 |
|
---|
996 | if (((my_ipaddr ^ dest) & netmask) != 0)
|
---|
997 | {
|
---|
998 | classmask= ip_port->ip_classfulmask;
|
---|
999 |
|
---|
1000 | /* Not a subnet broadcast, maybe a classful broadcast */
|
---|
1001 | if (((my_ipaddr ^ dest) & classmask) != 0)
|
---|
1002 | {
|
---|
1003 | return 0;
|
---|
1004 | }
|
---|
1005 | /* Two possibilities, net.0 (iff IP_42BSD_BCAST) and net.-1 */
|
---|
1006 | if ((dest & ~classmask) == ~classmask)
|
---|
1007 | {
|
---|
1008 | return 1;
|
---|
1009 | }
|
---|
1010 | #if IP_42BSD_BCAST
|
---|
1011 | if ((dest & ~classmask) == 0)
|
---|
1012 | return 1;
|
---|
1013 | #endif
|
---|
1014 | return 0;
|
---|
1015 | }
|
---|
1016 |
|
---|
1017 | if (!(ip_port->ip_flags & IPF_SUBNET_BCAST))
|
---|
1018 | return 0; /* No subnet broadcasts on this network */
|
---|
1019 |
|
---|
1020 | /* Two possibilities, subnet.0 (iff IP_42BSD_BCAST) and subnet.-1 */
|
---|
1021 | if ((dest & ~netmask) == ~netmask)
|
---|
1022 | return 1;
|
---|
1023 | #if IP_42BSD_BCAST
|
---|
1024 | if ((dest & ~netmask) == 0)
|
---|
1025 | return 1;
|
---|
1026 | #endif
|
---|
1027 | return 0;
|
---|
1028 | }
|
---|
1029 |
|
---|
1030 | void ip_process_loopb(ev, arg)
|
---|
1031 | event_t *ev;
|
---|
1032 | ev_arg_t arg;
|
---|
1033 | {
|
---|
1034 | ip_port_t *ip_port;
|
---|
1035 | acc_t *pack;
|
---|
1036 |
|
---|
1037 | ip_port= arg.ev_ptr;
|
---|
1038 | assert(ev == &ip_port->ip_loopb_event);
|
---|
1039 |
|
---|
1040 | while(pack= ip_port->ip_loopb_head, pack != NULL)
|
---|
1041 | {
|
---|
1042 | ip_port->ip_loopb_head= pack->acc_ext_link;
|
---|
1043 | ip_arrived(ip_port, pack);
|
---|
1044 | }
|
---|
1045 | }
|
---|
1046 |
|
---|
1047 | /*
|
---|
1048 | * $PchId: ip_read.c,v 1.33 2005/06/28 14:18:50 philip Exp $
|
---|
1049 | */
|
---|