]> rtime.felk.cvut.cz Git - pes-rpp/rpp-lwip.git/blob - src/core/ipv4/ip.c
Fixed SYS_ARCH_PROTECT macros when NO_SYS is not defined.
[pes-rpp/rpp-lwip.git] / src / core / ipv4 / ip.c
1 /*
2  * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
3  * All rights reserved. 
4  * 
5  * Redistribution and use in source and binary forms, with or without modification, 
6  * are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  *    this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright notice,
11  *    this list of conditions and the following disclaimer in the documentation
12  *    and/or other materials provided with the distribution.
13  * 3. The name of the author may not be used to endorse or promote products
14  *    derived from this software without specific prior written permission. 
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
19  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
21  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
24  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
25  * OF SUCH DAMAGE.
26  *
27  * This file is part of the lwIP TCP/IP stack.
28  * 
29  * Author: Adam Dunkels <adam@sics.se>
30  *
31  */
32
33
34 /*-----------------------------------------------------------------------------------*/
35 /* ip.c
36  *
37  * This is the code for the IP layer.
38  *
39  */   
40 /*-----------------------------------------------------------------------------------*/
41
42 #include "lwip/debug.h"
43
44 #include "lwip/def.h"
45 #include "lwip/mem.h"
46 #include "lwip/ip.h"
47 #include "lwip/ip_frag.h"
48 #include "lwip/inet.h"
49 #include "lwip/netif.h"
50 #include "lwip/icmp.h"
51 #include "lwip/udp.h"
52 #include "lwip/tcp.h"
53
54 #include "lwip/stats.h"
55
56 #include "arch/perf.h"
57
58 #include "lwip/snmp.h"
59 #if LWIP_DHCP
60 #include "lwip/dhcp.h"
61 #endif /* LWIP_DHCP */
62
63 /*-----------------------------------------------------------------------------------*/
64 /* ip_init:
65  *
66  * Initializes the IP layer.
67  */
68 /*-----------------------------------------------------------------------------------*/
69 void
70 ip_init(void)
71 {
72 }
73 /*-----------------------------------------------------------------------------------*/
74 /* ip_lookup:
75  *
76  * An experimental feature that will be changed in future versions. Do
77  * not depend on it yet...
78  */
79 /*-----------------------------------------------------------------------------------*/
80 #ifdef LWIP_DEBUG
81 u8_t
82 ip_lookup(void *header, struct netif *inp)
83 {
84   struct ip_hdr *iphdr;
85
86   iphdr = header;
87
88   /* not IP v4? */
89   if(IPH_V(iphdr) != 4) {
90     return 0;
91   }
92
93   /* Immediately accept/decline packets that are fragments or has
94      options. */
95 #if IP_REASSEMBLY == 0
96   /*  if((IPH_OFFSET(iphdr) & htons(IP_OFFMASK | IP_MF)) != 0) {
97     return 0;
98     }*/
99 #endif /* IP_REASSEMBLY == 0 */
100
101 #if IP_OPTIONS == 0
102   if(IPH_HL(iphdr) != 5) {
103     return 0;
104   }
105 #endif /* IP_OPTIONS == 0 */
106   
107   switch(IPH_PROTO(iphdr)) {
108 #if LWIP_UDP > 0
109   case IP_PROTO_UDP:
110     return udp_lookup(iphdr, inp);
111 #endif /* LWIP_UDP */
112 #if LWIP_TCP > 0    
113   case IP_PROTO_TCP:
114     return 1;
115 #endif /* LWIP_TCP */
116   case IP_PROTO_ICMP:
117     return 1;
118   default:
119     return 0;
120   }
121 }
122 #endif /* LWIP_DEBUG */
123 /*-----------------------------------------------------------------------------------*/
124 /* ip_route:
125  *
126  * Finds the appropriate network interface for a given IP address. It
127  * searches the list of network interfaces linearly. A match is found
128  * if the masked IP address of the network interface equals the masked
129  * IP address given to the function.
130  */
131 /*-----------------------------------------------------------------------------------*/
132 struct netif *
133 ip_route(struct ip_addr *dest)
134 {
135   struct netif *netif;
136
137   /* iterate through netifs */  
138   for(netif = netif_list; netif != NULL; netif = netif->next) {
139     /* network mask matches? */
140     if(ip_addr_maskcmp(dest, &(netif->ip_addr), &(netif->netmask))) {
141       /* return netif on which to forward IP packet */
142       return netif;
143     }
144   }
145   /* no matching netif found, use default netif */
146   return netif_default;
147 }
148 #if IP_FORWARD
149 /*-----------------------------------------------------------------------------------*/
150 /* ip_forward:
151  *
152  * Forwards an IP packet. It finds an appropriate route for the
153  * packet, decrements the TTL value of the packet, adjusts the
154  * checksum and outputs the packet on the appropriate interface.
155  */
156 /*-----------------------------------------------------------------------------------*/
157 static void
158 ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp)
159 {
160   struct netif *netif;
161   
162   PERF_START;
163   /* Find network interface where to forward this IP packet to. */
164   netif = ip_route((struct ip_addr *)&(iphdr->dest));
165   if(netif == NULL) {
166     DEBUGF(IP_DEBUG, ("ip_forward: no forwarding route for 0x%lx found\n",
167                       iphdr->dest.addr));
168     snmp_inc_ipnoroutes();
169     return;
170   }
171   /* Do not forward packets onto the same network interface on which
172      they arrived. */
173   if(netif == inp) {
174     DEBUGF(IP_DEBUG, ("ip_forward: not bouncing packets back on incoming interface.\n"));
175     snmp_inc_ipnoroutes();
176     return;
177   }
178   
179   /* decrement TTL */
180   IPH_TTL_SET(iphdr, IPH_TTL(iphdr) - 1);
181   /* send ICMP if TTL == 0 */
182   if(IPH_TTL(iphdr) == 0) {
183     /* Don't send ICMP messages in response to ICMP messages */
184     if(IPH_PROTO(iphdr) != IP_PROTO_ICMP) {
185       icmp_time_exceeded(p, ICMP_TE_TTL);
186       snmp_inc_icmpouttimeexcds();
187     }
188     return;       
189   }
190   
191   /* Incrementally update the IP checksum. */
192   if(IPH_CHKSUM(iphdr) >= htons(0xffff - 0x100)) {
193     IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + htons(0x100) + 1);
194   } else {
195     IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + htons(0x100));
196   }
197
198   DEBUGF(IP_DEBUG, ("ip_forward: forwarding packet to 0x%lx\n",
199                     iphdr->dest.addr));
200
201 #ifdef IP_STATS
202   ++lwip_stats.ip.fw;
203   ++lwip_stats.ip.xmit;
204 #endif /* IP_STATS */
205     snmp_inc_ipforwdatagrams();
206
207   PERF_STOP("ip_forward");
208   /* transmit pbuf on chosen interface */
209   netif->output(netif, p, (struct ip_addr *)&(iphdr->dest));
210 }
211 #endif /* IP_FORWARD */
212 /*-----------------------------------------------------------------------------------*/
213 /* ip_input:
214  *
215  * This function is called by the network interface device driver when
216  * an IP packet is received. The function does the basic checks of the
217  * IP header such as packet size being at least larger than the header
218  * size etc. If the packet was not destined for us, the packet is
219  * forwarded (using ip_forward). The IP checksum is always checked.
220  *
221  * Finally, the packet is sent to the upper layer protocol input function.
222  */
223 /*-----------------------------------------------------------------------------------*/
224 err_t
225 ip_input(struct pbuf *p, struct netif *inp) {
226   static struct ip_hdr *iphdr;
227   static struct netif *netif;
228   static u16_t iphdrlen;
229   
230 #ifdef IP_STATS
231   ++lwip_stats.ip.recv;
232 #endif /* IP_STATS */
233   snmp_inc_ipinreceives();
234
235   /* identify the IP header */
236   iphdr = p->payload;
237   if(IPH_V(iphdr) != 4) {
238     DEBUGF(IP_DEBUG, ("IP packet dropped due to bad version number %d\n", IPH_V(iphdr)));
239 #if IP_DEBUG
240     ip_debug_print(p);
241 #endif /* IP_DEBUG */
242     pbuf_free(p);
243 #ifdef IP_STATS
244     ++lwip_stats.ip.err;
245     ++lwip_stats.ip.drop;
246 #endif /* IP_STATS */
247     snmp_inc_ipunknownprotos();
248     return ERR_OK;
249   }
250   /* obtain IP header length in number of 32-bit words */
251   iphdrlen = IPH_HL(iphdr);
252   /* calculate IP header length in bytes */
253   iphdrlen *= 4;
254
255   /* header length exceeds first pbuf length? */  
256   if(iphdrlen > p->len) {
257     DEBUGF(IP_DEBUG, ("IP header (len %u) does not fit in first pbuf (len %u), IP packet droppped.\n",
258       iphdrlen, p->len));
259     /* free (drop) packet pbufs */
260     pbuf_free(p);
261 #ifdef IP_STATS
262     ++lwip_stats.ip.lenerr;
263     ++lwip_stats.ip.drop;
264 #endif /* IP_STATS */
265     snmp_inc_ipindiscards();
266     return ERR_OK;
267   }
268
269   /* verify checksum */
270   if(inet_chksum(iphdr, iphdrlen) != 0) {
271
272     DEBUGF(IP_DEBUG, ("Checksum (0x%x) failed, IP packet dropped.\n", inet_chksum(iphdr, iphdrlen)));
273 #if IP_DEBUG
274     ip_debug_print(p);
275 #endif /* IP_DEBUG */
276     pbuf_free(p);
277 #ifdef IP_STATS
278     ++lwip_stats.ip.chkerr;
279     ++lwip_stats.ip.drop;
280 #endif /* IP_STATS */
281     snmp_inc_ipindiscards();
282     return ERR_OK;
283   }
284   
285   /* Trim pbuf. This should have been done at the netif layer,
286      but we'll do it anyway just to be sure that its done. */
287   pbuf_realloc(p, ntohs(IPH_LEN(iphdr)));
288
289   /* is this packet for us? */
290   for(netif = netif_list; netif != NULL; netif = netif->next) {
291
292     DEBUGF(IP_DEBUG, ("ip_input: iphdr->dest 0x%lx netif->ip_addr 0x%lx (0x%lx, 0x%lx, 0x%lx)\n",
293                       iphdr->dest.addr, netif->ip_addr.addr,
294                       iphdr->dest.addr & netif->netmask.addr,
295                       netif->ip_addr.addr & netif->netmask.addr,
296                       iphdr->dest.addr & ~(netif->netmask.addr)));
297
298     /* interface configured? */
299     if(!ip_addr_isany(&(netif->ip_addr)))
300     {
301       /* unicast to this interface address? */
302       if(ip_addr_cmp(&(iphdr->dest), &(netif->ip_addr)) ||
303         /* or broadcast matching this interface network address? */
304         (ip_addr_isbroadcast(&(iphdr->dest), &(netif->netmask)) &&
305          ip_addr_maskcmp(&(iphdr->dest), &(netif->ip_addr), &(netif->netmask))) ||
306          /* or restricted broadcast? */
307          ip_addr_cmp(&(iphdr->dest), IP_ADDR_BROADCAST)) {
308          DEBUGF(IP_DEBUG, ("ip_input: packet accepted on interface %c%c\n",
309                        netif->name[0], netif->name[1]));
310          /* break out of for loop */
311          break;
312       }
313     }
314   }
315 #if LWIP_DHCP
316   /* Pass DHCP messages regardless of destination address. DHCP traffic is addressed
317      using link layer addressing (such as Ethernet MAC) so we must not filter on IP.
318      According to RFC 1542 section 3.1.1, referred by RFC 2131). */
319   if(netif == NULL) {
320     /* remote port is DHCP server? */
321     if(IPH_PROTO(iphdr) == IP_PROTO_UDP) {
322       DEBUGF(IP_DEBUG, ("ip_input: UDP packet to DHCP client port %u\n",
323        ntohs(((struct udp_hdr *)((u8_t *)iphdr + iphdrlen))->dest)));
324       if (ntohs(((struct udp_hdr *)((u8_t *)iphdr + iphdrlen))->dest) == DHCP_CLIENT_PORT) {
325         DEBUGF(IP_DEBUG, ("ip_input: DHCP packet accepted.\n"));
326         netif = inp;
327       }
328     }
329   }
330 #endif /* LWIP_DHCP */
331         /* packet not for us? */  
332   if(netif == NULL) {
333     /* packet not for us, route or discard */
334     DEBUGF(IP_DEBUG, ("ip_input: packet not for us.\n"));
335 #if IP_FORWARD
336     /* non-broadcast packet? */
337     if(!ip_addr_isbroadcast(&(iphdr->dest), &(inp->netmask))) {
338       /* try to forward IP packet on (other) interfaces */
339       ip_forward(p, iphdr, inp);
340     }
341     else
342 #endif /* IP_FORWARD */
343     {
344       snmp_inc_ipindiscards();
345     }
346     pbuf_free(p);
347     return ERR_OK;
348   }
349
350 #if IP_REASSEMBLY
351   if((IPH_OFFSET(iphdr) & htons(IP_OFFMASK | IP_MF)) != 0) {
352     DEBUGF(IP_DEBUG, ("IP packet is a fragment (id=0x%04x tot_len=%u len=%u MF=%u offset=%u), calling ip_reass()\n", ntohs(IPH_ID(iphdr)), p->tot_len, ntohs(IPH_LEN(iphdr)), !!(IPH_OFFSET(iphdr) & htons(IP_MF)), (ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK)*8));
353     p = ip_reass(p);
354     if(p == NULL) {
355       return ERR_OK;
356     }
357     iphdr = p->payload;
358   }
359 #else /* IP_REASSEMBLY */
360   if((IPH_OFFSET(iphdr) & htons(IP_OFFMASK | IP_MF)) != 0) {
361     pbuf_free(p);
362     DEBUGF(IP_DEBUG, ("IP packet dropped since it was fragmented (0x%x) (while IP_REASSEMBLY == 0).\n",
363                   ntohs(IPH_OFFSET(iphdr))));
364 #ifdef IP_STATS
365     ++lwip_stats.ip.opterr;
366     ++lwip_stats.ip.drop;
367 #endif /* IP_STATS */
368     snmp_inc_ipunknownprotos();
369     return ERR_OK;
370   }
371 #endif /* IP_REASSEMBLY */
372   
373 #if IP_OPTIONS == 0
374   if(iphdrlen > IP_HLEN) {
375     DEBUGF(IP_DEBUG, ("IP packet dropped since there were IP options (while IP_OPTIONS == 0).\n"));
376     pbuf_free(p);    
377 #ifdef IP_STATS
378     ++lwip_stats.ip.opterr;
379     ++lwip_stats.ip.drop;
380 #endif /* IP_STATS */
381     snmp_inc_ipunknownprotos();
382     return ERR_OK;
383   }  
384 #endif /* IP_OPTIONS == 0 */
385
386   /* send to upper layers */
387 #if IP_DEBUG
388   DEBUGF(IP_DEBUG, ("ip_input: \n"));
389   ip_debug_print(p);
390   DEBUGF(IP_DEBUG, ("ip_input: p->len %d p->tot_len %d\n", p->len, p->tot_len));
391 #endif /* IP_DEBUG */   
392
393   switch(IPH_PROTO(iphdr)) {
394 #if LWIP_UDP > 0    
395   case IP_PROTO_UDP:
396     snmp_inc_ipindelivers();
397     udp_input(p, inp);
398     break;
399 #endif /* LWIP_UDP */
400 #if LWIP_TCP > 0    
401   case IP_PROTO_TCP:
402     snmp_inc_ipindelivers();
403     tcp_input(p, inp);
404     break;
405 #endif /* LWIP_TCP */
406   case IP_PROTO_ICMP:
407     snmp_inc_ipindelivers();
408     icmp_input(p, inp);
409     break;
410   default:
411     /* send ICMP destination protocol unreachable unless is was a broadcast */
412     if(!ip_addr_isbroadcast(&(iphdr->dest), &(inp->netmask)) &&
413        !ip_addr_ismulticast(&(iphdr->dest))) {
414       p->payload = iphdr;
415       icmp_dest_unreach(p, ICMP_DUR_PROTO);
416     }
417     pbuf_free(p);
418
419     DEBUGF(IP_DEBUG, ("Unsupported transportation protocol %d\n", IPH_PROTO(iphdr)));
420
421 #ifdef IP_STATS
422     ++lwip_stats.ip.proterr;
423     ++lwip_stats.ip.drop;
424 #endif /* IP_STATS */
425     snmp_inc_ipunknownprotos();
426
427   }
428   return ERR_OK;
429 }
430
431 /*-----------------------------------------------------------------------------------*/
432 /* ip_output_if:
433  *
434  * Sends an IP packet on a network interface. This function constructs
435  * the IP header and calculates the IP header checksum. If the source
436  * IP address is NULL, the IP address of the outgoing network
437  * interface is filled in as source address.
438  */
439 /*-----------------------------------------------------------------------------------*/
440 err_t
441 ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
442              u8_t ttl,
443              u8_t proto, struct netif *netif)
444 {
445   static struct ip_hdr *iphdr;
446   static u16_t ip_id = 0;
447
448   snmp_inc_ipoutrequests();
449   
450   if(dest != IP_HDRINCL) {
451     if(pbuf_header(p, IP_HLEN)) {
452       DEBUGF(IP_DEBUG, ("ip_output: not enough room for IP header in pbuf\n"));
453       
454 #ifdef IP_STATS
455       ++lwip_stats.ip.err;
456 #endif /* IP_STATS */
457       snmp_inc_ipoutdiscards();
458       return ERR_BUF;
459     }
460     
461     iphdr = p->payload;
462     
463     IPH_TTL_SET(iphdr, ttl);
464     IPH_PROTO_SET(iphdr, proto);
465     
466     ip_addr_set(&(iphdr->dest), dest);
467
468     IPH_VHLTOS_SET(iphdr, 4, IP_HLEN / 4, 0);
469     IPH_LEN_SET(iphdr, htons(p->tot_len));
470     IPH_OFFSET_SET(iphdr, htons(IP_DF));
471     IPH_ID_SET(iphdr, htons(ip_id));
472     ++ip_id;
473
474     if(ip_addr_isany(src)) {
475       ip_addr_set(&(iphdr->src), &(netif->ip_addr));
476     } else {
477       ip_addr_set(&(iphdr->src), src);
478     }
479
480     IPH_CHKSUM_SET(iphdr, 0);
481     IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
482   } else {
483     iphdr = p->payload;
484     dest = &(iphdr->dest);
485   }
486
487 #if IP_FRAG     
488   /* don't fragment if interface has mtu set to 0 [loopif] */
489   if (netif->mtu && (p->tot_len > netif->mtu))
490     return ip_frag(p,netif,dest);
491 #endif
492   
493 #ifdef IP_STATS
494   lwip_stats.ip.xmit++;
495 #endif /* IP_STATS */
496   DEBUGF(IP_DEBUG, ("ip_output_if: %c%c ", netif->name[0], netif->name[1]));
497 #if IP_DEBUG
498   ip_debug_print(p);
499 #endif /* IP_DEBUG */
500
501   DEBUGF(IP_DEBUG, ("netif->output()"));
502
503   return netif->output(netif, p, dest);  
504 }
505 /*-----------------------------------------------------------------------------------*/
506 /* ip_output:
507  *
508  * Simple interface to ip_output_if. It finds the outgoing network
509  * interface and calls upon ip_output_if to do the actual work.
510  */
511 /*-----------------------------------------------------------------------------------*/
512 err_t
513 ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
514           u8_t ttl, u8_t proto)
515 {
516   struct netif *netif;
517   
518   if((netif = ip_route(dest)) == NULL) {
519     DEBUGF(IP_DEBUG, ("ip_output: No route to 0x%lx\n", dest->addr));
520
521 #ifdef IP_STATS
522     ++lwip_stats.ip.rterr;
523 #endif /* IP_STATS */
524     snmp_inc_ipoutdiscards();
525     return ERR_RTE;
526   }
527
528   return ip_output_if(p, src, dest, ttl, proto, netif);
529 }
530 /*-----------------------------------------------------------------------------------*/
531 #if IP_DEBUG
532 void
533 ip_debug_print(struct pbuf *p)
534 {
535   struct ip_hdr *iphdr = p->payload;
536   u8_t *payload;
537
538   payload = (u8_t *)iphdr + IP_HLEN;
539   
540   DEBUGF(IP_DEBUG, ("IP header:\n"));
541   DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
542   DEBUGF(IP_DEBUG, ("|%2d |%2d |   %2u  |      %4u     | (v, hl, tos, len)\n",
543                     IPH_V(iphdr),
544                     IPH_HL(iphdr),
545                     IPH_TOS(iphdr),
546                     ntohs(IPH_LEN(iphdr))));
547   DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
548   DEBUGF(IP_DEBUG, ("|    %5u      |%u%u%u|    %4u   | (id, flags, offset)\n",
549                     ntohs(IPH_ID(iphdr)),
550                     ntohs(IPH_OFFSET(iphdr)) >> 15 & 1,
551                     ntohs(IPH_OFFSET(iphdr)) >> 14 & 1,
552                     ntohs(IPH_OFFSET(iphdr)) >> 13 & 1,
553                     ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK));
554   DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
555   DEBUGF(IP_DEBUG, ("|   %2u  |   %2u  |    0x%04x     | (ttl, proto, chksum)\n",
556                     IPH_TTL(iphdr),
557                     IPH_PROTO(iphdr),
558                     ntohs(IPH_CHKSUM(iphdr))));
559   DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
560   DEBUGF(IP_DEBUG, ("|  %3ld  |  %3ld  |  %3ld  |  %3ld  | (src)\n",
561                     ntohl(iphdr->src.addr) >> 24 & 0xff,
562                     ntohl(iphdr->src.addr) >> 16 & 0xff,
563                     ntohl(iphdr->src.addr) >> 8 & 0xff,
564                     ntohl(iphdr->src.addr) & 0xff));
565   DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
566   DEBUGF(IP_DEBUG, ("|  %3ld  |  %3ld  |  %3ld  |  %3ld  | (dest)\n",
567                     ntohl(iphdr->dest.addr) >> 24 & 0xff,
568                     ntohl(iphdr->dest.addr) >> 16 & 0xff,
569                     ntohl(iphdr->dest.addr) >> 8 & 0xff,
570                     ntohl(iphdr->dest.addr) & 0xff));
571   DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
572 }
573 #endif /* IP_DEBUG */
574 /*-----------------------------------------------------------------------------------*/
575
576
577
578
579