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