1 |
/* |
2 |
ROHC Project 2003 at Lulea University of Technology, Sweden. |
3 |
Authors: Andreas Vernersson <andver-8@student.luth.se> |
4 |
Daniel Pettersson <danpet-7@student.luth.se> |
5 |
Erik Soderstrom <soderstrom@yahoo.com> |
6 |
Fredrik Lindstrom <frelin-9@student.luth.se> |
7 |
Johan Stenmark <johste-8@student.luth.se> |
8 |
Martin Juhlin <juhlin@users.sourceforge.net> |
9 |
Mikael Larsson <larmik-9@student.luth.se> |
10 |
Robert Maxe <robmax-1@student.luth.se> |
11 |
|
12 |
Copyright (C) 2003 Andreas Vernersson, Daniel Pettersson, |
13 |
Erik Soderström, Fredrik Lindström, Johan Stenmark, |
14 |
Martin Juhlin, Mikael Larsson, Robert Maxe. |
15 |
|
16 |
This program is free software; you can redistribute it and/or modify |
17 |
it under the terms of the GNU General Public License as published by |
18 |
the Free Software Foundation; either version 2 of the License, or |
19 |
(at your option) any later version. |
20 |
|
21 |
This program is distributed in the hope that it will be useful, |
22 |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
23 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
24 |
GNU General Public License for more details. |
25 |
|
26 |
You should have received a copy of the GNU General Public License |
27 |
along with this program; if not, write to the Free Software |
28 |
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
29 |
*/ |
30 |
/* |
31 |
* File: c_ip.c |
32 |
* Description: Implementation of the IP profile (compressor-side). |
33 |
*/ |
34 |
|
35 |
#include "rohc.h" |
36 |
#include "comp.h" |
37 |
#include "c_util.h" |
38 |
|
39 |
static const char *packet_types[] = { |
40 |
"IR", "IRDYN", "OU-0", "OU-1", "OU-2" |
41 |
}; |
42 |
|
43 |
static const char *extension_types[] = { |
44 |
"NOEXT", "EXT0", "EXT1", "EXT2", "EXT3" |
45 |
}; |
46 |
|
47 |
|
48 |
/* |
49 |
Structure that contain counters, flags and structures that need to saved between different |
50 |
packages. A context have a structure like this for the two first ip-headers. |
51 |
*/ |
52 |
struct sc_ip_header |
53 |
{ |
54 |
struct sc_wlsb *ip_id_window; |
55 |
struct iphdr old_ip; |
56 |
|
57 |
int tos_count, ttl_count, df_count, protocol_count; |
58 |
int rnd_count, nbo_count; |
59 |
int old_rnd,old_nbo; |
60 |
int id_delta; |
61 |
|
62 |
}; |
63 |
|
64 |
/* |
65 |
Structure that contain variables that are temporar, i.e. they will only be used in this |
66 |
packet, they have to be reinitilized every time a new packet arrive. |
67 |
*/ |
68 |
struct ip_tmp_variables{ |
69 |
// The following variables are set in encode |
70 |
int nr_of_ip_hdr; |
71 |
unsigned short changed_fields; |
72 |
unsigned short changed_fields2; |
73 |
int send_static; |
74 |
int send_dynamic; |
75 |
int nr_ip_id_bits; |
76 |
int nr_sn_bits; |
77 |
int nr_ip_id_bits2; |
78 |
int packet_type; |
79 |
int max_size; |
80 |
}; |
81 |
|
82 |
/* |
83 |
Structure that contain counters, flags and structures that need to saved between different |
84 |
packages. Every context have one of these |
85 |
*/ |
86 |
struct sc_ip_context { |
87 |
unsigned int sn; |
88 |
struct sc_wlsb *sn_window; |
89 |
|
90 |
int ir_count, fo_count, so_count; |
91 |
int go_back_fo_count, go_back_ir_count, ir_dyn_count; |
92 |
|
93 |
struct sc_ip_header ip_flags, ip2_flags; |
94 |
|
95 |
struct ip_tmp_variables tmp_variables; |
96 |
|
97 |
int is_initialized; // if ip2 is initialized |
98 |
|
99 |
}; |
100 |
|
101 |
|
102 |
|
103 |
|
104 |
static void decide_state(struct sc_context *context); |
105 |
|
106 |
static void update_variables(struct sc_context *context,const struct iphdr *ip, |
107 |
const struct iphdr *ip2); |
108 |
|
109 |
static int decide_packet(struct sc_context *context); |
110 |
|
111 |
static int decide_FO_packet(struct sc_context *context); |
112 |
|
113 |
static int decide_SO_packet(const struct sc_context *context); |
114 |
|
115 |
static void periodic_down_transition(struct sc_context *context); |
116 |
|
117 |
static int code_packet(struct sc_ip_context *ip_profile,const struct iphdr *ip, |
118 |
const struct iphdr *ip2,unsigned char *dest, struct sc_context *context); |
119 |
|
120 |
|
121 |
static int code_IR_packet(struct sc_ip_context *ip_profile,const struct iphdr *ip, |
122 |
const struct iphdr *ip2,unsigned char *dest,struct sc_context *context); |
123 |
|
124 |
static int code_IR_DYN_packet(struct sc_ip_context *ip_profile,const struct iphdr *ip, |
125 |
const struct iphdr *ip2,unsigned char *dest, struct sc_context *context); |
126 |
|
127 |
|
128 |
static int code_static_part(struct sc_context *context,struct sc_ip_header *ip_hdr_profile, |
129 |
const struct iphdr *ip,unsigned char *dest, int counter); |
130 |
|
131 |
static int code_dynamic_part(struct sc_context *context,struct sc_ip_header *ip_hdr_profile, |
132 |
const struct iphdr *ip,unsigned char *dest, int counter,int *rnd, int *nbo); |
133 |
|
134 |
static int code_UO0_packet(struct sc_context *context,const struct iphdr *ip, |
135 |
unsigned char *dest); |
136 |
|
137 |
static int code_UO1_packet(struct sc_context *context,const struct iphdr *ip, |
138 |
unsigned char *dest); |
139 |
|
140 |
static int code_UO2_packet(struct sc_context *context,struct sc_ip_context *ip_profile, |
141 |
const struct iphdr *ip,const struct iphdr *ip2,unsigned char *dest); |
142 |
|
143 |
static int code_EXT0_packet(struct sc_context *context,const struct iphdr *ip, |
144 |
unsigned char *dest,int counter); |
145 |
|
146 |
static int code_EXT1_packet(struct sc_context *context,const struct iphdr *ip, |
147 |
unsigned char *dest,int counter); |
148 |
|
149 |
static int code_EXT2_packet(struct sc_context *context,struct sc_ip_context *ip_profile, |
150 |
const struct iphdr *ip,unsigned char *dest,int counter); |
151 |
|
152 |
static int code_EXT3_packet(struct sc_context *context,struct sc_ip_context *ip_profile, |
153 |
const struct iphdr *ip,const struct iphdr *ip2, |
154 |
unsigned char *dest,int counter); |
155 |
|
156 |
static int header_flags(struct sc_context *context,unsigned short changed_f, |
157 |
struct sc_ip_header *ip_hdr_profile,int counter,boolean is_outer, |
158 |
int nr_ip_id_bits,const struct iphdr *ip,unsigned char *dest, |
159 |
int context_rnd,int context_nbo); |
160 |
|
161 |
static int header_fields(struct sc_context *context,unsigned short changed_f, |
162 |
struct sc_ip_header *ip_hdr_profile,int counter,boolean is_outer, |
163 |
int nr_ip_id_bits,const struct iphdr *ip,unsigned char *dest,int context_rnd); |
164 |
|
165 |
static int decide_extension(struct sc_context *context); |
166 |
|
167 |
|
168 |
static int changed_static_both_hdr(struct sc_context *context,const struct iphdr *ip, |
169 |
const struct iphdr *ip2); |
170 |
|
171 |
static int changed_static_one_hdr(unsigned short changed_fields,struct sc_ip_header *ip_header, |
172 |
const struct iphdr *ip,struct sc_context *context); |
173 |
|
174 |
|
175 |
static int changed_dynamic_both_hdr(struct sc_context *context,const struct iphdr *ip, |
176 |
const struct iphdr *ip2); |
177 |
|
178 |
static int changed_dynamic_one_hdr(unsigned short changed_fields,struct sc_ip_header *ip_hdr_profile, |
179 |
const struct iphdr *ip,int context_rnd,int context_nbo,struct sc_context *context); |
180 |
|
181 |
static boolean is_changed(unsigned short changed_fields,unsigned short check_field); |
182 |
|
183 |
static unsigned short changed_fields(struct sc_ip_header *ip_hdr_profile,const struct iphdr *ip); |
184 |
|
185 |
static void change_state(struct sc_context *, C_STATE); |
186 |
static void change_mode(struct sc_context *, C_MODE); |
187 |
|
188 |
static void check_ip_identification(struct sc_ip_header *ip_hdr_profile, const struct iphdr *ip, |
189 |
int *context_rnd, int *context_nbo); |
190 |
|
191 |
/* |
192 |
Initilize one ip-header context |
193 |
*/ |
194 |
void c_init_context(struct sc_ip_header *ip_header, |
195 |
const struct iphdr *ip, |
196 |
int context_rnd, |
197 |
int context_nbo) |
198 |
{ |
199 |
ip_header -> ip_id_window = c_create_wlsb(16,C_WINDOW_WIDTH,0); |
200 |
ip_header->old_ip = *ip; |
201 |
ip_header->old_rnd = context_rnd; |
202 |
ip_header->old_nbo = context_nbo; |
203 |
ip_header->tos_count = MAX_FO_COUNT; |
204 |
ip_header->ttl_count = MAX_FO_COUNT; |
205 |
ip_header->df_count = MAX_FO_COUNT; |
206 |
ip_header->protocol_count = MAX_FO_COUNT; |
207 |
ip_header->rnd_count = MAX_FO_COUNT; |
208 |
ip_header->nbo_count = MAX_FO_COUNT; |
209 |
} |
210 |
|
211 |
/* |
212 |
Initilize all temp variables |
213 |
*/ |
214 |
void c_init_tmp_variables(struct ip_tmp_variables *ip_tmp_variables){ |
215 |
ip_tmp_variables->nr_of_ip_hdr = -1; |
216 |
ip_tmp_variables->changed_fields = -1; |
217 |
ip_tmp_variables->changed_fields2 = -1; |
218 |
ip_tmp_variables->send_static = -1; |
219 |
ip_tmp_variables->send_dynamic = -1; |
220 |
ip_tmp_variables->nr_ip_id_bits = -1; |
221 |
ip_tmp_variables->nr_sn_bits = -1; |
222 |
ip_tmp_variables->nr_ip_id_bits2 = -1; |
223 |
ip_tmp_variables->packet_type = -1; |
224 |
ip_tmp_variables->max_size = -1; |
225 |
|
226 |
} |
227 |
|
228 |
/* |
229 |
Function to allocate for a new context, it aslo initilize alot of variables. |
230 |
This function is one of the functions that must exist for the framework to |
231 |
work. Please notice that a pointer to this function has to exist in the |
232 |
sc_profile struct thatwe have in the bottom of this file. |
233 |
*/ |
234 |
int c_ip_create(struct sc_context *context, const struct iphdr *ip) |
235 |
{ |
236 |
struct sc_ip_context *ip_profile; |
237 |
|
238 |
context->profile_context = kmalloc(sizeof(struct sc_ip_context),GFP_ATOMIC); |
239 |
if (context->profile_context == 0) { |
240 |
rohc_debugf(0,"c_ip_create(): no mem for profile context\n"); |
241 |
return 0; |
242 |
} |
243 |
ip_profile = (struct sc_ip_context *)context->profile_context; |
244 |
|
245 |
ip_profile->sn = 0; |
246 |
ip_profile -> sn_window = c_create_wlsb(16,C_WINDOW_WIDTH,-1); |
247 |
|
248 |
ip_profile->ir_count = 0; |
249 |
ip_profile->fo_count = 0; |
250 |
ip_profile->so_count = 0; |
251 |
|
252 |
ip_profile->go_back_fo_count = 0; |
253 |
ip_profile->go_back_ir_count = 0; |
254 |
ip_profile->ir_dyn_count = 0; |
255 |
c_init_context(&ip_profile->ip_flags,ip,context->rnd,context->nbo); |
256 |
c_init_tmp_variables(&ip_profile->tmp_variables); |
257 |
ip_profile->is_initialized = 0; |
258 |
return 1; |
259 |
} |
260 |
|
261 |
/* |
262 |
Function to deallocate a context. |
263 |
|
264 |
This function is one of the functions that must exist for the framework to |
265 |
work. Please notice that a pointer to this function has to exist in the |
266 |
sc_profile struct thatwe have in the bottom of this file. |
267 |
*/ |
268 |
void c_ip_destroy(struct sc_context *context){ |
269 |
struct sc_ip_context *ip_profile = (struct sc_ip_context *)context->profile_context; |
270 |
c_destroy_wlsb(ip_profile->ip_flags.ip_id_window); |
271 |
c_destroy_wlsb(ip_profile->sn_window); |
272 |
|
273 |
if (context->profile_context != 0) |
274 |
kfree(context->profile_context); |
275 |
|
276 |
} |
277 |
|
278 |
/* |
279 |
The function are jused by the framework to check if a package belongs to this context |
280 |
We check that its not framgmented. It is the source and destination addresses in the |
281 |
ip-headers that decides if the package belong to this context. |
282 |
|
283 |
This function is one of the functions that must exist for the framework to |
284 |
work. Please notice that a pointer to this function has to exist in the |
285 |
sc_profile struct that we have in the bottom of this file. |
286 |
|
287 |
|
288 |
This function is one of the functions that must exist for the framework to |
289 |
work. Please notice that a pointer to this function has to exist in the |
290 |
sc_profile struct that we have in the bottom of this file. |
291 |
*/ |
292 |
int c_ip_check_context(struct sc_context *context, const struct iphdr *ip) |
293 |
{ |
294 |
struct sc_ip_context *ip_profile = (struct sc_ip_context *)context->profile_context; |
295 |
int reserved, dont_fragment, more_fragments, fragment_offset; |
296 |
unsigned short fragment; |
297 |
|
298 |
fragment = ntohs(ip->frag_off); |
299 |
|
300 |
reserved = (fragment >> 15); |
301 |
dont_fragment = (fragment >> 14) & 1; |
302 |
more_fragments = (fragment >> 13) & 1; |
303 |
fragment_offset = fragment & ((1<<14)-1); |
304 |
if(reserved != 0 || more_fragments != 0 || fragment_offset != 0) { |
305 |
rohc_debugf(0,"Fragment error (%d, %d, %d, %d)\n", reserved, dont_fragment, more_fragments, fragment_offset); |
306 |
return -1; |
307 |
} |
308 |
|
309 |
if (ip->protocol == 4) { |
310 |
struct iphdr *ip2 = (struct iphdr *)ip+1; |
311 |
boolean same_src = ip_profile->ip_flags.old_ip.saddr == ip->saddr; |
312 |
boolean same_des = ip_profile->ip_flags.old_ip.daddr == ip->daddr; |
313 |
|
314 |
boolean same_src2 = ip_profile->ip2_flags.old_ip.saddr == ip2->saddr; |
315 |
boolean same_des2 = ip_profile->ip2_flags.old_ip.daddr == ip2->daddr; |
316 |
|
317 |
boolean same_first_ip = same_src && same_des; |
318 |
boolean same_second_ip = same_src2 && same_des2; |
319 |
return (same_first_ip && same_second_ip); |
320 |
|
321 |
|
322 |
}else{ |
323 |
boolean same_src = ip_profile->ip_flags.old_ip.saddr == ip->saddr; |
324 |
boolean same_des = ip_profile->ip_flags.old_ip.daddr == ip->daddr; |
325 |
|
326 |
if(same_src && same_des){ |
327 |
return 1; |
328 |
} |
329 |
else |
330 |
return 0; |
331 |
} |
332 |
|
333 |
|
334 |
} |
335 |
|
336 |
// Change the mode of this context |
337 |
void change_mode(struct sc_context *c, C_MODE new_mode) { |
338 |
if(c->c_mode != new_mode){ |
339 |
c->c_mode = new_mode; |
340 |
change_state(c, IR); |
341 |
} |
342 |
} |
343 |
|
344 |
// Change the state of this context |
345 |
void change_state(struct sc_context *c, C_STATE new_state) |
346 |
{ |
347 |
struct sc_ip_context *ip = (struct sc_ip_context *)c->profile_context; |
348 |
|
349 |
// Reset counters only if different state |
350 |
if (c->c_state != new_state) { |
351 |
ip->ir_count = 0; |
352 |
ip->fo_count = 0; |
353 |
ip->so_count = 0; |
354 |
} |
355 |
|
356 |
c->c_state = new_state; |
357 |
} |
358 |
|
359 |
/* |
360 |
Encode packages to a pattern decided by several different factors. |
361 |
1. Checks if we have double ip-headers |
362 |
2. Check if the ip identification field are random and if it has network byte order |
363 |
3. Decide what state we have, ir,fo or so |
364 |
4. Decide how many bits needed to send ip-id and sn fields and most imortant updating |
365 |
the sliding windows. |
366 |
5. Decide what packet to send. |
367 |
6. Code the packet. |
368 |
|
369 |
This function is one of the functions that must exist for the framework to |
370 |
work. Please notice that a pointer to this function has to exist in the |
371 |
sc_profile struct that we have in the bottom of this file. |
372 |
*/ |
373 |
|
374 |
int c_ip_encode(struct sc_context *context, |
375 |
const struct iphdr *ip, |
376 |
int packet_size, |
377 |
unsigned char *dest, |
378 |
int dest_size, |
379 |
int *payload_offset) |
380 |
|
381 |
{ |
382 |
|
383 |
int size; |
384 |
int reserved, dont_fragment, more_fragments, fragment_offset; |
385 |
unsigned short fragment; |
386 |
|
387 |
struct sc_ip_context *ip_profile = (struct sc_ip_context *)context->profile_context; |
388 |
struct iphdr *ip2=(struct iphdr *)ip+1; |
389 |
ip_profile->tmp_variables.changed_fields2 = 0; |
390 |
ip_profile->tmp_variables.nr_ip_id_bits2 = 0; |
391 |
ip_profile->tmp_variables.packet_type = c_IR; |
392 |
ip_profile->tmp_variables.max_size = dest_size; |
393 |
// 1 |
394 |
if (ip->protocol != 4){ |
395 |
ip2 = NULL; |
396 |
ip_profile->tmp_variables.nr_of_ip_hdr = 1; |
397 |
|
398 |
*payload_offset = 20; |
399 |
}else { |
400 |
if(!ip_profile->is_initialized){ |
401 |
c_init_context(&ip_profile->ip2_flags,ip2,context->rnd2,context->nbo2); |
402 |
ip_profile->is_initialized = 1; |
403 |
} |
404 |
*payload_offset = 40; |
405 |
ip_profile->tmp_variables.nr_of_ip_hdr = 2; |
406 |
} |
407 |
|
408 |
if (ip_profile == 0) { |
409 |
rohc_debugf(0,"c_ip_encode(): ip_profile==null\n"); |
410 |
return 0; |
411 |
} |
412 |
|
413 |
fragment = ntohs(ip->frag_off); |
414 |
|
415 |
reserved = (fragment >> 15); |
416 |
dont_fragment = (fragment >> 14) & 1; |
417 |
more_fragments = (fragment >> 13) & 1; |
418 |
fragment_offset = fragment & ((1<<14)-1); |
419 |
if(reserved != 0 || more_fragments != 0 || fragment_offset != 0) { |
420 |
rohc_debugf(0,"Fragment error (%d, %d, %d, %d)\n", reserved, dont_fragment, more_fragments, fragment_offset); |
421 |
return -1; |
422 |
} |
423 |
|
424 |
|
425 |
// 2. Check NBO and RND of IP-ID |
426 |
if (ip_profile->sn != 0){ // skip first packet |
427 |
check_ip_identification(&ip_profile->ip_flags,ip,&context->rnd, &context->nbo); |
428 |
if(ip_profile->tmp_variables.nr_of_ip_hdr > 1){ |
429 |
check_ip_identification(&ip_profile->ip2_flags,ip2,&context->rnd2, &context->nbo2); |
430 |
} |
431 |
} |
432 |
|
433 |
// Increase the sequence number every time we encode something. |
434 |
ip_profile->sn = ip_profile->sn + 1; |
435 |
ip_profile->tmp_variables.changed_fields = changed_fields(&ip_profile->ip_flags,ip); |
436 |
if(ip_profile->tmp_variables.nr_of_ip_hdr > 1){ |
437 |
ip_profile->tmp_variables.changed_fields2 = changed_fields(&ip_profile->ip2_flags,ip2); |
438 |
} |
439 |
|
440 |
|
441 |
ip_profile->tmp_variables.send_static = changed_static_both_hdr(context,ip,ip2); |
442 |
ip_profile->tmp_variables.send_dynamic = changed_dynamic_both_hdr(context,ip,ip2); |
443 |
|
444 |
rohc_debugf(2,"send_static = %d, send_dynamic = %d\n", ip_profile->tmp_variables.send_static |
445 |
,ip_profile->tmp_variables.send_dynamic); |
446 |
// 3 |
447 |
decide_state(context); |
448 |
rohc_debugf(2,"ip->id=%d context->sn=%d\n", ntohs(ip->id), ip_profile->sn); |
449 |
|
450 |
// 4 |
451 |
update_variables(context,ip,ip2); |
452 |
|
453 |
// 5 |
454 |
|
455 |
ip_profile->tmp_variables.packet_type = decide_packet(context); |
456 |
|
457 |
// 6 |
458 |
size = code_packet(ip_profile,ip,ip2,dest,context); |
459 |
if(size < 0) |
460 |
return -1; |
461 |
if (ip_profile->tmp_variables.packet_type == c_UO2) { |
462 |
int extension = decide_extension(context); |
463 |
|
464 |
rohc_debugf(1, "ROHC-IP %s (%s): %d -> %d\n", |
465 |
packet_types[ip_profile->tmp_variables.packet_type], |
466 |
extension_types[extension],*payload_offset, size); |
467 |
} else { |
468 |
rohc_debugf(1, "ROHC-IP %s: from %d -> %d\n", |
469 |
packet_types[ip_profile->tmp_variables.packet_type], |
470 |
*payload_offset, size); |
471 |
} |
472 |
|
473 |
ip_profile->ip_flags.old_ip = *ip; |
474 |
|
475 |
ip_profile->ip_flags.old_rnd = context->rnd; |
476 |
ip_profile->ip_flags.old_nbo = context->nbo; |
477 |
|
478 |
if(ip_profile->tmp_variables.nr_of_ip_hdr > 1){ |
479 |
ip_profile->ip2_flags.old_ip = *ip2; |
480 |
ip_profile->ip2_flags.old_rnd = context->rnd2; |
481 |
ip_profile->ip2_flags.old_nbo = context->nbo2; |
482 |
} |
483 |
|
484 |
if (ip_profile->tmp_variables.packet_type == c_IR) |
485 |
context->num_send_ir ++; |
486 |
else if (ip_profile->tmp_variables.packet_type == c_IRDYN) |
487 |
context->num_send_ir_dyn ++; |
488 |
|
489 |
return size; |
490 |
} |
491 |
|
492 |
|
493 |
/* |
494 |
Function that update the profile when feedback has arrived. |
495 |
|
496 |
This function is one of the functions that must exist for the framework to |
497 |
work. Please notice that a pointer to this function has to exist in the |
498 |
sc_profile struct that we have in the bottom of this file. |
499 |
*/ |
500 |
void c_ip_feedback(struct sc_context *context, struct sc_feedback *feedback) |
501 |
{ |
502 |
struct sc_ip_context *ip_context = (struct sc_ip_context *)context->profile_context; |
503 |
unsigned char *p = feedback->data + feedback->specific_offset; |
504 |
|
505 |
if (feedback->type == 1) { // ack |
506 |
unsigned int sn = p[0]; |
507 |
|
508 |
c_ack_sn_wlsb(ip_context->ip_flags.ip_id_window, sn); |
509 |
c_ack_sn_wlsb(ip_context->sn_window, sn); |
510 |
|
511 |
} else if (feedback->type == 2) { // FEEDBACK-2 |
512 |
unsigned int crc = 0, crc_used=0; |
513 |
|
514 |
int sn_not_valid = 0; |
515 |
unsigned char mode = (p[0]>>4) & 3; |
516 |
unsigned int sn = ((p[0] & 15) << 8) + p[1]; |
517 |
int remaining = feedback->specific_size-2; |
518 |
p+=2; |
519 |
|
520 |
|
521 |
while (remaining > 0) { |
522 |
int opt = p[0]>>4; |
523 |
int optlen = p[0] & 0x0f; |
524 |
|
525 |
switch (opt) { |
526 |
case 1: // CRC |
527 |
crc = p[1]; |
528 |
crc_used = 1; |
529 |
p[1] = 0; // set to zero for crc computation.. |
530 |
break; |
531 |
//case 2: // Reject |
532 |
//break; |
533 |
case 3: // SN-Not-Valid |
534 |
sn_not_valid=1; |
535 |
break; |
536 |
case 4: // SN -- TODO: how is several SN options combined? |
537 |
sn = (sn<<8) + p[1]; |
538 |
break; |
539 |
//case 7: // Loss |
540 |
//break; |
541 |
default: |
542 |
rohc_debugf(0,"c_ip_feedback(): Unknown feedback type: %d\n", opt); |
543 |
break; |
544 |
} |
545 |
|
546 |
remaining -= 1 + optlen; |
547 |
p += 1 + optlen; |
548 |
} |
549 |
|
550 |
if (crc_used) { // check crc.. |
551 |
if (crc_calculate(CRC_TYPE_8, feedback->data, feedback->size ) != crc) { |
552 |
rohc_debugf(0,"c_ip_feedback(): crc check failed..(size=%d)\n", feedback->size); |
553 |
return; |
554 |
} |
555 |
} |
556 |
|
557 |
if (mode != 0) { |
558 |
if (crc_used) { |
559 |
change_mode(context, mode); |
560 |
rohc_debugf(1,"c_ip_feedback(): changing mode to %d\n", mode); |
561 |
} else { |
562 |
rohc_debugf(0,"c_ip_feedback(): mode change requested but no crc was given..\n"); |
563 |
} |
564 |
} |
565 |
|
566 |
switch (feedback->acktype) { |
567 |
case ACK: |
568 |
if (sn_not_valid == 0) { |
569 |
c_ack_sn_wlsb(ip_context->ip_flags.ip_id_window, sn); |
570 |
c_ack_sn_wlsb(ip_context->sn_window, sn); |
571 |
} |
572 |
break; |
573 |
|
574 |
case NACK: |
575 |
if (context->c_state == SO){ |
576 |
change_state(context, FO); |
577 |
ip_context->ir_dyn_count = 0; |
578 |
} |
579 |
if(context->c_state == FO){ |
580 |
ip_context->ir_dyn_count = 0; |
581 |
} |
582 |
|
583 |
break; |
584 |
|
585 |
case STATIC_NACK: |
586 |
change_state(context, IR); |
587 |
break; |
588 |
|
589 |
case RESERVED: |
590 |
rohc_debugf(0, "c_ip_feedback(): reserved field used\n"); |
591 |
break; |
592 |
} |
593 |
|
594 |
} else { |
595 |
rohc_debugf(0,"c_ip_feedback(): Feedback type not implemented (%d)\n", feedback->type); |
596 |
} |
597 |
|
598 |
} |
599 |
|
600 |
/* |
601 |
Decide the state that that should be used for this packet |
602 |
The three states are: |
603 |
IR (initialization and refresh). |
604 |
FO (first order). |
605 |
SO (second order). |
606 |
*/ |
607 |
void decide_state(struct sc_context *context) |
608 |
{ |
609 |
struct sc_ip_context *ip_profile = (struct sc_ip_context *)context->profile_context; |
610 |
int send_static = ip_profile->tmp_variables.send_static; |
611 |
int send_dynamic = ip_profile->tmp_variables.send_dynamic; |
612 |
|
613 |
if(context->c_state == IR && send_dynamic |
614 |
&& ip_profile->ir_count >= MAX_IR_COUNT){ |
615 |
change_state(context, FO); |
616 |
}else if(context->c_state == IR && send_static |
617 |
&& ip_profile->ir_count >= MAX_IR_COUNT){ |
618 |
change_state(context, FO); |
619 |
}else if (context->c_state == IR && ip_profile->ir_count >= MAX_IR_COUNT) { |
620 |
change_state(context, SO); |
621 |
}else if (context->c_state == FO && send_dynamic |
622 |
&& ip_profile->fo_count >= MAX_FO_COUNT) { |
623 |
change_state(context, FO); |
624 |
}else if (context->c_state == FO && send_static |
625 |
&& ip_profile->fo_count >= MAX_FO_COUNT) { |
626 |
change_state(context, FO); |
627 |
}else if (context->c_state == FO && ip_profile->fo_count >= MAX_FO_COUNT) { |
628 |
change_state(context, SO); |
629 |
}else if(context->c_state == SO && send_dynamic){ |
630 |
change_state(context, FO); |
631 |
}else if(context->c_state == SO && send_static){ |
632 |
change_state(context, FO); |
633 |
} |
634 |
if(context->c_mode == U){ |
635 |
periodic_down_transition(context); |
636 |
} |
637 |
|
638 |
} |
639 |
|
640 |
/* |
641 |
A function just to update some variables, only used in encode. Everything in this |
642 |
function could be in encode but to make it more readable we have it here instead. |
643 |
*/ |
644 |
void update_variables(struct sc_context *context, |
645 |
const struct iphdr *ip, |
646 |
const struct iphdr *ip2) |
647 |
{ |
648 |
struct sc_ip_context *ip_profile = (struct sc_ip_context *)context->profile_context; |
649 |
|
650 |
if (context->nbo) |
651 |
ip_profile->ip_flags.id_delta = (ntohs(ip->id) - ip_profile->sn); |
652 |
else |
653 |
ip_profile->ip_flags.id_delta = ip->id - ip_profile->sn; |
654 |
|
655 |
if(ip_profile->tmp_variables.nr_of_ip_hdr > 1){ |
656 |
if (context->nbo2) |
657 |
ip_profile->ip2_flags.id_delta = (ntohs(ip2->id) - ip_profile->sn); |
658 |
else |
659 |
ip_profile->ip2_flags.id_delta = ip2->id - ip_profile->sn; |
660 |
} |
661 |
|
662 |
|
663 |
rohc_debugf(3,"Get k\n"); |
664 |
rohc_debugf(2,"id_delta: %d\n",ip_profile->ip_flags.id_delta); |
665 |
rohc_debugf(2,"Given that sn: %d\n",ip_profile->sn); |
666 |
ip_profile->tmp_variables.nr_ip_id_bits = c_get_k_wlsb(ip_profile->ip_flags.ip_id_window, ip_profile->ip_flags.id_delta); |
667 |
ip_profile->tmp_variables.nr_sn_bits = c_get_k_wlsb(ip_profile->sn_window, ip_profile->sn); |
668 |
|
669 |
if (ip_profile->sn > 1) { |
670 |
rohc_debugf(2, "Content of ip_id:\n"); |
671 |
//print_wlsb_stats(ip_profile->ip_flags.ip_id_window); |
672 |
} |
673 |
|
674 |
rohc_debugf(3,"Adding\n"); |
675 |
|
676 |
c_add_wlsb(ip_profile->ip_flags.ip_id_window, ip_profile->sn, 0, ip_profile->ip_flags.id_delta); // TODO: replace 0 with time(0) |
677 |
c_add_wlsb(ip_profile->sn_window, ip_profile->sn, 0, ip_profile->sn); // TODO: replace 0 with time(0) |
678 |
|
679 |
rohc_debugf(2,"ip_id bits=%d\n", ip_profile->tmp_variables.nr_ip_id_bits); |
680 |
rohc_debugf(2,"sn bits=%d\n", ip_profile->tmp_variables.nr_sn_bits); |
681 |
if(ip_profile->tmp_variables.nr_of_ip_hdr > 1){ |
682 |
ip_profile->tmp_variables.nr_ip_id_bits2 = c_get_k_wlsb(ip_profile->ip2_flags.ip_id_window, ip_profile->ip2_flags.id_delta); |
683 |
rohc_debugf(2,"ip_id bits2=%d\n", ip_profile->tmp_variables.nr_ip_id_bits); |
684 |
c_add_wlsb(ip_profile->ip2_flags.ip_id_window, ip_profile->sn, 0, ip_profile->ip2_flags.id_delta); // TODO: replace 0 with time(0) |
685 |
} |
686 |
} |
687 |
|
688 |
/*Function that change state periodicly after a certain number of packets */ |
689 |
void periodic_down_transition(struct sc_context *context) |
690 |
{ |
691 |
struct sc_ip_context *ip_profile = (struct sc_ip_context *)context->profile_context; |
692 |
if(ip_profile->go_back_fo_count == CHANGE_TO_FO_COUNT){ |
693 |
ip_profile->go_back_fo_count = 0; |
694 |
ip_profile->ir_dyn_count = 0; |
695 |
change_state(context, FO); |
696 |
|
697 |
} else if(ip_profile->go_back_ir_count == CHANGE_TO_IR_COUNT){ |
698 |
ip_profile->go_back_ir_count = 0; |
699 |
change_state(context, IR); |
700 |
} |
701 |
if (context->c_state == SO) |
702 |
ip_profile->go_back_fo_count++; |
703 |
if(context->c_state == SO || context->c_state == FO) |
704 |
ip_profile->go_back_ir_count++; |
705 |
} |
706 |
|
707 |
/* |
708 |
Decide what packet to send in the different states, |
709 |
In IR state, ir packets are used. In FO and SO the functions decide_FO_packet and decide_SO_packet is used. |
710 |
*/ |
711 |
int decide_packet(struct sc_context *context) |
712 |
{ |
713 |
struct sc_ip_context *ip_profile = (struct sc_ip_context *)context->profile_context; |
714 |
int packet_type=IR; |
715 |
switch(context->c_state) |
716 |
{ |
717 |
case IR: |
718 |
rohc_debugf(2,"c_ip_encode(): IR state\n"); |
719 |
ip_profile->ir_count++; |
720 |
packet_type = c_IR; |
721 |
break; |
722 |
case FO: |
723 |
rohc_debugf(2,"c_ip_encode(): FO state\n"); |
724 |
ip_profile->fo_count++; |
725 |
packet_type = decide_FO_packet(context); |
726 |
break; |
727 |
|
728 |
case SO: |
729 |
rohc_debugf(2,"c_ip_encode(): SO state\n"); |
730 |
ip_profile->so_count++; |
731 |
packet_type = decide_SO_packet(context); |
732 |
break; |
733 |
} |
734 |
return packet_type; |
735 |
} |
736 |
|
737 |
/* |
738 |
Decide which packet to send in first order state |
739 |
The packets that can be used is IRDYN and UO2 packets. |
740 |
*/ |
741 |
int decide_FO_packet(struct sc_context *context) |
742 |
{ |
743 |
struct sc_ip_context *ip_profile = (struct sc_ip_context *)context->profile_context; |
744 |
int nr_of_ip_hdr = ip_profile->tmp_variables.nr_of_ip_hdr; |
745 |
|
746 |
if(ip_profile->ir_dyn_count < MAX_FO_COUNT){ |
747 |
ip_profile->ir_dyn_count++; |
748 |
return c_IRDYN; |
749 |
}else if (ip_profile->tmp_variables.send_static) { // if static field changed we must go back to ir |
750 |
return c_UO2; |
751 |
}else if((nr_of_ip_hdr == 1 && ip_profile->tmp_variables.send_dynamic > 2)){ |
752 |
return c_IRDYN; |
753 |
}else if((nr_of_ip_hdr > 1 && ip_profile->tmp_variables.send_dynamic > 4)){ |
754 |
return c_IRDYN; |
755 |
} |
756 |
else{ |
757 |
return c_UO2; |
758 |
} |
759 |
} |
760 |
|
761 |
/* |
762 |
Decide which packet to send in second order state |
763 |
Packet that can be used are UO0, UO1, UO2 with or without extensions. |
764 |
*/ |
765 |
int decide_SO_packet(const struct sc_context *context) |
766 |
{ |
767 |
struct sc_ip_context *ip_profile = (struct sc_ip_context *)context->profile_context; |
768 |
int nr_of_ip_hdr = ip_profile->tmp_variables.nr_of_ip_hdr; |
769 |
int nr_ip_id_bits = ip_profile->tmp_variables.nr_ip_id_bits; |
770 |
int nr_sn_bits = ip_profile->tmp_variables.nr_sn_bits; |
771 |
int nr_ip_id_bits2 = ip_profile->tmp_variables.nr_ip_id_bits2; |
772 |
|
773 |
rohc_debugf(3,"haha, nr_ip_bits=%d nr_sn_bits=%d nr_of_ip_hdr=%d\n",nr_ip_id_bits, nr_sn_bits,nr_of_ip_hdr); |
774 |
|
775 |
if(nr_of_ip_hdr == 1){ |
776 |
|
777 |
if(context->rnd == 1 && nr_sn_bits <= 4){ |
778 |
return c_UO0; |
779 |
} |
780 |
else if(nr_sn_bits <= 4 && nr_ip_id_bits == 0){ |
781 |
return c_UO0; |
782 |
} |
783 |
else if(nr_sn_bits == 5 && nr_ip_id_bits == 0){ |
784 |
return c_UO2; |
785 |
} |
786 |
else if(nr_sn_bits <= 5 && nr_ip_id_bits <= 6){ |
787 |
return c_UO1; |
788 |
} |
789 |
else{ |
790 |
return c_UO2; |
791 |
} |
792 |
} |
793 |
else{ |
794 |
if(context->rnd == 1 && context->rnd2 == 1 && nr_sn_bits <= 4){ |
795 |
return c_UO0; |
796 |
} |
797 |
else if(nr_sn_bits <= 4 && (context->rnd == 1 || nr_ip_id_bits == 0) |
798 |
&& (context->rnd2 == 1 || nr_ip_id_bits2 ==0)){ |
799 |
|
800 |
return c_UO0; |
801 |
} |
802 |
else if(nr_sn_bits <= 5 && nr_ip_id_bits <= 6 && (context->rnd2 == 1 || nr_ip_id_bits2 == 0)){ |
803 |
return c_UO1; |
804 |
} |
805 |
else{ |
806 |
return c_UO2; |
807 |
} |
808 |
} |
809 |
} |
810 |
|
811 |
/*Code the given packet type*/ |
812 |
|
813 |
/* |
814 |
Code the given packet type |
815 |
Every given type has its own help function |
816 |
The ir and ir-dyn packet are totally coded by their own functions. The general format |
817 |
for other packets are coded in this function according to the following: |
818 |
|
819 |
0 1 2 3 4 5 6 7 |
820 |
--- --- --- --- --- --- --- --- |
821 |
1 : Add-CID octet : | |
822 |
+---+---+---+---+---+---+---+---+ | |
823 |
2 | first octet of base header | | |
824 |
+---+---+---+---+---+---+---+---+ | |
825 |
: : | |
826 |
3 / 0, 1, or 2 octets of CID / | |
827 |
: : | |
828 |
+---+---+---+---+---+---+---+---+ | |
829 |
4 / remainder of base header / | |
830 |
+---+---+---+---+---+---+---+---+ | |
831 |
: : | |
832 |
5 / Extension / | |
833 |
: : | |
834 |
--- --- --- --- --- --- --- --- | |
835 |
: : | |
836 |
6 + IP-ID of outer IPv4 header + |
837 |
: : (see section 5.7 or [RFC-3095]) |
838 |
--- --- --- --- --- --- --- --- |
839 |
7 / AH data for outer list / | |
840 |
--- --- --- --- --- --- --- --- | |
841 |
: : | |
842 |
8 + GRE checksum + | |
843 |
: : | |
844 |
--- --- --- --- --- --- --- --- | |
845 |
: : | |
846 |
9 + IP-ID of inner IPv4 header + | |
847 |
: : | |
848 |
--- --- --- --- --- --- --- --- | |
849 |
10 / AH data for inner list / | |
850 |
--- --- --- --- --- --- --- --- | |
851 |
: : | |
852 |
11 + GRE checksum + | |
853 |
: : | |
854 |
--- --- --- --- --- --- --- --- |
855 |
: List of : |
856 |
12 / Dynamic chains / variable, given by static chain |
857 |
: for additional IP headers : (includes no SN) |
858 |
--- --- --- --- --- --- --- --- |
859 |
7, 8, 10, 11, 12 is not supported. |
860 |
Each profile code 1, 2, 3, 4, 5 is coded in each packets function |
861 |
6 and 9 is coded in this function |
862 |
*/ |
863 |
int code_packet(struct sc_ip_context *ip_profile, |
864 |
const struct iphdr *ip, |
865 |
const struct iphdr *ip2, |
866 |
unsigned char *dest, |
867 |
struct sc_context *context) |
868 |
{ |
869 |
int counter = 0; |
870 |
int nr_of_ip_hdr = ip_profile->tmp_variables.nr_of_ip_hdr; |
871 |
//struct sc_ip_context *ip_profile = (struct sc_ip_context *)context->profile_context; |
872 |
|
873 |
rohc_debugf(2,"RND=%d RND2=%d\n",context->rnd, context->rnd2); |
874 |
switch(ip_profile->tmp_variables.packet_type){ |
875 |
case c_IR: |
876 |
rohc_debugf(2,"code_packet(): IR packet..\n"); |
877 |
return code_IR_packet(ip_profile,ip,ip2,dest,context); |
878 |
break; |
879 |
case c_IRDYN: |
880 |
rohc_debugf(2,"code_packet(): IRDYN packet..\n"); |
881 |
return code_IR_DYN_packet(ip_profile,ip,ip2,dest,context); |
882 |
break; |
883 |
case c_UO0: |
884 |
rohc_debugf(2,"code_packet(): OU-0 packet..\n"); |
885 |
counter = code_UO0_packet(context, ip, dest); |
886 |
break; |
887 |
case c_UO1: |
888 |
rohc_debugf(2,"code_packet(): OU-1 packet..\n"); |
889 |
counter = code_UO1_packet(context, ip, dest); |
890 |
break; |
891 |
|
892 |
case c_UO2: |
893 |
rohc_debugf(2,"code_packet(): OU-2 packet..\n"); |
894 |
counter = code_UO2_packet(context,ip_profile,ip,ip2,dest); |
895 |
break; |
896 |
default: |
897 |
rohc_debugf(0,"code_packet(): Unknown packet..\n"); |
898 |
return -1; |
899 |
} |
900 |
|
901 |
|
902 |
// 6 |
903 |
if(context->rnd == 1){ |
904 |
memcpy(&dest[counter], &ip->id, 2); |
905 |
counter += 2; |
906 |
} |
907 |
|
908 |
// 9 |
909 |
if(nr_of_ip_hdr > 1){ |
910 |
if(context->rnd2 == 1){ |
911 |
memcpy(&dest[counter], &ip2->id, 2); |
912 |
counter += 2; |
913 |
} |
914 |
} |
915 |
|
916 |
|
917 |
return counter; |
918 |
|
919 |
} |
920 |
/* |
921 |
Code the IR-packet to this pattern: |
922 |
|
923 |
IR packet (5.7.7.1): |
924 |
|
925 |
0 1 2 3 4 5 6 7 |
926 |
--- --- --- --- --- --- --- --- |
927 |
1 | Add-CID octet | if for small CIDs and CID != 0 |
928 |
+---+---+---+---+---+---+---+---+ |
929 |
2 | 1 1 1 1 1 1 0 | D | |
930 |
+---+---+---+---+---+---+---+---+ |
931 |
| | |
932 |
3 / 0-2 octets of CID info / 1-2 octets if for large CIDs |
933 |
| | |
934 |
+---+---+---+---+---+---+---+---+ |
935 |
4 | Profile | 1 octet |
936 |
+---+---+---+---+---+---+---+---+ |
937 |
5 | CRC | 1 octet |
938 |
+---+---+---+---+---+---+---+---+ |
939 |
| | |
940 |
6 | Static chain | variable length |
941 |
| | |
942 |
+---+---+---+---+---+---+---+---+ |
943 |
| | |
944 |
7 | Dynamic chain | present if D = 1, variable length |
945 |
| | |
946 |
+---+---+---+---+---+---+---+---+ |
947 |
8 | SN | 2 octets |
948 |
+---+---+---+---+---+---+---+---+ |
949 |
| | |
950 |
| Payload | variable length |
951 |
| | |
952 |
- - - - - - - - - - - - - - - - |
953 |
|
954 |
The numbers before every field is used to find where in the code we try |
955 |
to code that field. |
956 |
*/ |
957 |
int code_IR_packet(struct sc_ip_context *ip_profile, |
958 |
const struct iphdr *ip, |
959 |
const struct iphdr *ip2, |
960 |
unsigned char *dest, |
961 |
struct sc_context *context) |
962 |
|
963 |
{ |
964 |
unsigned char type; |
965 |
int crc_position; |
966 |
int counter = 0; |
967 |
int first_position; |
968 |
int nr_of_ip_hdr = ip_profile->tmp_variables.nr_of_ip_hdr; |
969 |
|
970 |
rohc_debugf(2,"Coding IR packet (cid=%d)\n", context->cid); |
971 |
//Both 1 and 3, 2 will be placed in dest[first_position] |
972 |
counter = code_cid_values(context,dest,ip_profile->tmp_variables.max_size,&first_position); |
973 |
|
974 |
// 2 |
975 |
type = 0xfc; |
976 |
|
977 |
// Set the type and set the d flag if the dynamic part |
978 |
// will be present in the ir packet |
979 |
|
980 |
type += 1; |
981 |
|
982 |
|
983 |
dest[first_position] = type; |
984 |
// if large cid |
985 |
// Set profile_id and crc to zero so far |
986 |
// 3 |
987 |
dest[counter] = context -> profile_id; |
988 |
counter++; |
989 |
|
990 |
// 5 |
991 |
// Becuase we calculate the crc over the ir packet with the crc field set to zero |
992 |
// The real crc is calculated in the end of this function |
993 |
crc_position = counter; |
994 |
dest[counter] = 0; |
995 |
counter++; |
996 |
|
997 |
// 6 |
998 |
counter = code_static_part(context,&ip_profile->ip_flags,ip,dest,counter); |
999 |
|
1000 |
if(nr_of_ip_hdr > 1){ |
1001 |
counter = code_static_part(context,&ip_profile->ip2_flags,ip2,dest,counter); |
1002 |
} |
1003 |
|
1004 |
|
1005 |
|
1006 |
|
1007 |
// 7 |
1008 |
|
1009 |
//Observe that if we don't wan't dynamic part in ir-packet we should not send the following |
1010 |
//****************************************************************************************************** |
1011 |
counter = code_dynamic_part(context,&ip_profile->ip_flags,ip,dest,counter,&context->rnd,&context->nbo); |
1012 |
if(nr_of_ip_hdr > 1){ |
1013 |
counter = code_dynamic_part(context,&ip_profile->ip2_flags,ip2,dest,counter,&context->rnd2,&context->nbo2); |
1014 |
} |
1015 |
if(counter < 0) |
1016 |
return -1; |
1017 |
|
1018 |
// 8 |
1019 |
|
1020 |
dest[counter] = (ip_profile->sn) >> 8; |
1021 |
counter++; |
1022 |
dest[counter] = (ip_profile->sn) & 0xff; |
1023 |
counter++; |
1024 |
//****************************************************************************************************** |
1025 |
|
1026 |
|
1027 |
//} |
1028 |
|
1029 |
// 5 Count the crc and set the crc field to the checksum. |
1030 |
rohc_debugf(2,"Crc length=%d\n", counter); |
1031 |
dest[crc_position]= crc_calculate(CRC_TYPE_8,dest,counter); |
1032 |
return counter; |
1033 |
|
1034 |
} |
1035 |
/* |
1036 |
Code the IRDYN-packet to this pattern: |
1037 |
|
1038 |
IR-dyn packet (5.7.7.2): |
1039 |
|
1040 |
0 1 2 3 4 5 6 7 |
1041 |
--- --- --- --- --- --- --- --- |
1042 |
1 : Add-CID octet : if for small CIDs and CID != 0 |
1043 |
+---+---+---+---+---+---+---+---+ |
1044 |
2 | 1 1 1 1 1 0 0 0 | IR-DYN packet type |
1045 |
+---+---+---+---+---+---+---+---+ |
1046 |
: : |
1047 |
3 / 0-2 octets of CID info / 1-2 octets if for large CIDs |
1048 |
: : |
1049 |
+---+---+---+---+---+---+---+---+ |
1050 |
4 | Profile | 1 octet |
1051 |
+---+---+---+---+---+---+---+---+ |
1052 |
5 | CRC | 1 octet |
1053 |
+---+---+---+---+---+---+---+---+ |
1054 |
| | |
1055 |
6 / Dynamic chain / variable length |
1056 |
| | |
1057 |
+---+---+---+---+---+---+---+---+ |
1058 |
7 | SN | 2 octets |
1059 |
+---+---+---+---+---+---+---+---+ |
1060 |
: : |
1061 |
/ Payload / variable length |
1062 |
: : |
1063 |
- - - - - - - - - - - - - - - - |
1064 |
|
1065 |
|
1066 |
The numbers before every field is used to find where in the code we try |
1067 |
to code that field. |
1068 |
|
1069 |
*/ |
1070 |
int code_IR_DYN_packet(struct sc_ip_context *ip_profile, |
1071 |
const struct iphdr *ip, |
1072 |
const struct iphdr *ip2, |
1073 |
unsigned char *dest, |
1074 |
struct sc_context *context) |
1075 |
|
1076 |
|
1077 |
{ |
1078 |
|
1079 |
int crc_position; |
1080 |
int counter = 0; |
1081 |
int first_position; |
1082 |
int nr_of_ip_hdr = ip_profile->tmp_variables.nr_of_ip_hdr; |
1083 |
|
1084 |
//Both 1 and 3, 2 will be placed in dest[first_position] |
1085 |
counter = code_cid_values(context,dest,ip_profile->tmp_variables.max_size,&first_position); |
1086 |
|
1087 |
// 2 |
1088 |
dest[first_position] = 0xf8; |
1089 |
|
1090 |
// 4 |
1091 |
dest[counter] = context -> profile_id; |
1092 |
counter++; |
1093 |
|
1094 |
// 5 |
1095 |
// Becuase we calculate the crc over the ir packet with the crc field set to zero |
1096 |
// The real crc is calculated in the end of this function |
1097 |
crc_position = counter; |
1098 |
dest[counter] = 0; |
1099 |
counter++; |
1100 |
|
1101 |
// 6 |
1102 |
counter = code_dynamic_part(context,&ip_profile->ip_flags,ip,dest,counter,&context->rnd,&context->nbo); |
1103 |
if(nr_of_ip_hdr > 1){ |
1104 |
counter = code_dynamic_part(context,&ip_profile->ip2_flags,ip2,dest,counter,&context->rnd2,&context->nbo2); |
1105 |
} |
1106 |
if(counter < 0) |
1107 |
return -1; |
1108 |
|
1109 |
// 7 |
1110 |
dest[counter] = (ip_profile->sn) >> 8; |
1111 |
counter++; |
1112 |
dest[counter] = (ip_profile->sn) & 0xff; |
1113 |
counter++; |
1114 |
|
1115 |
// 5 |
1116 |
// Count the crc and set the crc field to the checksum. |
1117 |
dest[crc_position]= crc_calculate(CRC_TYPE_8,dest,counter); |
1118 |
return counter; |
1119 |
} |
1120 |
|
1121 |
/* |
1122 |
Code the static part: |
1123 |
Static part IPv4 (5.7.7.4): |
1124 |
|
1125 |
+---+---+---+---+---+---+---+---+ |
1126 |
1 | Version = 4 | 0 | |
1127 |
+---+---+---+---+---+---+---+---+ |
1128 |
2 | Protocol | |
1129 |
+---+---+---+---+---+---+---+---+ |
1130 |
3 / Source Address / 4 octets |
1131 |
+---+---+---+---+---+---+---+---+ |
1132 |
4 / Destination Address / 4 octets |
1133 |
+---+---+---+---+---+---+---+---+ |
1134 |
*/ |
1135 |
int code_static_part(struct sc_context *context, |
1136 |
struct sc_ip_header *ip_hdr_profile, |
1137 |
const struct iphdr *ip, |
1138 |
unsigned char *dest, |
1139 |
int counter) |
1140 |
{ |
1141 |
|
1142 |
// 1 |
1143 |
dest[counter] = 0x40; |
1144 |
counter++; |
1145 |
|
1146 |
// 2 |
1147 |
dest[counter] = ip -> protocol; rohc_debugf(3,"code_IR, protocol=%d\n", dest[counter]); |
1148 |
counter++; |
1149 |
ip_hdr_profile -> protocol_count++; |
1150 |
|
1151 |
// 3 |
1152 |
memcpy(&dest[counter], &ip -> saddr, 4); |
1153 |
counter += 4; |
1154 |
|
1155 |
// 4 |
1156 |
memcpy(&dest[counter], &ip -> daddr, 4); |
1157 |
counter += 4; |
1158 |
return counter; |
1159 |
} |
1160 |
|
1161 |
/* |
1162 |
Code the dynamic part: |
1163 |
Dynamic part IPv4 (5.7.7.4): |
1164 |
|
1165 |
+---+---+---+---+---+---+---+---+ |
1166 |
1 | Type of Service | |
1167 |
+---+---+---+---+---+---+---+---+ |
1168 |
2 | Time to Live | |
1169 |
+---+---+---+---+---+---+---+---+ |
1170 |
3 / Identification / 2 octets |
1171 |
+---+---+---+---+---+---+---+---+ |
1172 |
4 | DF|RND|NBO| 0 | |
1173 |
+---+---+---+---+---+---+---+---+ |
1174 |
5 / Generic extension header list / variable length |
1175 |
+---+---+---+---+---+---+---+---+ |
1176 |
*/ |
1177 |
int code_dynamic_part(struct sc_context *context, |
1178 |
struct sc_ip_header *ip_hdr_profile, |
1179 |
const struct iphdr *ip, |
1180 |
unsigned char *dest, |
1181 |
int counter, |
1182 |
int *rnd, |
1183 |
int *nbo) |
1184 |
{ |
1185 |
|
1186 |
unsigned char df_rnd_nbo = 0; |
1187 |
int reserved, dont_fragment, more_fragments, fragment_offset; |
1188 |
unsigned short fragment; |
1189 |
|
1190 |
// 1 |
1191 |
dest[counter] = ip -> tos; |
1192 |
counter++; |
1193 |
ip_hdr_profile->tos_count++; |
1194 |
|
1195 |
// 2 |
1196 |
dest[counter] = ip -> ttl; |
1197 |
counter++; |
1198 |
ip_hdr_profile->ttl_count++; |
1199 |
|
1200 |
// 3 |
1201 |
memcpy(&dest[counter], &ip->id, 2); |
1202 |
counter += 2; |
1203 |
|
1204 |
|
1205 |
// 4 |
1206 |
|
1207 |
fragment = ntohs(ip->frag_off); |
1208 |
|
1209 |
reserved = (fragment >> 15); |
1210 |
dont_fragment = (fragment >> 14) & 1; |
1211 |
more_fragments = (fragment >> 13) & 1; |
1212 |
fragment_offset = fragment & ((1<<14)-1); |
1213 |
if(reserved != 0 || more_fragments != 0 || fragment_offset != 0) { |
1214 |
rohc_debugf(0,"Fragment error (%d, %d, %d, %d)\n", reserved, dont_fragment, more_fragments, fragment_offset); |
1215 |
return -1; |
1216 |
} |
1217 |
df_rnd_nbo = (dont_fragment << 7); |
1218 |
ip_hdr_profile->df_count++; |
1219 |
// Check random flags and network byte order flag in the context struct |
1220 |
if(*rnd){ |
1221 |
df_rnd_nbo |= 0x40; |
1222 |
} |
1223 |
if(*nbo){ |
1224 |
df_rnd_nbo |= 0x20; |
1225 |
} |
1226 |
ip_hdr_profile->rnd_count++; |
1227 |
ip_hdr_profile->nbo_count++; |
1228 |
dest[counter] = df_rnd_nbo; |
1229 |
counter++; |
1230 |
|
1231 |
// 5 is not supported |
1232 |
|
1233 |
return counter; |
1234 |
} |
1235 |
|
1236 |
/* |
1237 |
Code UO0-packets acording to the following pattern: |
1238 |
|
1239 |
0 1 2 3 4 5 6 7 |
1240 |
--- --- --- --- --- --- --- --- |
1241 |
1 : Add-CID octet : |
1242 |
+---+---+---+---+---+---+---+---+ |
1243 |
2 | first octet of base header | |
1244 |
+---+---+---+---+---+---+---+---+ |
1245 |
: : |
1246 |
3 / 0, 1, or 2 octets of CID / |
1247 |
: : |
1248 |
+---+---+---+---+---+---+---+---+ |
1249 |
|
1250 |
UO-0 (5.7.1) |
1251 |
|
1252 |
0 1 2 3 4 5 6 7 |
1253 |
+---+---+---+---+---+---+---+---+ |
1254 |
2 | 0 | SN | CRC | |
1255 |
+===+===+===+===+===+===+===+===+ |
1256 |
*/ |
1257 |
|
1258 |
int code_UO0_packet(struct sc_context *context, |
1259 |
const struct iphdr *ip, |
1260 |
unsigned char *dest) |
1261 |
{ |
1262 |
struct sc_ip_context *ip_profile = (struct sc_ip_context *)context->profile_context; |
1263 |
int nr_of_ip_hdr = ip_profile->tmp_variables.nr_of_ip_hdr; |
1264 |
unsigned char f_byte; |
1265 |
int counter = 0; |
1266 |
int first_position; |
1267 |
int ch_sum; |
1268 |
//Both 1 and 3, 2 will be placed in dest[first_position] |
1269 |
counter = code_cid_values(context,dest,ip_profile->tmp_variables.max_size,&first_position); |
1270 |
|
1271 |
// 2 |
1272 |
f_byte = (ip_profile -> sn) & 0xf; |
1273 |
f_byte = f_byte << 3; |
1274 |
if(nr_of_ip_hdr == 1) |
1275 |
ch_sum= crc_calculate(CRC_TYPE_3,(unsigned char *)ip,20); |
1276 |
else |
1277 |
ch_sum= crc_calculate(CRC_TYPE_3,(unsigned char *)ip,40); |
1278 |
f_byte = f_byte + ch_sum; |
1279 |
dest[first_position] = f_byte; |
1280 |
return counter; |
1281 |
} |
1282 |
|
1283 |
/* |
1284 |
Code UO1-packets acording to the following pattern: |
1285 |
|
1286 |
0 1 2 3 4 5 6 7 |
1287 |
--- --- --- --- --- --- --- --- |
1288 |
1 : Add-CID octet : |
1289 |
+---+---+---+---+---+---+---+---+ |
1290 |
2 | first octet of base header | |
1291 |
+---+---+---+---+---+---+---+---+ |
1292 |
: : |
1293 |
3 / 0, 1, or 2 octets of CID / |
1294 |
: : |
1295 |
+---+---+---+---+---+---+---+---+ |
1296 |
|
1297 |
OU-1 (5.11.3) |
1298 |
|
1299 |
0 1 2 3 4 5 6 7 |
1300 |
+---+---+---+---+---+---+---+---+ |
1301 |
2 | 1 0 | IP-ID | |
1302 |
+===+===+===+===+===+===+===+===+ |
1303 |
4 | SN | CRC | |
1304 |
+---+---+---+---+---+---+---+---+ |
1305 |
|
1306 |
*/ |
1307 |
int code_UO1_packet(struct sc_context *context, |
1308 |
const struct iphdr *ip, |
1309 |
unsigned char *dest) |
1310 |
{ |
1311 |
struct sc_ip_context *ip_profile = (struct sc_ip_context *)context->profile_context; |
1312 |
int nr_of_ip_hdr = ip_profile->tmp_variables.nr_of_ip_hdr; |
1313 |
unsigned char f_byte; |
1314 |
unsigned char s_byte; |
1315 |
int counter = 0; |
1316 |
int first_position; |
1317 |
int ch_sum; |
1318 |
//Both 1 and 3, 2 will be placed in dest[first_position] |
1319 |
counter = code_cid_values(context,dest,ip_profile->tmp_variables.max_size,&first_position); |
1320 |
f_byte = (ip_profile -> ip_flags.id_delta) & 0x3f; |
1321 |
f_byte |= 0x80; |
1322 |
// Add the 5 bits of sn |
1323 |
s_byte = (ip_profile -> sn) & 0x1f; |
1324 |
s_byte = s_byte << 3; |
1325 |
if(nr_of_ip_hdr == 1) |
1326 |
ch_sum= crc_calculate(CRC_TYPE_3,(unsigned char *)ip,20); |
1327 |
else |
1328 |
ch_sum= crc_calculate(CRC_TYPE_3,(unsigned char *)ip,40); |
1329 |
s_byte |= ch_sum; |
1330 |
dest[first_position] = f_byte; |
1331 |
dest[counter] = s_byte; |
1332 |
counter++; |
1333 |
return counter; |
1334 |
} |
1335 |
|
1336 |
/* |
1337 |
Code UO0-packets acording to the following pattern: |
1338 |
|
1339 |
0 1 2 3 4 5 6 7 |
1340 |
--- --- --- --- --- --- --- --- |
1341 |
1 : Add-CID octet : |
1342 |
+---+---+---+---+---+---+---+---+ |
1343 |
2 | first octet of base header | |
1344 |
+---+---+---+---+---+---+---+---+ |
1345 |
: : |
1346 |
3 / 0, 1, or 2 octets of CID / |
1347 |
: : |
1348 |
+---+---+---+---+---+---+---+---+ |
1349 |
|
1350 |
OU-2 (5.11.3): |
1351 |
|
1352 |
0 1 2 3 4 5 6 7 |
1353 |
+---+---+---+---+---+---+---+---+ |
1354 |
2 | 1 1 0 | SN | |
1355 |
+===+===+===+===+===+===+===+===+ |
1356 |
4 | X | CRC | |
1357 |
+---+---+---+---+---+---+---+---+ |
1358 |
|
1359 |
+---+---+---+---+---+---+---+---+ |
1360 |
: : |
1361 |
5 / Extension / |
1362 |
: : |
1363 |
--- --- --- --- --- --- --- --- |
1364 |
*/ |
1365 |
int code_UO2_packet(struct sc_context *context, |
1366 |
struct sc_ip_context *ip_profile, |
1367 |
const struct iphdr *ip, |
1368 |
const struct iphdr *ip2, |
1369 |
unsigned char *dest) |
1370 |
{ |
1371 |
|
1372 |
unsigned char f_byte; |
1373 |
unsigned char s_byte; |
1374 |
int counter = 0; |
1375 |
int first_position; |
1376 |
int ch_sum; |
1377 |
int extension; |
1378 |
int nr_of_ip_hdr = ip_profile->tmp_variables.nr_of_ip_hdr; |
1379 |
//Both 1 and 3, 2 will be placed in dest[first_position] |
1380 |
counter = code_cid_values(context,dest,ip_profile->tmp_variables.max_size,&first_position); |
1381 |
|
1382 |
// 2 |
1383 |
f_byte = 0xc0; |
1384 |
// Add the 4 bits of sn |
1385 |
|
1386 |
// 4 |
1387 |
if(nr_of_ip_hdr == 1) |
1388 |
ch_sum= crc_calculate(CRC_TYPE_7,(unsigned char *)ip,20); |
1389 |
else |
1390 |
ch_sum= crc_calculate(CRC_TYPE_7,(unsigned char *)ip,40); |
1391 |
s_byte = ch_sum; |
1392 |
|
1393 |
// 5 |
1394 |
extension = decide_extension(context); |
1395 |
if(extension == c_NOEXT){ |
1396 |
rohc_debugf(1,"code_OU2_packet(): no extension\n"); |
1397 |
// 2 |
1398 |
f_byte |= ((ip_profile -> sn) & 0x1f); |
1399 |
dest[first_position] = f_byte; |
1400 |
// 4 |
1401 |
dest[counter] = s_byte; |
1402 |
counter++; |
1403 |
return counter; |
1404 |
} |
1405 |
// 4 |
1406 |
//We have a extension |
1407 |
s_byte |= 0x80; |
1408 |
dest[counter] = s_byte; |
1409 |
counter++; |
1410 |
|
1411 |
// 5 |
1412 |
if(extension == c_EXT0) { |
1413 |
rohc_debugf(1,"code_OU2_packet(): using extension 0\n"); |
1414 |
// 2 |
1415 |
f_byte |= ((ip_profile -> sn & 0xff) >> 3); |
1416 |
dest[first_position] = f_byte; |
1417 |
// 5 |
1418 |
counter = code_EXT0_packet(context,ip,dest,counter); |
1419 |
} else if(extension == c_EXT1) { |
1420 |
rohc_debugf(1,"code_OU2_packet(): using extension 1\n"); |
1421 |
// 2 |
1422 |
f_byte |= ((ip_profile -> sn & 0xff) >> 3); |
1423 |
dest[first_position] = f_byte; |
1424 |
// 5 |
1425 |
counter = code_EXT1_packet(context,ip,dest,counter); |
1426 |
} else if(extension == c_EXT2){ |
1427 |
rohc_debugf(1,"code_OU2_packet(): using extension 2\n"); |
1428 |
// 2 |
1429 |
f_byte |= ((ip_profile -> sn & 0xff) >> 3); |
1430 |
dest[first_position] = f_byte; |
1431 |
// 5 |
1432 |
counter = code_EXT2_packet(context,ip_profile,ip,dest,counter); |
1433 |
} |
1434 |
else if(extension == c_EXT3) { |
1435 |
rohc_debugf(1,"code_OU2_packet(): using extension 3\n"); |
1436 |
// 2 |
1437 |
// check if s-field needs to be used |
1438 |
if(ip_profile->tmp_variables.nr_sn_bits > 5) |
1439 |
f_byte |= ((ip_profile -> sn) >> 8); |
1440 |
else |
1441 |
f_byte |= (ip_profile -> sn & 0x1f); |
1442 |
|
1443 |
dest[first_position] = f_byte; |
1444 |
// 5 |
1445 |
counter = code_EXT3_packet(context,ip_profile,ip,ip2,dest, counter); |
1446 |
} else { |
1447 |
rohc_debugf(0,"code_OU2_packet(): Unknown extension (%d)..\n", extension); |
1448 |
|
1449 |
} |
1450 |
return counter; |
1451 |
} |
1452 |
|
1453 |
|
1454 |
/* |
1455 |
Coding the extension 0 part of the uo0-packet |
1456 |
|
1457 |
Extension 0 (5.11.4): |
1458 |
|
1459 |
+---+---+---+---+---+---+---+---+ |
1460 |
1 | 0 0 | SN | IP-ID | |
1461 |
+---+---+---+---+---+---+---+---+ |
1462 |
|
1463 |
*/ |
1464 |
int code_EXT0_packet(struct sc_context *context,const struct iphdr *ip, |
1465 |
unsigned char *dest, int counter) |
1466 |
{ |
1467 |
struct sc_ip_context *ip_profile = (struct sc_ip_context *)context->profile_context; |
1468 |
unsigned char f_byte; |
1469 |
|
1470 |
// 1 |
1471 |
f_byte = (ip_profile -> sn) & 0x07; |
1472 |
f_byte = f_byte << 3; |
1473 |
f_byte |= (ip_profile->ip_flags.id_delta) & 0x07; |
1474 |
dest[counter] = f_byte; |
1475 |
counter++; |
1476 |
return counter; |
1477 |
|
1478 |
} |
1479 |
/* |
1480 |
Coding the extension 1 part of the uo1-packet |
1481 |
|
1482 |
Extension 1 (5.11.4): |
1483 |
|
1484 |
+---+---+---+---+---+---+---+---+ |
1485 |
1 | 0 1 | SN | IP-ID | |
1486 |
+---+---+---+---+---+---+---+---+ |
1487 |
2 | IP-ID | |
1488 |
+---+---+---+---+---+---+---+---+ |
1489 |
*/ |
1490 |
int code_EXT1_packet(struct sc_context *context, |
1491 |
const struct iphdr *ip, |
1492 |
unsigned char *dest, |
1493 |
int counter) |
1494 |
{ |
1495 |
//Code for the extension |
1496 |
struct sc_ip_context *ip_profile = (struct sc_ip_context *)context->profile_context; |
1497 |
unsigned char f_byte; |
1498 |
unsigned char s_byte; |
1499 |
unsigned short id; |
1500 |
|
1501 |
// 1 |
1502 |
f_byte = (ip_profile -> sn) & 0x07; |
1503 |
f_byte = f_byte << 3; |
1504 |
id = (ip_profile ->ip_flags. id_delta) & 0x0700; |
1505 |
id = id >> 8; |
1506 |
f_byte |= id; |
1507 |
f_byte |= 0x40; |
1508 |
|
1509 |
// 2 |
1510 |
s_byte = (ip_profile ->ip_flags. id_delta) & 0xff; |
1511 |
dest[counter] = f_byte; |
1512 |
counter++; |
1513 |
dest[counter] = s_byte; |
1514 |
counter++; |
1515 |
return counter; |
1516 |
} |
1517 |
|
1518 |
|
1519 |
/* |
1520 |
Coding the extension 1 part of the uo1-packet |
1521 |
|
1522 |
Extension 2 (5.11.4): |
1523 |
|
1524 |
+---+---+---+---+---+---+---+---+ |
1525 |
1 | 1 0 | SN | IP-ID2 | |
1526 |
+---+---+---+---+---+---+---+---+ |
1527 |
2 | IP-ID2 | |
1528 |
+---+---+---+---+---+---+---+---+ |
1529 |
3 | IP-ID | |
1530 |
+---+---+---+---+---+---+---+---+ |
1531 |
|
1532 |
IP-ID2: For outer IP-ID field. |
1533 |
*/ |
1534 |
int code_EXT2_packet(struct sc_context *context, |
1535 |
struct sc_ip_context *ip_profile, |
1536 |
const struct iphdr *ip, |
1537 |
unsigned char *dest, |
1538 |
int counter) |
1539 |
{ |
1540 |
//Code for the extension |
1541 |
|
1542 |
unsigned char f_byte; |
1543 |
unsigned char s_byte; |
1544 |
unsigned short id; |
1545 |
|
1546 |
//its a bit confusing here but ip-id2 in the packet |
1547 |
//description means the first headers ip-id and ip-flags |
1548 |
//mean the first header and ip2-flags means the second |
1549 |
//ip-header |
1550 |
// 1 |
1551 |
f_byte = (ip_profile -> sn) & 0x07; |
1552 |
f_byte = f_byte << 3; |
1553 |
id = (ip_profile->ip_flags.id_delta) & 0x0700; |
1554 |
id = id >> 8; |
1555 |
f_byte |= id; |
1556 |
f_byte |= 0x80; |
1557 |
dest[counter] = f_byte; |
1558 |
counter++; |
1559 |
|
1560 |
// 2 |
1561 |
s_byte = (ip_profile->ip_flags .id_delta) & 0xff; |
1562 |
dest[counter] = s_byte; |
1563 |
counter++; |
1564 |
|
1565 |
// 3 |
1566 |
dest[counter] = (ip_profile ->ip2_flags.id_delta) & 0xff; |
1567 |
counter++; |
1568 |
return counter; |
1569 |
} |
1570 |
|
1571 |
/* |
1572 |
Coding the extension 3 part of the uo2-packet |
1573 |
|
1574 |
Extension 3 (5.7.5 && 5.11.4): |
1575 |
|
1576 |
0 1 2 3 4 5 6 7 |
1577 |
+-----+-----+-----+-----+-----+-----+-----+-----+ |
1578 |
1 | 1 1 | S | Mode | I | ip | ip2 | |
1579 |
+-----+-----+-----+-----+-----+-----+-----+-----+ |
1580 |
2 | Inner IP header flags | | if ip = 1 |
1581 |
+-----+-----+-----+-----+-----+-----+-----+-----+ |
1582 |
3 | Outer IP header flags | |
1583 |
+-----+-----+-----+-----+-----+-----+-----+-----+ |
1584 |
4 | SN | if S = 1 |
1585 |
+-----+-----+-----+-----+-----+-----+-----+-----+ |
1586 |
| | |
1587 |
5 / Inner IP header fields / variable, |
1588 |
| | |
1589 |
+-----+-----+-----+-----+-----+-----+-----+-----+ |
1590 |
6 | IP-ID | 2 octets, if I = 1 |
1591 |
+-----+-----+-----+-----+-----+-----+-----+-----+ |
1592 |
| | |
1593 |
7 / Outer IP header fields / variable, |
1594 |
| | |
1595 |
+-----+-----+-----+-----+-----+-----+-----+-----+ |
1596 |
|
1597 |
*/ |
1598 |
int code_EXT3_packet(struct sc_context *context, |
1599 |
struct sc_ip_context *ip_profile, |
1600 |
const struct iphdr *ip, |
1601 |
const struct iphdr *ip2, |
1602 |
unsigned char *dest, |
1603 |
int counter) |
1604 |
{ |
1605 |
//Code for the extension |
1606 |
int nr_of_ip_hdr = ip_profile->tmp_variables.nr_of_ip_hdr; |
1607 |
unsigned char f_byte; |
1608 |
unsigned short changed_f = ip_profile->tmp_variables.changed_fields; |
1609 |
unsigned short changed_f2 = ip_profile->tmp_variables.changed_fields2; |
1610 |
int nr_sn_bits = ip_profile->tmp_variables.nr_sn_bits; |
1611 |
int nr_ip_id_bits = ip_profile->tmp_variables.nr_ip_id_bits; |
1612 |
int nr_ip_id_bits2 = ip_profile->tmp_variables.nr_ip_id_bits2; |
1613 |
boolean have_inner = 0; |
1614 |
boolean have_outer = 0; |
1615 |
|
1616 |
// 1 |
1617 |
f_byte = 0xc0; |
1618 |
if(nr_sn_bits > 5){ |
1619 |
f_byte |= 0x20; |
1620 |
} |
1621 |
|
1622 |
f_byte = f_byte | (context -> c_mode) << 3; |
1623 |
//If random bit is set we have the ip-id field outside this function |
1624 |
rohc_debugf(1,"rnd_count_up: %d \n",ip_profile->ip_flags.rnd_count); |
1625 |
|
1626 |
|
1627 |
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
1628 |
if(nr_of_ip_hdr == 1){ |
1629 |
if ((nr_ip_id_bits > 0 && (context->rnd == 0))||(ip_profile->ip_flags.rnd_count < MAX_FO_COUNT && context->rnd == 0)){ |
1630 |
f_byte = f_byte | 0x04; |
1631 |
} |
1632 |
if(changed_dynamic_one_hdr(changed_f,&ip_profile->ip_flags,ip,context->rnd,context->nbo,context) || |
1633 |
changed_static_one_hdr(changed_f,&ip_profile->ip_flags,ip,context)) |
1634 |
{ |
1635 |
have_inner = 1; |
1636 |
f_byte = f_byte | 0x02; |
1637 |
} |
1638 |
} |
1639 |
else{ |
1640 |
if ((nr_ip_id_bits > 0 && (context->rnd2 == 0))||(ip_profile->ip2_flags.rnd_count < MAX_FO_COUNT && context->rnd2 == 0)){ |
1641 |
f_byte = f_byte | 0x04; |
1642 |
|
1643 |
} |
1644 |
if(changed_dynamic_one_hdr(changed_f,&ip_profile->ip_flags,ip,context->rnd,context->nbo,context) || |
1645 |
changed_static_one_hdr(changed_f,&ip_profile->ip_flags,ip,context)) |
1646 |
{ |
1647 |
have_outer = 1; |
1648 |
f_byte = f_byte | 0x01; |
1649 |
} |
1650 |
if(changed_dynamic_one_hdr(changed_f2,&ip_profile->ip2_flags,ip2,context->rnd2,context->nbo2,context) || |
1651 |
changed_static_one_hdr(changed_f2,&ip_profile->ip2_flags,ip2,context)) |
1652 |
{ |
1653 |
have_inner = 1; |
1654 |
f_byte = f_byte | 0x02; |
1655 |
} |
1656 |
|
1657 |
} |
1658 |
dest[counter] = f_byte; |
1659 |
counter++; |
1660 |
|
1661 |
|
1662 |
if(nr_of_ip_hdr == 1){ |
1663 |
// 2 |
1664 |
if(have_inner){ |
1665 |
counter = header_flags(context,changed_f,&ip_profile->ip_flags,counter,0, |
1666 |
nr_ip_id_bits,ip,dest,context->rnd,context->nbo); |
1667 |
} |
1668 |
// 4 |
1669 |
if(nr_sn_bits > 5){ |
1670 |
dest[counter] = (ip_profile -> sn) & 0xff; |
1671 |
counter++; |
1672 |
} |
1673 |
// 5 |
1674 |
if(have_inner){ |
1675 |
counter = header_fields(context,changed_f,&ip_profile->ip_flags,counter,0, |
1676 |
nr_ip_id_bits,ip,dest,context->rnd); |
1677 |
} |
1678 |
//6 |
1679 |
if(((nr_ip_id_bits > 0) && (context->rnd == 0)) || ((ip_profile->ip_flags.rnd_count-1 < MAX_FO_COUNT) && (context->rnd == 0))){ |
1680 |
|
1681 |
memcpy(&dest[counter], &ip->id, 2); |
1682 |
counter+=2; |
1683 |
} |
1684 |
} |
1685 |
else{ |
1686 |
// 2 |
1687 |
if(have_inner){ |
1688 |
counter = header_flags(context,changed_f2,&ip_profile->ip2_flags,counter,0, |
1689 |
nr_ip_id_bits2,ip2,dest,context->rnd2,context->nbo2); |
1690 |
} |
1691 |
// 3 |
1692 |
if(have_outer){ |
1693 |
counter = header_flags(context,changed_f,&ip_profile->ip_flags,counter,1, |
1694 |
nr_ip_id_bits,ip,dest,context->rnd,context->nbo); |
1695 |
|
1696 |
} |
1697 |
// 4 |
1698 |
if(nr_sn_bits > 5){ |
1699 |
dest[counter] = (ip_profile -> sn) & 0xff; |
1700 |
counter++; |
1701 |
} |
1702 |
// 5 |
1703 |
if(have_inner){ |
1704 |
counter = header_fields(context,changed_f2,&ip_profile->ip2_flags,counter,0, |
1705 |
nr_ip_id_bits2,ip2,dest,context->rnd2); |
1706 |
} |
1707 |
//6 |
1708 |
if(((nr_ip_id_bits2 > 0) && (context->rnd2 == 0)) || ((ip_profile->ip2_flags.rnd_count-1 < MAX_FO_COUNT) && (context->rnd2 == 0))){ |
1709 |
|
1710 |
memcpy(&dest[counter], &ip2->id, 2); |
1711 |
counter+=2; |
1712 |
} |
1713 |
|
1714 |
// 7 |
1715 |
if(have_outer){ |
1716 |
counter = header_fields(context,changed_f,&ip_profile->ip_flags,counter,1, |
1717 |
nr_ip_id_bits,ip,dest,context->rnd); |
1718 |
} |
1719 |
} |
1720 |
//No ip extension until list compression |
1721 |
return counter; |
1722 |
////////////////////////////////////////////////////////////////////////////////////////////////////// |
1723 |
} |
1724 |
|
1725 |
/* |
1726 |
Function coding header flags: |
1727 |
|
1728 |
For inner flags: |
1729 |
|
1730 |
+-----+-----+-----+-----+-----+-----+-----+-----+ |
1731 |
1 | Inner IP header flags | | if ip = 1 |
1732 |
| TOS | TTL | DF | PR | IPX | NBO | RND | 0** | 0** reserved |
1733 |
+-----+-----+-----+-----+-----+-----+-----+-----+ |
1734 |
|
1735 |
|
1736 |
or for outer flags: |
1737 |
|
1738 |
+-----+-----+-----+-----+-----+-----+-----+-----+ |
1739 |
2 | Outer IP header flags | |
1740 |
| TOS2| TTL2| DF2 | PR2 |IPX2 |NBO2 |RND2 | I2 | if ip2 = 1 |
1741 |
+-----+-----+-----+-----+-----+-----+-----+-----+ |
1742 |
*/ |
1743 |
int header_flags(struct sc_context *context, |
1744 |
unsigned short changed_f, |
1745 |
struct sc_ip_header *ip_hdr_profile, |
1746 |
int counter, |
1747 |
boolean is_outer, |
1748 |
int nr_ip_id_bits, |
1749 |
const struct iphdr *ip, |
1750 |
unsigned char *dest, |
1751 |
int context_rnd, |
1752 |
int context_nbo) |
1753 |
{ |
1754 |
int ip_h_f = 0; |
1755 |
|
1756 |
// 1 and 2 |
1757 |
if(is_changed(changed_f,MOD_TOS) || (ip_hdr_profile->tos_count < MAX_FO_COUNT)){ |
1758 |
ip_h_f |= 0x80; |
1759 |
} |
1760 |
if(is_changed(changed_f,MOD_TTL) || (ip_hdr_profile->ttl_count < MAX_FO_COUNT)){ |
1761 |
ip_h_f |= 0x40; |
1762 |
} |
1763 |
if(is_changed(changed_f,MOD_PROTOCOL) || (ip_hdr_profile->protocol_count < MAX_FO_COUNT)){ |
1764 |
ip_h_f |= 0x10; |
1765 |
} |
1766 |
|
1767 |
rohc_debugf(1,"DF=%d\n", GET_DF(ip->frag_off)); |
1768 |
ip_hdr_profile->df_count++; |
1769 |
ip_h_f |= GET_DF(ip->frag_off) << 5; |
1770 |
|
1771 |
ip_hdr_profile->nbo_count++; |
1772 |
ip_h_f |= (context_nbo) << 2; |
1773 |
|
1774 |
ip_hdr_profile->rnd_count++; |
1775 |
ip_h_f |= (context_rnd) << 1; |
1776 |
|
1777 |
// Only 2 |
1778 |
if(is_outer){ |
1779 |
if ((nr_ip_id_bits > 0 && (context_rnd == 0))||(ip_hdr_profile->rnd_count-1 < MAX_FO_COUNT && context_rnd == 0) ){ |
1780 |
ip_h_f |= 0x01; |
1781 |
|
1782 |
} |
1783 |
} |
1784 |
|
1785 |
|
1786 |
// 1 and 2 |
1787 |
dest[counter] = ip_h_f; |
1788 |
counter++; |
1789 |
|
1790 |
return counter; |
1791 |
} |
1792 |
|
1793 |
/* |
1794 |
Function coding header fields: |
1795 |
|
1796 |
For inner fields and outer fields (The function is called two times |
1797 |
one for inner and one for outer with different arguments): |
1798 |
|
1799 |
+-----+-----+-----+-----+-----+-----+-----+-----+ |
1800 |
1 | Type of Service/Traffic Class | if TOS = 1 |
1801 |
..... ..... ..... ..... ..... ..... ..... ..... |
1802 |
2 | Time to Live/Hop Limit | if TTL = 1 |
1803 |
..... ..... ..... ..... ..... ..... ..... ..... |
1804 |
3 | Protocol/Next Header | if PR = 1 |
1805 |
..... ..... ..... ..... ..... ..... ..... ..... |
1806 |
4 / IP extension headers / variable, if IPX = 1 |
1807 |
..... ..... ..... ..... ..... ..... ..... ..... |
1808 |
|
1809 |
Ip id is coded here for outer header fields |
1810 |
+-----+-----+-----+-----+-----+-----+-----+-----+ |
1811 |
5 | IP-ID | 2 octets, if I = 1 |
1812 |
+-----+-----+-----+-----+-----+-----+-----+-----+ |
1813 |
|
1814 |
4 is not supported. |
1815 |
|
1816 |
*/ |
1817 |
int header_fields(struct sc_context *context, |
1818 |
unsigned short changed_f, |
1819 |
struct sc_ip_header *ip_hdr_profile, |
1820 |
int counter, |
1821 |
boolean is_outer, |
1822 |
int nr_ip_id_bits, |
1823 |
const struct iphdr *ip, |
1824 |
unsigned char *dest, |
1825 |
int context_rnd) |
1826 |
{ |
1827 |
// 1 |
1828 |
if(is_changed(changed_f,MOD_TOS) || (ip_hdr_profile->tos_count < MAX_FO_COUNT)){ |
1829 |
ip_hdr_profile->tos_count++; |
1830 |
dest[counter] = ip->tos; |
1831 |
counter++; |
1832 |
} |
1833 |
|
1834 |
// 2 |
1835 |
if(is_changed(changed_f,MOD_TTL) || (ip_hdr_profile->ttl_count < MAX_FO_COUNT)){ |
1836 |
ip_hdr_profile->ttl_count++; |
1837 |
dest[counter] = ip->ttl; |
1838 |
counter++; |
1839 |
} |
1840 |
|
1841 |
// 3 |
1842 |
if(is_changed(changed_f,MOD_PROTOCOL) || (ip_hdr_profile->protocol_count < MAX_FO_COUNT) ){ |
1843 |
ip_hdr_profile->protocol_count++; |
1844 |
dest[counter] = ip->protocol; |
1845 |
counter++; |
1846 |
} |
1847 |
|
1848 |
// 5 |
1849 |
if(is_outer){ |
1850 |
if(((nr_ip_id_bits > 0) && (context_rnd == 0)) || ((ip_hdr_profile->rnd_count-1 < MAX_FO_COUNT) && (context_rnd == 0))){ |
1851 |
|
1852 |
memcpy(&dest[counter], &ip->id, 2); |
1853 |
counter+=2; |
1854 |
} |
1855 |
} |
1856 |
|
1857 |
|
1858 |
return counter; |
1859 |
} |
1860 |
|
1861 |
|
1862 |
|
1863 |
/*Decide what extension shall be used in the uo2 packet*/ |
1864 |
int decide_extension(struct sc_context *context) |
1865 |
{ |
1866 |
struct sc_ip_context *ip_profile = (struct sc_ip_context *)context->profile_context; |
1867 |
int nr_ip_id_bits = ip_profile->tmp_variables.nr_ip_id_bits; |
1868 |
int nr_ip_id_bits2 = ip_profile->tmp_variables.nr_ip_id_bits2; |
1869 |
int nr_sn_bits = ip_profile->tmp_variables.nr_sn_bits; |
1870 |
//if (ip_context->ttl_count < MAX_FO_COUNT || ip_context->tos_count < MAX_FO_COUNT || ip_context->df_count < MAX_FO_COUNT) |
1871 |
// return c_EXT3; |
1872 |
|
1873 |
if(ip_profile->tmp_variables.nr_of_ip_hdr == 1){ |
1874 |
if(ip_profile->tmp_variables.send_static > 0){ |
1875 |
rohc_debugf(2,"Vi har �drat static\n"); |
1876 |
return c_EXT3; |
1877 |
|
1878 |
} |
1879 |
if(ip_profile->tmp_variables.send_dynamic > 0){ |
1880 |
return c_EXT3; |
1881 |
} |
1882 |
if(nr_sn_bits < 5 && (nr_ip_id_bits == 0 || context->rnd == 1)){ |
1883 |
return c_NOEXT; |
1884 |
} |
1885 |
else if(nr_sn_bits <= 8 && nr_ip_id_bits <= 3){ |
1886 |
return c_EXT0; |
1887 |
} |
1888 |
else if(nr_sn_bits <= 8 && nr_ip_id_bits <= 11){ |
1889 |
return c_EXT1; |
1890 |
} |
1891 |
else{ |
1892 |
return c_EXT3; |
1893 |
} |
1894 |
} |
1895 |
else{ |
1896 |
if(ip_profile->tmp_variables.send_static > 0 || ip_profile->tmp_variables.send_dynamic > 0){ |
1897 |
return c_EXT3; |
1898 |
|
1899 |
} |
1900 |
if(nr_sn_bits < 5 && (nr_ip_id_bits == 0 || context->rnd == 1) |
1901 |
&& (nr_ip_id_bits2 == 0 || context->rnd2 == 1)){ |
1902 |
return c_NOEXT; |
1903 |
} |
1904 |
else if(nr_sn_bits <= 8 && nr_ip_id_bits <= 3 |
1905 |
&& (nr_ip_id_bits2 == 0 || context->rnd2 == 1)){ |
1906 |
return c_EXT0; |
1907 |
} |
1908 |
else if(nr_sn_bits <= 8 && nr_ip_id_bits <= 11 |
1909 |
&& (nr_ip_id_bits2 == 0 || context->rnd2 == 1)){ |
1910 |
return c_EXT1; |
1911 |
} |
1912 |
else if(nr_sn_bits <= 3 && nr_ip_id_bits <= 11 |
1913 |
&& nr_ip_id_bits2 <= 8){ |
1914 |
return c_EXT2; |
1915 |
} |
1916 |
|
1917 |
else{ |
1918 |
return c_EXT3; |
1919 |
} |
1920 |
} |
1921 |
|
1922 |
} |
1923 |
/* |
1924 |
Check if the static part of the context has been changed in any of the two first headers |
1925 |
*/ |
1926 |
int changed_static_both_hdr(struct sc_context *context, |
1927 |
const struct iphdr *ip, |
1928 |
const struct iphdr *ip2) |
1929 |
{ |
1930 |
int return_value = 0; |
1931 |
struct sc_ip_context *ip_profile = (struct sc_ip_context *)context->profile_context; |
1932 |
unsigned short changed_fields = ip_profile->tmp_variables.changed_fields; |
1933 |
unsigned short changed_fields2 = ip_profile->tmp_variables.changed_fields2; |
1934 |
return_value = changed_static_one_hdr(changed_fields,&ip_profile->ip_flags,ip,context); |
1935 |
|
1936 |
if(ip_profile->tmp_variables.nr_of_ip_hdr > 1){ |
1937 |
return_value += changed_static_one_hdr(changed_fields2,&ip_profile->ip2_flags,ip2,context); |
1938 |
} |
1939 |
return return_value; |
1940 |
} |
1941 |
|
1942 |
/* |
1943 |
Check if the static part of the context has been changed in one of header |
1944 |
*/ |
1945 |
int changed_static_one_hdr(unsigned short changed_fields, |
1946 |
struct sc_ip_header *ip_header, |
1947 |
const struct iphdr *ip, |
1948 |
struct sc_context *context) |
1949 |
{ |
1950 |
int return_value = 0; |
1951 |
struct sc_ip_context *org_ip_profile = (struct sc_ip_context *)context->profile_context; |
1952 |
|
1953 |
if (is_changed(changed_fields,MOD_PROTOCOL) || (ip_header->protocol_count < MAX_FO_COUNT)){ |
1954 |
rohc_debugf(2,"protocol_count %d\n",ip_header->protocol_count); |
1955 |
if (is_changed(changed_fields,MOD_PROTOCOL)) { |
1956 |
ip_header->protocol_count = 0; |
1957 |
org_ip_profile->fo_count = 0; |
1958 |
} |
1959 |
|
1960 |
|
1961 |
return_value += 1; |
1962 |
} |
1963 |
return return_value; |
1964 |
|
1965 |
} |
1966 |
|
1967 |
|
1968 |
/* |
1969 |
Check if the dynamic parts are changed, it returns the number of |
1970 |
dynamic bytes that are changed in both of the two first headers |
1971 |
*/ |
1972 |
int changed_dynamic_both_hdr(struct sc_context *context, |
1973 |
const struct iphdr *ip, |
1974 |
const struct iphdr *ip2) |
1975 |
{ |
1976 |
int return_value = 0; |
1977 |
struct sc_ip_context *ip_profile = (struct sc_ip_context *)context->profile_context; |
1978 |
unsigned short changed_fields = ip_profile->tmp_variables.changed_fields; |
1979 |
unsigned short changed_fields2 = ip_profile->tmp_variables.changed_fields2; |
1980 |
|
1981 |
return_value = changed_dynamic_one_hdr(changed_fields,&ip_profile->ip_flags,ip,context->rnd,context->nbo,context); |
1982 |
//rohc_debugf(1,"return_value = %d \n",return_value); |
1983 |
if(ip_profile->tmp_variables.nr_of_ip_hdr > 1){ |
1984 |
|
1985 |
return_value += changed_dynamic_one_hdr(changed_fields2,&ip_profile->ip2_flags,ip2,context->rnd2,context->nbo2,context); |
1986 |
} |
1987 |
return return_value; |
1988 |
} |
1989 |
|
1990 |
/* |
1991 |
Check if the dynamic part of the context has been changed in one of header |
1992 |
*/ |
1993 |
int changed_dynamic_one_hdr(unsigned short changed_fields, |
1994 |
struct sc_ip_header *ip_hdr_profile, |
1995 |
const struct iphdr *ip, |
1996 |
int context_rnd, |
1997 |
int context_nbo, |
1998 |
struct sc_context *context) |
1999 |
{ |
2000 |
int return_value = 0; |
2001 |
int small_flags = 0; |
2002 |
struct sc_ip_context *org_ip_profile = (struct sc_ip_context *)context->profile_context; |
2003 |
|
2004 |
if (is_changed(changed_fields,MOD_TOS) || (ip_hdr_profile->tos_count < MAX_FO_COUNT)){ |
2005 |
|
2006 |
if (is_changed(changed_fields,MOD_TOS)){ |
2007 |
ip_hdr_profile->tos_count = 0; |
2008 |
org_ip_profile->fo_count = 0; |
2009 |
} |
2010 |
|
2011 |
return_value += 1; |
2012 |
} |
2013 |
if(is_changed(changed_fields,MOD_TTL) || (ip_hdr_profile->ttl_count < MAX_FO_COUNT)){ |
2014 |
if (is_changed(changed_fields,MOD_TTL)){ |
2015 |
ip_hdr_profile->ttl_count = 0; |
2016 |
org_ip_profile->fo_count = 0; |
2017 |
} |
2018 |
|
2019 |
return_value += 1; |
2020 |
} |
2021 |
|
2022 |
if((GET_DF(ip->frag_off) != GET_DF(ip_hdr_profile->old_ip.frag_off)) || (ip_hdr_profile->df_count < MAX_FO_COUNT)){ |
2023 |
if (GET_DF(ip->frag_off) != GET_DF(ip_hdr_profile->old_ip.frag_off)){ |
2024 |
ip_hdr_profile->ttl_count = 0; |
2025 |
org_ip_profile->fo_count = 0; |
2026 |
} |
2027 |
return_value += 1; |
2028 |
} |
2029 |
|
2030 |
|
2031 |
|
2032 |
rohc_debugf(2,"rnd_count=%d nbo_count=%d\n", ip_hdr_profile->rnd_count, ip_hdr_profile->nbo_count); |
2033 |
if(context_rnd != ip_hdr_profile->old_rnd || ip_hdr_profile->rnd_count < MAX_FO_COUNT){ |
2034 |
|
2035 |
if (context_rnd != ip_hdr_profile->old_rnd) { |
2036 |
rohc_debugf(1,"RND changed, reseting count..\n"); |
2037 |
ip_hdr_profile->rnd_count = 0; |
2038 |
org_ip_profile->fo_count = 0; |
2039 |
} |
2040 |
|
2041 |
small_flags += 1; |
2042 |
|
2043 |
} |
2044 |
rohc_debugf(2,"nbo = %d, old_nbo = %d \n",context_nbo,ip_hdr_profile->old_nbo); |
2045 |
if(context_nbo != ip_hdr_profile->old_nbo || ip_hdr_profile->nbo_count < MAX_FO_COUNT){ |
2046 |
if (context_nbo != ip_hdr_profile->old_nbo) { |
2047 |
rohc_debugf(1,"NBO changed, reseting count..\n"); |
2048 |
ip_hdr_profile->nbo_count = 0; |
2049 |
org_ip_profile->fo_count = 0; |
2050 |
} |
2051 |
|
2052 |
small_flags += 1; |
2053 |
} |
2054 |
if(small_flags > 0) { |
2055 |
return_value += 1; |
2056 |
} |
2057 |
//rohc_debugf(1,"return_value = %d \n",return_value); |
2058 |
rohc_debugf(2,"changed_dynamic_both_hdr()=%d\n", return_value); |
2059 |
return return_value; |
2060 |
|
2061 |
|
2062 |
} |
2063 |
|
2064 |
|
2065 |
/* |
2066 |
Check if a specified field is changed, it is checked against the bitfield |
2067 |
created in the function changed_fields |
2068 |
*/ |
2069 |
boolean is_changed(unsigned short changed_fields,unsigned short check_field) |
2070 |
{ |
2071 |
if((changed_fields & check_field) > 0) |
2072 |
return 1; |
2073 |
else |
2074 |
return 0; |
2075 |
} |
2076 |
/* |
2077 |
This function returns a bitpattern, the bits that are set is changed |
2078 |
*/ |
2079 |
unsigned short changed_fields(struct sc_ip_header *ip_hdr_profile,const struct iphdr *ip) |
2080 |
{ |
2081 |
unsigned short ret_value = 0; |
2082 |
|
2083 |
//Kan version och header length bitordersskiftningar ha n�on betydelse fr oss?? |
2084 |
if(ip_hdr_profile -> old_ip.tos != ip -> tos) |
2085 |
ret_value |= MOD_TOS; |
2086 |
if(ip_hdr_profile -> old_ip.tot_len != ip -> tot_len) |
2087 |
ret_value |= MOD_TOT_LEN; |
2088 |
if(ip_hdr_profile -> old_ip.id != ip -> id) |
2089 |
ret_value |= MOD_ID; |
2090 |
if(ip_hdr_profile -> old_ip.frag_off != ip -> frag_off) |
2091 |
ret_value |= MOD_FRAG_OFF; |
2092 |
if(ip_hdr_profile -> old_ip.ttl != ip -> ttl) |
2093 |
ret_value |= MOD_TTL; |
2094 |
if(ip_hdr_profile -> old_ip.protocol != ip -> protocol) |
2095 |
ret_value |= MOD_PROTOCOL; |
2096 |
if(ip_hdr_profile -> old_ip.check != ip -> check) |
2097 |
ret_value |= MOD_CHECK; |
2098 |
if(ip_hdr_profile -> old_ip.saddr != ip -> saddr) |
2099 |
ret_value |= MOD_SADDR; |
2100 |
if(ip_hdr_profile -> old_ip.daddr != ip -> daddr) |
2101 |
ret_value |= MOD_DADDR; |
2102 |
|
2103 |
return ret_value; |
2104 |
} |
2105 |
/* |
2106 |
Function to determine if the ip-identification has nbo and if it is random |
2107 |
*/ |
2108 |
void check_ip_identification(struct sc_ip_header *ip_hdr_profile, |
2109 |
const struct iphdr *ip, |
2110 |
int *context_rnd, |
2111 |
int *context_nbo) |
2112 |
{ |
2113 |
|
2114 |
int id1, id2; |
2115 |
int nbo = -1; |
2116 |
|
2117 |
id1 = ntohs(ip_hdr_profile->old_ip.id); |
2118 |
id2 = ntohs(ip->id); |
2119 |
|
2120 |
|
2121 |
rohc_debugf(2,"1) id1=0x%04x id2=0x%04x\n", id1, id2); |
2122 |
|
2123 |
if (id2-id1 < IPID_MAX_DELTA && id2-id1 > 0) |
2124 |
{ |
2125 |
nbo = 1; |
2126 |
} else if ((id1 + IPID_MAX_DELTA > 0xffff) && (id2 < ((id1+IPID_MAX_DELTA) & 0xffff))) { |
2127 |
nbo = 1; |
2128 |
} |
2129 |
|
2130 |
if (nbo == -1) { |
2131 |
// change byte ordering and check nbo=0 |
2132 |
id1 = (id1>>8) | ((id1<<8) & 0xff00); |
2133 |
id2 = (id2>>8) | ((id2<<8) & 0xff00); |
2134 |
|
2135 |
rohc_debugf(2,"2) id1=0x%04x id2=0x%04x\n", id1, id2); |
2136 |
|
2137 |
if (id2-id1 < IPID_MAX_DELTA && id2-id1 > 0) |
2138 |
{ |
2139 |
nbo = 0; |
2140 |
} else if ((id1 + IPID_MAX_DELTA > 0xffff) && (id2 < ((id1+IPID_MAX_DELTA) & 0xffff))) { |
2141 |
nbo = 0; |
2142 |
} |
2143 |
} |
2144 |
|
2145 |
if (nbo == -1) { |
2146 |
rohc_debugf(2,"check_ip_id(): RND detected!\n"); |
2147 |
*context_rnd = 1; |
2148 |
|
2149 |
} else { |
2150 |
rohc_debugf(2,"check_ip_id(): NBO=%d\n", nbo); |
2151 |
*context_rnd = 0; |
2152 |
*context_nbo = nbo; |
2153 |
} |
2154 |
|
2155 |
} |
2156 |
|
2157 |
/* |
2158 |
A struct thate every function must have the first fieldtell what protocol this profile has. |
2159 |
The second row is the profile id-number, Then two strings that is for printing version and |
2160 |
description. And finaly pointers to functions that have to exist in every profile. |
2161 |
*/ |
2162 |
struct sc_profile c_ip_profile = { |
2163 |
0, // IP-Protocol |
2164 |
4, // Profile ID |
2165 |
"1.0b", // Version |
2166 |
"IP / Compressor", // Description |
2167 |
c_ip_create, |
2168 |
c_ip_destroy, |
2169 |
c_ip_check_context, |
2170 |
c_ip_encode, |
2171 |
c_ip_feedback |
2172 |
}; |
2173 |
|