fix for corrupted graphics when manipulating config files
[open-ps2-loader.git] / modules / network / SMSTCPIP / ip.c
blobc1c860ec486383cb682060c775f80148157e2b32
1 /*
2 * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
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.
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.
27 * This file is part of the lwIP TCP/IP stack.
29 * Author: Adam Dunkels <adam@sics.se>
35 /* ip.c
37 * This is the code for the IP layer.
42 #include "lwip/opt.h"
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/raw.h"
53 #include "lwip/udp.h"
54 #include "lwip/tcp.h"
56 #include "lwip/stats.h"
58 #include "lwip/snmp.h"
59 #if LWIP_DHCP
60 # include "lwip/dhcp.h"
61 #endif /* LWIP_DHCP */
64 /* ip_init:
66 * Initializes the IP layer.
69 void
70 ip_init(void)
74 /* ip_lookup:
76 * An experimental feature that will be changed in future versions. Do
77 * not depend on it yet...
80 #ifdef LWIP_DEBUG
81 u8_t
82 ip_lookup(void *header, struct netif *inp)
84 struct ip_hdr *iphdr;
86 iphdr = header;
88 /* not IP v4? */
89 if (IPH_V(iphdr) != 4) {
90 return 0;
93 #if IP_OPTIONS == 0
94 if (IPH_HL(iphdr) != 5) {
95 return 0;
97 #endif /* IP_OPTIONS == 0 */
99 switch (IPH_PROTO(iphdr)) {
100 #if LWIP_UDP
101 case IP_PROTO_UDP:
102 case IP_PROTO_UDPLITE:
103 return udp_lookup(iphdr, inp);
104 #endif /* LWIP_UDP */
105 #if LWIP_TCP
106 case IP_PROTO_TCP:
107 return 1;
108 #endif /* LWIP_TCP */
109 case IP_PROTO_ICMP:
110 return 1;
111 default:
112 return 0;
115 #endif /* LWIP_DEBUG */
117 /* ip_route:
119 * Finds the appropriate network interface for a given IP address. It
120 * searches the list of network interfaces linearly. A match is found
121 * if the masked IP address of the network interface equals the masked
122 * IP address given to the function.
125 struct netif *
126 ip_route(struct ip_addr *dest)
128 struct netif *netif;
130 /* iterate through netifs */
131 for(netif = netif_list; netif != NULL; netif = netif->next) {
132 /* network mask matches? */
133 if (ip_addr_maskcmp(dest, &(netif->ip_addr), &(netif->netmask))) {
134 /* return netif on which to forward IP packet */
135 return netif;
138 /* no matching netif found, use default netif */
139 return netif_default;
141 #if IP_FORWARD
143 /* ip_forward:
145 * Forwards an IP packet. It finds an appropriate route for the
146 * packet, decrements the TTL value of the packet, adjusts the
147 * checksum and outputs the packet on the appropriate interface.
150 static void
151 ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp)
153 struct netif *netif;
155 PERF_START;
156 /* Find network interface where to forward this IP packet to. */
157 netif = ip_route((struct ip_addr *)&(iphdr->dest));
158 if (netif == NULL) {
159 LWIP_DEBUGF(IP_DEBUG, ("ip_forward: no forwarding route for 0x%lx found\n",
160 iphdr->dest.addr));
161 snmp_inc_ipnoroutes();
162 return;
164 /* Do not forward packets onto the same network interface on which
165 they arrived. */
166 if (netif == inp) {
167 LWIP_DEBUGF(IP_DEBUG, ("ip_forward: not bouncing packets back on incoming interface.\n"));
168 snmp_inc_ipnoroutes();
169 return;
172 /* decrement TTL */
173 IPH_TTL_SET(iphdr, IPH_TTL(iphdr) - 1);
174 /* send ICMP if TTL == 0 */
175 if (IPH_TTL(iphdr) == 0) {
176 /* Don't send ICMP messages in response to ICMP messages */
177 if (IPH_PROTO(iphdr) != IP_PROTO_ICMP) {
178 icmp_time_exceeded(p, ICMP_TE_TTL);
179 snmp_inc_icmpouttimeexcds();
181 return;
183 /* Incrementally update the IP checksum. */
184 if (IPH_CHKSUM(iphdr) >= htons(0xffff - 0x100)) {
185 IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + 2 );
186 } else {
187 IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + 1 );
190 LWIP_DEBUGF(IP_DEBUG, ("ip_forward: forwarding packet to 0x%lx\n",
191 iphdr->dest.addr));
193 IP_STATS_INC(ip.fw);
194 IP_STATS_INC(ip.xmit);
195 snmp_inc_ipforwdatagrams();
197 PERF_STOP("ip_forward");
198 /* transmit pbuf on chosen interface */
199 netif->output(netif, p, (struct ip_addr *)&(iphdr->dest));
201 #endif /* IP_FORWARD */
203 /* ip_input:
205 * This function is called by the network interface device driver when
206 * an IP packet is received. The function does the basic checks of the
207 * IP header such as packet size being at least larger than the header
208 * size etc. If the packet was not destined for us, the packet is
209 * forwarded (using ip_forward). The IP checksum is always checked.
211 * Finally, the packet is sent to the upper layer protocol input function.
213 err_t ip_input ( struct pbuf* p, struct netif* inp ) {
215 static struct ip_hdr* iphdr;
216 static struct netif* netif;
217 static u16_t iphdrlen;
219 iphdr = p -> payload;
221 if ( IPH_V( iphdr ) != 4 ) {
222 pbuf_free ( p );
223 return ERR_OK;
224 } /* end if */
226 iphdrlen = IPH_HL( iphdr );
227 iphdrlen *= 4;
229 if ( iphdrlen > p -> len ) {
230 pbuf_free ( p );
231 return ERR_OK;
232 } /* end if */
234 if ( inet_chksum ( iphdr, iphdrlen ) ) {
235 pbuf_free(p);
236 return ERR_OK;
237 } /* end if */
239 pbuf_realloc ( p, ntohs ( IPH_LEN( iphdr ) ) );
241 for ( netif = netif_list; netif; netif = netif -> next )
243 if ( !ip_addr_isany ( &netif -> ip_addr ) ) {
245 if ( ip_addr_cmp ( &iphdr -> dest, &netif -> ip_addr ) || (
246 ip_addr_isbroadcast ( &iphdr -> dest, &netif -> netmask ) &&
247 ip_addr_maskcmp ( &iphdr -> dest, &netif -> ip_addr, &netif -> netmask )
248 ) || ip_addr_cmp ( &iphdr -> dest, IP_ADDR_BROADCAST )
249 ) break;
251 } /* end if */
252 #if LWIP_DHCP
253 if ( !netif ) {
254 if ( IPH_PROTO( iphdr ) == IP_PROTO_UDP ) {
255 if ( ntohs (
256 ( ( struct udp_hdr* )( ( u8_t* )iphdr + iphdrlen ) ) -> dest
257 ) == DHCP_CLIENT_PORT
258 ) netif = inp;
259 } /* end if */
260 } /* end if */
261 #endif /* LWIP_DHCP */
262 if ( !netif ) {
263 #if IP_FORWARD
264 if ( !ip_addr_isbroadcast ( &iphdr -> dest, &inp -> netmask ) ) ip_forward ( p, iphdr, inp );
265 #endif /* IP_FORWARD */
266 pbuf_free ( p );
267 return ERR_OK;
268 } /* end if */
269 #if IP_REASSEMBLY
270 if ( ( IPH_OFFSET( iphdr ) & 0xFF3F ) != 0 ) {
271 p = ip_reass ( p );
272 if ( p == NULL ) return ERR_OK;
273 iphdr = p -> payload;
274 } /* end if */
275 #else /* IP_REASSEMBLY */
276 if ( ( IPH_OFFSET( iphdr ) & 0xFF3F ) != 0 ) {
277 pbuf_free ( p );
278 return ERR_OK;
279 } /* end if */
280 #endif /* IP_REASSEMBLY */
281 #if IP_OPTIONS == 0
282 if (iphdrlen > IP_HLEN) {
283 LWIP_DEBUGF(IP_DEBUG | 2, ("IP packet dropped since there were IP options (while IP_OPTIONS == 0).\n"));
284 pbuf_free(p);
285 IP_STATS_INC(ip.opterr);
286 IP_STATS_INC(ip.drop);
287 snmp_inc_ipunknownprotos();
288 return ERR_OK;
290 #endif /* IP_OPTIONS == 0 */
291 #if LWIP_RAW
292 if (!raw_input(p, inp)) {
293 #endif /* LWIP_RAW */
295 switch (IPH_PROTO(iphdr)) {
296 #if LWIP_UDP
297 case IP_PROTO_UDP:
298 case IP_PROTO_UDPLITE:
299 snmp_inc_ipindelivers();
300 udp_input(p, inp);
301 break;
302 #endif /* LWIP_UDP */
303 #if LWIP_TCP
304 case IP_PROTO_TCP:
305 snmp_inc_ipindelivers();
306 tcp_input(p, inp);
307 break;
308 #endif /* LWIP_TCP */
309 case IP_PROTO_ICMP:
310 snmp_inc_ipindelivers();
311 icmp_input(p, inp);
312 break;
313 default:
314 /* send ICMP destination protocol unreachable unless is was a broadcast */
315 if (!ip_addr_isbroadcast(&(iphdr->dest), &(inp->netmask)) &&
316 !ip_addr_ismulticast(&(iphdr->dest))) {
317 p->payload = iphdr;
318 icmp_dest_unreach(p, ICMP_DUR_PROTO);
320 pbuf_free(p);
323 #if LWIP_RAW
324 } /* LWIP_RAW */
325 #endif
326 return ERR_OK;
330 /* ip_output_if:
332 * Sends an IP packet on a network interface. This function constructs
333 * the IP header and calculates the IP header checksum. If the source
334 * IP address is NULL, the IP address of the outgoing network
335 * interface is filled in as source address.
338 err_t
339 ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
340 u8_t ttl, u8_t tos,
341 u8_t proto, struct netif *netif)
343 static struct ip_hdr *iphdr;
344 static u16_t ip_id = 0;
346 snmp_inc_ipoutrequests();
348 if (dest != IP_HDRINCL) {
349 if (pbuf_header(p, IP_HLEN)) {
350 LWIP_DEBUGF(IP_DEBUG | 2, ("ip_output: not enough room for IP header in pbuf\n"));
352 IP_STATS_INC(ip.err);
353 snmp_inc_ipoutdiscards();
354 return ERR_BUF;
357 iphdr = p->payload;
359 IPH_TTL_SET(iphdr, ttl);
360 IPH_PROTO_SET(iphdr, proto);
362 ip_addr_set(&(iphdr->dest), dest);
364 IPH_VHLTOS_SET(iphdr, 4, IP_HLEN / 4, tos);
365 IPH_LEN_SET(iphdr, htons(p->tot_len));
366 IPH_OFFSET_SET(iphdr, 0x0040);
367 IPH_ID_SET(iphdr, htons(ip_id));
368 ++ip_id;
370 if (ip_addr_isany(src)) {
371 ip_addr_set(&(iphdr->src), &(netif->ip_addr));
372 } else {
373 ip_addr_set(&(iphdr->src), src);
376 IPH_CHKSUM_SET(iphdr, 0);
377 IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
378 } else {
379 iphdr = p->payload;
380 dest = &(iphdr->dest);
383 #if IP_FRAG
384 /* don't fragment if interface has mtu set to 0 [loopif] */
385 if (netif->mtu && (p->tot_len > netif->mtu))
386 return ip_frag(p,netif,dest);
387 #endif
388 return netif->output(netif, p, dest);
390 /* ip_output:
392 * Simple interface to ip_output_if. It finds the outgoing network
393 * interface and calls upon ip_output_if to do the actual work.
395 err_t ip_output ( struct pbuf* p, struct ip_addr* src, struct ip_addr* dest, u8_t ttl, u8_t tos, u8_t proto ) {
397 struct netif *netif;
399 if ( !( netif = ip_route ( dest ) ) ) return ERR_RTE;
401 return ip_output_if ( p, src, dest, ttl, tos, proto, netif );
403 } /* end ip_output */