Disabling auto-refresh of game list by default, as it is causing bugs sometimes
[open-ps2-loader.git] / modules / network / SMSTCPIP / ip_frag.c
bloba1e5308f0e59d4ca98c1792f8439fc849cee735b
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:
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: Jani Monoses <jani@iv.ro>
30 * original reassembly code by Adam Dunkels <adam@sics.se>
35 /* ip_frag.c
37 * This is the code for IP segmentation and reassembly
42 #include "lwip/opt.h"
43 #include "lwip/sys.h"
44 #include "lwip/ip.h"
45 #include "lwip/ip_frag.h"
46 #include "lwip/netif.h"
48 #include "lwip/stats.h"
50 #include <sysclib.h>
51 #include <thbase.h>
53 #include "smsutils.h"
56 * Copy len bytes from offset in pbuf to buffer
58 * helper used by both ip_reass and ip_frag
60 static struct pbuf* copy_from_pbuf (
61 struct pbuf *p, u16_t * offset, u8_t * buffer, u16_t len
62 ) {
64 u16_t l = 0;
66 p -> payload = ( u8_t* )p -> payload + *offset;
67 p -> len -= *offset;
69 for ( ; len; p = p -> next ) {
70 l = len < p -> len ? len : p -> len;
71 mips_memcpy ( buffer, p -> payload, l );
72 buffer += l;
73 len -= l;
74 } /* end while */
76 *offset = l;
78 return p;
80 } /* end copy_from_pbuf */
82 #define IP_REASS_BUFSIZE 5760
83 #define IP_REASS_MAXAGE 30
84 #define IP_REASS_TMO 250
86 static iop_sys_clock_t s_Clock = {
87 0x01194000, 0x00000000
90 static u8_t ip_reassbuf[IP_HLEN + IP_REASS_BUFSIZE];
91 static u8_t ip_reassbitmap[IP_REASS_BUFSIZE / (8 * 8)];
93 static const u8_t bitmap_bits[ 8 ] = {
94 0xFF, 0x7F, 0x3F, 0x1F,
95 0x0F, 0x07, 0x03, 0x01
98 static u16_t ip_reasslen;
99 static u8_t ip_reassflags;
101 #define IP_REASS_FLAG_LASTFRAG 0x01
103 static u8_t ip_reasstmr;
105 static unsigned ip_reass_timer ( void* apArg ) {
107 iop_sys_clock_t* lpClock = ( iop_sys_clock_t* )apArg;
109 if ( ip_reasstmr ) {
110 --ip_reasstmr;
111 return lpClock -> lo;
112 } else return 0;
114 } /* end ip_reass_timer */
116 struct pbuf *
117 ip_reass(struct pbuf *p)
119 struct pbuf *q;
120 struct ip_hdr *fraghdr, *iphdr;
121 u16_t offset, len;
122 u16_t i;
124 iphdr = (struct ip_hdr *) ip_reassbuf;
125 fraghdr = (struct ip_hdr *) p->payload;
126 /* If ip_reasstmr is zero, no packet is present in the buffer, so we
127 write the IP header of the fragment into the reassembly
128 buffer. The timer is updated with the maximum age. */
129 if (ip_reasstmr == 0) {
130 mips_memcpy(iphdr, fraghdr, IP_HLEN);
131 ip_reasstmr = IP_REASS_MAXAGE;
132 SetAlarm ( &s_Clock, ip_reass_timer, &s_Clock );
133 ip_reassflags = 0;
134 /* Clear the bitmap. */
135 mips_memset(ip_reassbitmap, 0, sizeof(ip_reassbitmap));
138 /* Check if the incoming fragment matches the one currently present
139 in the reasembly buffer. If so, we proceed with copying the
140 fragment into the buffer. */
141 if (ip_addr_cmp(&iphdr->src, &fraghdr->src) &&
142 ip_addr_cmp(&iphdr->dest, &fraghdr->dest) &&
143 IPH_ID(iphdr) == IPH_ID(fraghdr)) {
144 /* Find out the offset in the reassembly buffer where we should
145 copy the fragment. */
146 len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4;
147 offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8;
149 /* If the offset or the offset + fragment length overflows the
150 reassembly buffer, we discard the entire packet. */
151 if (offset > IP_REASS_BUFSIZE || offset + len > IP_REASS_BUFSIZE) {
152 CancelAlarm ( ip_reass_timer, &s_Clock );
153 ip_reasstmr = 0;
154 goto nullreturn;
157 /* Copy the fragment into the reassembly buffer, at the right
158 offset. */
159 LWIP_DEBUGF(IP_REASS_DEBUG,
160 ("ip_reass: copying with offset %d into %d:%d\n", offset,
161 IP_HLEN + offset, IP_HLEN + offset + len));
162 i = IPH_HL(fraghdr) * 4;
163 copy_from_pbuf(p, &i, &ip_reassbuf[IP_HLEN + offset], len);
165 /* Update the bitmap. */
166 if (offset / (8 * 8) == (offset + len) / (8 * 8)) {
167 /* If the two endpoints are in the same byte, we only update
168 that byte. */
169 ip_reassbitmap[offset / (8 * 8)] |=
170 bitmap_bits[(offset / 8) & 7] &
171 ~bitmap_bits[((offset + len) / 8) & 7];
172 } else {
173 /* If the two endpoints are in different bytes, we update the
174 bytes in the endpoints and fill the stuff inbetween with
175 0xff. */
176 ip_reassbitmap[offset / (8 * 8)] |= bitmap_bits[(offset / 8) & 7];
177 for (i = 1 + offset / (8 * 8); i < (offset + len) / (8 * 8); ++i) {
178 ip_reassbitmap[i] = 0xff;
180 ip_reassbitmap[(offset + len) / (8 * 8)] |=
181 ~bitmap_bits[((offset + len) / 8) & 7];
184 /* If this fragment has the More Fragments flag set to zero, we
185 know that this is the last fragment, so we can calculate the
186 size of the entire packet. We also set the
187 IP_REASS_FLAG_LASTFRAG flag to indicate that we have received
188 the final fragment. */
190 if ((ntohs(IPH_OFFSET(fraghdr)) & IP_MF) == 0) {
191 ip_reassflags |= IP_REASS_FLAG_LASTFRAG;
192 ip_reasslen = offset + len;
195 /* Finally, we check if we have a full packet in the buffer. We do
196 this by checking if we have the last fragment and if all bits
197 in the bitmap are set. */
198 if (ip_reassflags & IP_REASS_FLAG_LASTFRAG) {
199 /* Check all bytes up to and including all but the last byte in
200 the bitmap. */
201 for (i = 0; i < ip_reasslen / (8 * 8) - 1; ++i) {
202 if (ip_reassbitmap[i] != 0xff) {
203 goto nullreturn;
206 /* Check the last byte in the bitmap. It should contain just the
207 right amount of bits. */
208 if (ip_reassbitmap[ip_reasslen / (8 * 8)] !=
209 (u8_t) ~ bitmap_bits[ip_reasslen / 8 & 7]) {
210 goto nullreturn;
213 /* Pretend to be a "normal" (i.e., not fragmented) IP packet
214 from now on. */
215 ip_reasslen += IP_HLEN;
217 IPH_LEN_SET(iphdr, htons(ip_reasslen));
218 IPH_OFFSET_SET(iphdr, 0);
219 IPH_CHKSUM_SET(iphdr, 0);
220 IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
222 /* If we have come this far, we have a full packet in the
223 buffer, so we allocate a pbuf and copy the packet into it. We
224 also reset the timer. */
225 CancelAlarm ( ip_reass_timer, &s_Clock );
227 ip_reasstmr = 0;
228 pbuf_free(p);
229 p = pbuf_alloc(PBUF_LINK, ip_reasslen, PBUF_POOL);
230 if (p != NULL) {
231 i = 0;
232 for (q = p; q != NULL; q = q->next) {
233 /* Copy enough bytes to fill this pbuf in the chain. The
234 available data in the pbuf is given by the q->len
235 variable. */
236 mips_memcpy(q->payload, &ip_reassbuf[i],
237 q->len > ip_reasslen - i ? ip_reasslen - i : q->len);
238 i += q->len;
241 return p;
244 nullreturn:
245 pbuf_free(p);
246 return NULL;
249 #define MAX_MTU 1500
250 static u8_t buf[MEM_ALIGN_SIZE(MAX_MTU)];
253 * Fragment an IP packet if too large
255 * Chop the packet in mtu sized chunks and send them in order
256 * by using a fixed size static memory buffer (PBUF_ROM)
258 err_t
259 ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest)
261 struct pbuf *rambuf;
262 struct pbuf *header;
263 struct ip_hdr *iphdr;
264 u16_t nfb = 0;
265 u16_t left, cop;
266 u16_t mtu = netif->mtu;
267 u16_t ofo, omf;
268 u16_t last;
269 u16_t poff = IP_HLEN;
270 u16_t tmp;
272 /* Get a RAM based MTU sized pbuf */
273 rambuf = pbuf_alloc(PBUF_LINK, 0, PBUF_REF);
274 rambuf->tot_len = rambuf->len = mtu;
275 rambuf->payload = MEM_ALIGN((void *)buf);
278 /* Copy the IP header in it */
279 iphdr = rambuf->payload;
280 mips_memcpy(iphdr, p->payload, IP_HLEN);
282 /* Save original offset */
283 tmp = ntohs(IPH_OFFSET(iphdr));
284 ofo = tmp & IP_OFFMASK;
285 omf = tmp & IP_MF;
287 left = p->tot_len - IP_HLEN;
289 while (left) {
290 last = (left <= mtu - IP_HLEN);
292 /* Set new offset and MF flag */
293 ofo += nfb;
294 tmp = omf | (IP_OFFMASK & (ofo));
295 if (!last)
296 tmp = tmp | IP_MF;
297 IPH_OFFSET_SET(iphdr, htons(tmp));
299 /* Fill this fragment */
300 nfb = (mtu - IP_HLEN) / 8;
301 cop = last ? left : nfb * 8;
303 p = copy_from_pbuf(p, &poff, (u8_t *) iphdr + IP_HLEN, cop);
305 /* Correct header */
306 IPH_LEN_SET(iphdr, htons(cop + IP_HLEN));
307 IPH_CHKSUM_SET(iphdr, 0);
308 IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
310 if (last)
311 pbuf_realloc(rambuf, left + IP_HLEN);
312 /* This part is ugly: we alloc a RAM based pbuf for
313 * the link level header for each chunk and then
314 * free it.A PBUF_ROM style pbuf for which pbuf_header
315 * worked would make things simpler.
317 header = pbuf_alloc(PBUF_LINK, 0, PBUF_RAM);
318 pbuf_chain(header, rambuf);
319 netif->output(netif, header, dest);
320 IPFRAG_STATS_INC(ip_frag.xmit);
321 pbuf_free(header);
323 left -= cop;
325 pbuf_free(rambuf);
326 return ERR_OK;