ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/gvpe/src/rohc/comp.c
Revision: 1.3
Committed: Tue Apr 26 00:55:56 2005 UTC (19 years, 1 month ago) by pcg
Content type: text/plain
Branch: MAIN
CVS Tags: rel-2_01, rel-3_0, rel-2_2, rel-2_0, rel-2_21, rel-2_22, rel-2_25, HEAD
Changes since 1.2: +1 -1 lines
Log Message:
*** empty log message ***

File Contents

# Content
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: comp.c *
32 * Description: description *
33 ***************************************************************************/
34
35 #include "rohc.h"
36 #include "comp.h"
37 #include "c_util.h"
38
39 #include "decomp.h"
40 #include "d_util.h"
41
42 ///////////////////////////////////////////////////////////////////////
43 // Profile definitions and variables
44
45 // Profile IDs
46 #define ROHC_PROFILE_UNCOMPRESSED 0
47 #define ROHC_PROFILE_UDP 2
48 #define ROHC_PROFILE_UDPLITE 8
49 #define ROHC_PROFILE_IP 4
50
51 // The profiles.. in c_ip.c, c_udp.c, c_udp_lite.c, c_uncompressed.c
52 extern struct sc_profile c_ip_profile;
53 extern struct sc_profile c_uncompressed_profile;
54 extern struct sc_profile c_udp_profile;
55 extern struct sc_profile c_udp_lite_profile;
56
57 /* C_NUM_PROFILES is defined in comp.h */
58
59 // Pointers to all profiles:
60 static struct sc_profile *c_profiles[C_NUM_PROFILES] = {
61 &c_udp_profile,
62 &c_udp_lite_profile,
63 &c_ip_profile,
64 &c_uncompressed_profile
65 };
66
67 ////////////////////////////////////////////////////////////////////////
68 // Feedback variables
69 static void c_piggyback_destroy(struct sc_rohc *);
70 static int c_piggyback_get(struct sc_rohc *, unsigned char *buf);
71
72 ////////////////////////////////////////////////////////////////////////
73 // Context definitions functions
74 static void c_destroy_contexts(struct sc_rohc *);
75 static int c_create_contexts(struct sc_rohc *);
76 static int c_alloc_contexts(struct sc_rohc *, int num);
77
78
79 ////////////////////////////////////////////////////////////////////////
80 // Public functions
81
82 /* Allocate space for a compressor (transmit side) */
83 void *rohc_alloc_compressor(int max_cid)
84 {
85
86 struct sc_rohc *comp;
87 int i;
88 rohc_debugf(1, "ROHC: Allocating compressor\n");
89
90 comp = kmalloc(sizeof(struct sc_rohc), GFP_ATOMIC);
91 if (comp == NULL) {
92 rohc_debugf(0, "rohc_alloc_compressor() no mem for compressor!\n");
93 return NULL;
94 }
95
96 comp->enabled = 1;
97 comp->feedback_pointer = 0;
98 comp->max_cid = max_cid;
99 comp->large_cid = 0;
100 comp->mrru = 0;
101
102 for (i = 0; i < C_NUM_PROFILES; i++) {
103 comp->profiles[i] = 0;
104 }
105
106 comp->num_packets = 0;
107 comp->total_compressed_size = 0;
108 comp->total_uncompressed_size = 0;
109
110 for (i=0; i<FEEDBACK_BUFFER_SIZE; i++) {
111 comp->feedback_buffer[i] = (void*)0;
112 comp->feedback_size[i] = 0;
113 }
114
115 if (!c_create_contexts(comp)) {
116 return NULL;
117 }
118
119 return comp;
120 }
121
122
123 /* Free space used by a compressor */
124 void rohc_free_compressor(struct sc_rohc *comp) {
125
126 rohc_debugf(2,"ROHC: Free contexts\n");
127 // free memory used by contexts..
128 c_destroy_contexts(comp);
129
130 rohc_debugf(2,"ROHC: Free piggybacks\n");
131 // destroy unsent piggybacked feedback
132 c_piggyback_destroy(comp);
133
134 // free profile array
135 rohc_debugf(2,"ROHC: Free profiles\n");
136
137 // free compressor..
138 kfree(comp);
139 }
140
141
142 /* Compress a packet */
143 int rohc_compress(struct sc_rohc *comp, unsigned char *ibuf, int isize,
144 unsigned char *obuf, int osize)
145 {
146 struct iphdr *ip = (struct iphdr *)(ibuf); // + PPP_HDRLEN);
147 int proto = ip->protocol;
148 struct sc_profile *p;
149 struct sc_context *c;
150 int feedback_size, payload_size, payload_offset;
151 int size, esize;
152
153 if (comp == 0) {
154 rohc_debugf(0, "c_compress(): comp=null!\n");
155 return 0;
156 }
157
158 if (ip->version != 4) {
159 rohc_debugf(0, "Wrong IP version (%d)\n", ip->version);
160 return 0;
161 }
162
163 if (ip->ihl*4 != 20) {
164 rohc_debugf(0, "Wrong IP header size (%d)\n", ip->ihl);
165 return 0;
166 }
167
168 // Get profile based on ip->protocol..
169 rohc_debugf(2,"c_compress(): protocoll %d \n", proto);
170 p = c_get_profile_from_protocol(comp, proto);
171
172 if (p == 0) // use IP-profile if no profile was found based on the protocol
173 {
174 rohc_debugf(2,"c_compress(): Using IP profile\n");
175 p = c_get_profile_from_id(comp, ROHC_PROFILE_IP);
176
177 if (p == 0) { // Use Uncompressed-profile if IP profile was not found..
178 rohc_debugf(0,"c_compress(): Using UNCOMPRESSED profile\n");
179 p = c_get_profile_from_id(comp, ROHC_PROFILE_UNCOMPRESSED);
180
181 if (p == 0) {
182 rohc_debugf(0,"c_compress(): No profile found, giving up\n");
183 return 0;
184 }
185 }
186 }
187
188
189 // Get Context using help from the profiles..
190 c = c_find_context(comp, p, ip);
191
192 if (c==0) // skapa nytt context
193 c = c_create_context(comp, p, ip);
194 else if (c==(struct sc_context*)-1) {
195 // the profile dedected anomalities in ip-packet (such as fragments) that made
196 // it un-compressible - switch to Uncompressed profile!
197
198 p = c_get_profile_from_id(comp, ROHC_PROFILE_UNCOMPRESSED);
199 c = c_find_context(comp, p, ip); // find the uncompressed
200 if (c==0)
201 c = c_create_context(comp, p, ip);
202 }
203
204
205 c->latest_used = get_milliseconds();
206
207 // copy PPP header
208 //memcpy(obuf, rptr, PPP_HDRLEN);
209 // change protocol in ppp header to rohc-over-ppp identifier???
210 size = 0; //PPP_HDRLEN;
211
212 // add feedback
213 feedback_size = c_piggyback_get(comp, obuf);
214 obuf += feedback_size;
215 size += feedback_size;
216
217 // use profile to compress packet
218 esize = p->encode(c, ip, isize, obuf, osize - size, &payload_offset);
219
220 if (esize < 0) { // error while compressing.. use uncompressed..
221 if (c->num_send_packets <= 1) { // free context
222 c->profile->destroy(c);
223 c->used = 0;
224 }
225
226 p = c_get_profile_from_id(comp, ROHC_PROFILE_UNCOMPRESSED);
227 c = c_find_context(comp, p, ip); // find the uncompressed
228 if (c==0)
229 c = c_create_context(comp, p, ip);
230
231 if (c!=0)
232 esize = p->encode(c, ip, isize, obuf, osize - size, &payload_offset);
233 else {
234 rohc_debugf(0, "c_compress(): Failed to create uncompressed context!\n");
235 return 0;
236 }
237 }
238
239 size += esize;
240 obuf += esize;
241
242 payload_size = ntohs(ip->tot_len) - payload_offset;
243
244 rohc_debugf(2,"c_compress(): ROHC size=%d, Payload size=%d (totlen=%d, ihl=%d), outbut buffer size=%d\n", size, payload_size, ntohs(ip->tot_len), ip->ihl*4, osize);
245
246 if (size + payload_size > osize) // packet to big!!!
247 {
248 // do uncompressed!!
249 rohc_debugf(0,"ROHC packet to large (osize=%d, isize=%d)\n", size+payload_size, isize);
250 return 0;
251 }
252
253 // copy payload to rohc packet..
254 memcpy(obuf, ((unsigned char*)ip) + payload_offset, payload_size);
255
256 obuf += payload_size;
257 size += payload_size;
258
259 // Update statistic..
260 comp->num_packets ++;
261 comp->total_uncompressed_size += isize;
262 comp->total_compressed_size += size;
263
264 c->total_uncompressed_size += isize;
265 c->total_compressed_size += size;
266 c->header_uncompressed_size += payload_offset;
267 c->header_compressed_size += esize;
268 c->num_send_packets ++;
269 c_add_wlsb(c->total_16_uncompressed, 0, 0, isize);
270 c_add_wlsb(c->total_16_compressed, 0,0, size);
271 c_add_wlsb(c->header_16_uncompressed, 0, 0, payload_offset);
272 c_add_wlsb(c->header_16_compressed, 0,0, esize);
273
274 return size;
275 }
276
277 // Used in the handshake to active profiles that are can be used
278 void rohc_activate_profile(struct sc_rohc * comp, int profile)
279 {
280 int i;
281 for (i = 0; i < C_NUM_PROFILES; i++) {
282 if (c_profiles[i]->id == profile) {
283 comp->profiles[i] = 1;
284 return;
285 }
286 }
287 rohc_debugf(0, "Unknown ROHC profile with id = %d\n", profile);
288 }
289
290 int rohc_c_using_small_cid(struct sc_rohc * comp)
291 {
292 return !comp->large_cid;
293 }
294
295 void rohc_c_set_header(struct sc_rohc *compressor, int header)
296 {
297 compressor->max_header_size = header;
298 }
299
300 void rohc_c_set_mrru(struct sc_rohc *compressor, int value) {
301 compressor->mrru = value;
302 }
303
304 void rohc_c_set_max_cid(struct sc_rohc *compressor, int value) {
305 if (compressor->large_cid) {
306 if (value > 0 && value < 65536)
307 compressor->max_cid = value;
308 } else {
309 if (value > 0 && value < 16)
310 compressor->max_cid = value;
311 }
312 }
313
314 void rohc_c_set_large_cid(struct sc_rohc *compressor, int value) {
315 if (value) {
316 compressor->large_cid = 1;
317 } else {
318 compressor->large_cid = 0;
319 if (compressor->max_cid > 15)
320 compressor->max_cid = 15;
321 }
322 }
323
324 void rohc_c_set_connection_type(struct sc_rohc *compressor, int value) {
325 compressor->connection_type = value;
326 }
327
328 void rohc_c_set_enable(struct sc_rohc *compressor, int value) {
329 compressor->enabled = value;
330 }
331
332 int rohc_c_is_enabled(struct sc_rohc *compressor) {
333 return compressor->enabled;
334 }
335
336
337 /* Called by proc_rohc to get information about available profiles (used in usermode ppp for handshake)*/
338 int rohc_c_info(char *buffer) {
339 int i;
340
341 sprintf(buffer, "%s\n", "---Information");
342
343 //"Profiles: 1 2 3 4"
344 sprintf(buffer, "%s%s", buffer, "Profiles:");
345 for (i=0; i<C_NUM_PROFILES; i++) {
346 sprintf(buffer, "%s%d ", buffer, c_profiles[i]->id);
347 }
348 sprintf(buffer, "%s\n", buffer);
349
350 return strlen(buffer);
351 }
352
353 /* Called by proc_rohc to get information about the compressor */
354 int rohc_c_statistics(struct sc_rohc *comp, char *buffer)
355 {
356 char *save;
357 struct sc_profile *p;
358 int i,v;
359
360 save = buffer;
361
362 // Instance part..
363 buffer += strlen(buffer);
364 sprintf(buffer, "\n---Instance\n");
365 buffer += strlen(buffer);
366 sprintf(buffer, "CREATOR:%s\n", "LULEA/SMD143/2003");
367 buffer += strlen(buffer);
368 sprintf(buffer, "VERSION NO:%s\n", "1.0");
369 buffer += strlen(buffer);
370 sprintf(buffer, "STATUS:%s\n", comp->enabled?"ENABLED":"DISABLED");
371 buffer += strlen(buffer);
372 sprintf(buffer, "NO COMPRESSED FLOWS:%d\n", comp->num_used);
373 buffer += strlen(buffer);
374 sprintf(buffer, "TOTAL NO PACKETS:%d\n", comp->num_packets);
375 buffer += strlen(buffer);
376
377 if (comp->total_uncompressed_size != 0)
378 v = (100 * comp->total_compressed_size) / comp->total_uncompressed_size;
379 else
380 v = 0;
381 sprintf(buffer, "TOTAL COMPRESSION RATIO:%d%%\n", v);
382 buffer += strlen(buffer);
383 sprintf(buffer, "MAX_CID:%d\n", comp->max_cid);
384 buffer += strlen(buffer);
385 sprintf(buffer, "MRRU:%d\n", 4); // comp->mrru
386 buffer += strlen(buffer);
387 sprintf(buffer, "LARGE_CID:%s\n", comp->large_cid?"YES" : "NO");
388 buffer += strlen(buffer);
389 sprintf(buffer, "CONNECTION_TYPE:%d\n", 3);
390 buffer += strlen(buffer);
391 sprintf(buffer, "FEEDBACK_FREQ:%d\n", 7); // comp-> ??
392 buffer += strlen(buffer);
393
394 // profiles part
395 for (i=0; i<C_NUM_PROFILES; i++) {
396 p = c_profiles[i];
397
398 sprintf(buffer, "\n---Profile\n");
399 buffer += strlen(buffer);
400 sprintf(buffer, "PROFILE NO:%d\n", p->id);
401 buffer += strlen(buffer);
402 sprintf(buffer, "ACTIVE:%s\n", comp->profiles[i]?"YES":"NO");
403 buffer += strlen(buffer);
404 sprintf(buffer, "VERSION NO:%s\n", p->version);
405 buffer += strlen(buffer);
406 sprintf(buffer, "PROFILE TYPE:%s\n", p->description);
407 buffer += strlen(buffer);
408 }
409
410 return strlen(save);
411 }
412
413 /* Called by proc_rohc to get information about a context (cid=index)
414 * Returns -2 if index is larger than allocated cids
415 * Returns -1 if cid is unused
416 * Else returns length if buffer..
417 */
418 int rohc_c_context(struct sc_rohc *comp, int index, char *buffer) {
419 struct sc_context *c;
420 char *save;
421 char *modes[4]= {"error", "U-mode", "O-mode", "R-mode"};
422 char *states[4] = {"error", "IR", "FO", "SO"};
423 int v;
424
425 // Compressor Contexts
426 if (index >= comp->num_allocated)
427 return -2;
428
429 c = &comp->contexts[index];
430 if (!c->used)
431 return -1;
432
433 save = buffer;
434 buffer += strlen(buffer);
435 sprintf(buffer, "\n%s\n", "---Context");
436 buffer += strlen(buffer);
437 sprintf(buffer, "CONTEXTTYPE:Compressor\n");
438 buffer += strlen(buffer);
439 sprintf(buffer, "CID:%d\n", c->cid);
440 buffer += strlen(buffer);
441 sprintf(buffer, "CID_STATE:%s\n", c->used?"USED":"UNUSED");
442 buffer += strlen(buffer);
443 sprintf(buffer, "STATE:%s\n", states[c->c_state]);
444 buffer += strlen(buffer);
445 sprintf(buffer, "MODE:%s\n", modes[c->c_mode]);
446 buffer += strlen(buffer);
447 sprintf(buffer, "PROFILE:%s\n", c->profile->description);
448 buffer += strlen(buffer);
449
450 if (c->total_uncompressed_size != 0)
451 v = (100*c->total_compressed_size) / c->total_uncompressed_size;
452 else
453 v = 0;
454 if (v < 0) {
455 rohc_debugf(0, "comp: total_compressed_size=%d total_uncompressed_size=%d\n", c->total_compressed_size, c->total_uncompressed_size);
456 }
457 sprintf(buffer, "TOTALCOMPRATIOALLPACK:%d%%\n", v);
458 buffer += strlen(buffer);
459
460 if (c->header_uncompressed_size != 0)
461 v = (100*c->header_compressed_size) / c->header_uncompressed_size;
462 else
463 v = 0;
464 sprintf(buffer, "TOTALCOMPRATIOALLPACKHEAD:%d%%\n", v);
465 buffer += strlen(buffer);
466
467 if (c->num_send_packets != 0)
468 v = c->total_compressed_size / c->num_send_packets;
469 else
470 v = 0;
471 sprintf(buffer, "MEANCOMPPACKSIZEALLPACK:%d\n", v);
472 buffer += strlen(buffer);
473
474 if (c->num_send_packets != 0)
475 v = c->header_compressed_size / c->num_send_packets;
476 else
477 v = 0;
478 sprintf(buffer, "MEANHEADSIZEALLCOMPHEAD:%d\n", v);
479 buffer += strlen(buffer);
480
481 v = c_sum_wlsb(c->total_16_uncompressed);
482 if (v != 0)
483 v = (100*c_sum_wlsb(c->total_16_compressed)) / v;
484 sprintf(buffer, "COMPRATIOLAST16PACK:%d%%\n", v);
485 buffer += strlen(buffer);
486
487 v = c_sum_wlsb(c->header_16_uncompressed);
488 if (v != 0)
489 v = (100*c_sum_wlsb(c->header_16_compressed)) / v;
490 sprintf(buffer, "COMPRATIOLAST16PACKHEAD:%d%%\n", v);
491 buffer += strlen(buffer);
492
493 v = c_mean_wlsb(c->total_16_compressed);
494 sprintf(buffer, "MEANCOMPPACKSIZELAST16PACK:%d\n", v);
495 buffer += strlen(buffer);
496
497 v = c_mean_wlsb(c->header_16_compressed);
498 sprintf(buffer, "MEANHEADSIZELAST16COMPHEAD:%d\n", v);
499 buffer += strlen(buffer);
500 sprintf(buffer, "CONTEXTACTIVATIONTIME:%d\n", (get_milliseconds() - c->first_used)/1000);
501 buffer += strlen(buffer);
502 sprintf(buffer, "CONTEXTIDLETIME:%d\n", (get_milliseconds() - c->latest_used)/1000);
503 buffer += strlen(buffer);
504 sprintf(buffer, "NOSENTPACKETS:%d\n", c->num_send_packets);
505 buffer += strlen(buffer);
506 sprintf(buffer, "NOSENTIRPACKETS:%d\n", c->num_send_ir);
507 buffer += strlen(buffer);
508 sprintf(buffer, "NOSENTIRDYNPACKETS:%d\n", c->num_send_ir_dyn);
509 buffer += strlen(buffer);
510 sprintf(buffer, "NORECVFEEDBACKS:%d\n", c->num_recv_feedbacks);
511
512 return strlen(save);
513 }
514
515
516 ////////////////////////////////////////////////////////////////////////
517 // Generic profile functions
518
519 // Retrieve a profile given a profile_id
520 struct sc_profile *c_get_profile_from_id(struct sc_rohc *comp, int profile_id)
521 {
522 int i;
523 for (i=0; i<C_NUM_PROFILES; i++)
524 {
525 if (c_profiles[i]->id == profile_id && comp->profiles[i]==1)
526 return c_profiles[i];
527 }
528
529 // log this failure maybe..
530 return NULL;
531 }
532
533 // Retrieve a profile given a (ip) protocol id
534 struct sc_profile *c_get_profile_from_protocol(struct sc_rohc *comp, int protocol)
535 {
536 int i;
537 for (i=0; i<C_NUM_PROFILES; i++)
538 {
539 if (c_profiles[i]->protocol == protocol && comp->profiles[i]==1)
540 return c_profiles[i];
541 }
542
543 return NULL;
544 }
545
546 ////////////////////////////////////////////////////////////////////////
547 // Generic context functions
548
549
550 // Allocate the context array
551 static int c_alloc_contexts(struct sc_rohc *comp, int num) {
552 if (num > comp->max_cid+1)
553 num = comp->max_cid+1;
554
555 if (comp->num_allocated < num) {
556 struct sc_context *tmp;
557 int i;
558
559 tmp = kmalloc(sizeof(struct sc_context) * num, GFP_ATOMIC);
560 if (tmp == 0) {
561 rohc_debugf(0,"rohc_alloc_compressor() no mem for contexts!\n");
562 return 0;
563 }
564
565 for (i=0; i<num; i++) {
566 tmp[i].used = 0;
567 }
568
569 if (comp->num_allocated > 0 && comp->contexts) {
570 memcpy(tmp,comp->contexts, comp->num_allocated * sizeof(struct sc_context));
571 kfree(comp->contexts);
572 }
573
574 for (i=comp->num_allocated; i<num; i++) {
575 tmp[i].total_16_uncompressed = c_create_wlsb(32, 16, 0); // create a window with 16 entries..
576 tmp[i].total_16_compressed = c_create_wlsb(32, 16, 0);
577 tmp[i].header_16_uncompressed = c_create_wlsb(32, 16, 0);
578 tmp[i].header_16_compressed = c_create_wlsb(32, 16, 0);
579 }
580
581 comp->contexts = tmp;
582 comp->num_allocated = num;
583 }
584
585 return 1;
586 }
587
588 // Skapa en ny context
589 struct sc_context *c_create_context(struct sc_rohc *comp, struct sc_profile *profile, struct iphdr *ip) {
590 struct sc_context *c;
591 int index, i;
592
593 index = 0;
594
595 if (comp->num_used >= comp->max_cid+1) {
596 // find oldest or one not in use:
597 int minimum;
598
599 find_oldest:
600
601 index = 0;
602 minimum = 0x7fffffff;
603 for (i=0; i<comp->num_allocated; i++) {
604 if (comp->contexts[i].used == 0) {
605 index = i;
606 break;
607 } else if (comp->contexts[i].latest_used < minimum) {
608 minimum = comp->contexts[i].latest_used;
609 index = i;
610 }
611 }
612
613 if (comp->contexts[index].used) {
614 // free memory..
615 rohc_debugf(2,"Freeing memory for recycled context (cid=%d)\n", index);
616 comp->contexts[index].profile->destroy(&comp->contexts[index]);
617 }
618
619 } else if (comp->num_used >= comp->num_allocated) {
620 if (!c_alloc_contexts(comp, comp->num_used * 2))
621 goto find_oldest;
622
623 index = comp->num_used;
624 comp->num_used ++;
625
626 } else{
627 index = -1;
628 for (i=0; i<comp->num_used; i++) {
629 if (comp->contexts[i].used==0) {
630 index = i;
631 break;
632 }
633 }
634
635 if (index==-1) {
636 index = comp->num_used;
637 comp->num_used++;
638 }
639 }
640
641
642 c = &comp->contexts[index];
643
644 c->used = 1;
645 c->first_used = get_milliseconds();
646 c->latest_used = get_milliseconds();
647
648 c->total_uncompressed_size = 0;
649 c->total_compressed_size = 0;
650 c->header_uncompressed_size = 0;
651 c->header_compressed_size = 0;
652 c->num_send_packets = 0;
653 c->num_send_ir = 0;
654 c->num_send_ir_dyn = 0;
655 c->num_recv_feedbacks = 0;
656
657 c->cid = index;
658
659 c->profile = profile;
660 c->profile_id = profile->id;
661
662 c->c_mode = U;
663 c->c_state = IR;
664
665 c->nbo = 1;
666 c->rnd = 0;
667
668 c->nbo2 = 1;
669 c->rnd2 = 0;
670
671 c->compressor = comp;
672 c->latest_used = get_milliseconds();
673
674 rohc_debugf(1, "Creating context CID=%d (numUsed=%d)\n", c->cid, comp->num_used);
675
676 // Create profile specific context and initialize..
677 if (profile->create(c, ip) == 0) {
678 c->used = 0;
679 return NULL;
680 }
681
682 return c;
683 }
684
685
686
687 // Find context given a profile and a ip packet..
688 struct sc_context *c_find_context(struct sc_rohc *comp, struct sc_profile *profile, struct iphdr *ip) {
689 int i;
690 int ret;
691 struct sc_context *c;
692
693 rohc_debugf(2,"c_find_context(): %d\n", comp->num_used);
694
695 for (i=0; i<comp->num_used; i++) {
696 c = &comp->contexts[i];
697
698 if (c && !c->used) {
699 rohc_debugf(1,"Using unused context CID=%d\n", c->cid);
700 return c;
701 }
702 if (c && c->used && c->profile_id==profile->id) {
703 ret = c->profile->check_context(c, ip);
704
705 if (ret==-1)
706 return (struct sc_context*)-1;
707 if (ret) {
708 rohc_debugf(1,"Using context CID=%d\n", c->cid);
709 return c;
710 }
711 }
712 }
713
714 rohc_debugf(2,"c_find_context(): No context was found\n");
715 return NULL; // no matching context was found..
716 }
717
718
719 // Get context, given the CID
720 struct sc_context *c_get_context(struct sc_rohc *comp, int cid) {
721 if (cid > comp->num_allocated)
722 return NULL;
723 if (cid > comp->num_used)
724 return NULL;
725 if (comp->contexts[cid].used == 0)
726 return NULL;
727
728 return &comp->contexts[cid];
729 }
730
731
732 // Allocate context memory..
733 static int c_create_contexts(struct sc_rohc *comp) {
734 comp->num_used = 0;
735 comp->num_allocated = 0;
736 comp->contexts = 0;
737
738 return c_alloc_contexts(comp, 4); // start with 4 contexts from the beginning..
739 }
740
741
742 // Deallocate all contexts including their profile specific context
743 static void c_destroy_contexts(struct sc_rohc *comp) {
744 if (comp->num_allocated > 0) {
745 int i;
746 for (i=0; i<comp->num_allocated; i++) {
747
748 if (comp->contexts[i].used && comp->contexts[i].profile != 0)
749 comp->contexts[i].profile->destroy(&comp->contexts[i]);
750
751 c_destroy_wlsb(comp->contexts[i].total_16_uncompressed);
752 c_destroy_wlsb(comp->contexts[i].total_16_compressed);
753 c_destroy_wlsb(comp->contexts[i].header_16_uncompressed);
754 c_destroy_wlsb(comp->contexts[i].header_16_compressed);
755
756 comp->contexts[i].used = 0;
757
758 }
759
760 kfree(comp->contexts);
761 }
762 }
763
764
765
766 ////////////////////////////////////////////////////////////////////////
767 // Feedback functions for piggybacking
768
769 // Add this feedback to the next outgoing ROHC packet:
770 void c_piggyback_feedback(struct sc_rohc *comp, unsigned char *feedback, int size) {
771 if (comp->feedback_pointer >= FEEDBACK_BUFFER_SIZE) // log this failure maybe?
772 return;
773
774 comp->feedback_buffer[comp->feedback_pointer] = kmalloc(size, GFP_ATOMIC);
775 if (comp->feedback_buffer[comp->feedback_pointer] == 0) {
776 rohc_debugf(0,"c_piggyback_feedback() no mem for feedback!\n");
777 return;
778 }
779 memcpy(comp->feedback_buffer[comp->feedback_pointer], feedback, size);
780 comp->feedback_size[comp->feedback_pointer] = size;
781
782 comp->feedback_pointer++;
783 }
784
785 // Retrieve one feedback and store in buf. Return length of feedback
786 static int c_piggyback_get(struct sc_rohc *comp, unsigned char *buf) {
787 if (comp->feedback_pointer > 0) {
788 int size;
789 int index=0;
790
791 comp->feedback_pointer--;
792 size = comp->feedback_size[comp->feedback_pointer];
793 if (size < 8) {
794 buf[index] = 0xf0 | size;
795 index++;
796 } else {
797 buf[index] = 0xf0;
798 index++;
799 buf[index] = size;
800 index++;
801 }
802
803 memcpy(buf+index, comp->feedback_buffer[comp->feedback_pointer], size);
804
805 kfree(comp->feedback_buffer[comp->feedback_pointer]);
806 comp->feedback_size[comp->feedback_pointer] = 0;
807
808 return index + size;
809 }
810
811 // No feedback exists..
812 return 0;
813 }
814
815 // Destory memory allocated by the feedback buffer
816 static void c_piggyback_destroy(struct sc_rohc *comp) {
817 int i;
818
819 for (i=0; i<FEEDBACK_BUFFER_SIZE; i++) {
820 if (comp->feedback_size[i] > 0 && comp->feedback_buffer[i] != 0)
821 kfree(comp->feedback_buffer[i]);
822 }
823 }
824
825 ////////////////////////////////////////////////////////////////////////
826 // Feedback functions delivery to right profile/context..
827
828
829 // When feedback is received by the decompressor, this function is called
830 // and delivers that to the right profile/context..
831 void c_deliver_feedback(struct sc_rohc *comp, unsigned char *packet, int size) {
832 struct sc_context *c;
833 struct sc_feedback feedback;
834 unsigned char *p = packet;
835
836 feedback.size = size;
837
838 if (comp->large_cid) { // decode large cid.at p[0..3]
839 feedback.cid = d_sdvalue_decode(p);
840 p += d_sdvalue_size(p);
841 } else {
842 if (d_is_add_cid(p)) {
843 feedback.cid = d_decode_add_cid(p);
844 p++;
845 } else
846 feedback.cid = 0;
847 }
848
849 feedback.specific_size = size - (p - packet);
850 rohc_debugf(2,"feedback size = %d\n",feedback.specific_size);
851 if (feedback.specific_size == 1)
852 feedback.type = 1; // FEEDBACK-1
853 else {
854 feedback.type = 2; // FEEDBACK-2
855 feedback.acktype = p[0]>>6;
856 }
857
858 feedback.specific_offset = (p - packet);
859 feedback.data = kmalloc(feedback.size, GFP_ATOMIC);
860
861 if (feedback.data == 0) {
862 rohc_debugf(0, "c_deliver_feedback(): no mem for feedback data\n");
863 return;
864 }
865
866 rohc_debugf(2, "spec size %d\n",feedback.specific_size);
867
868 memcpy(feedback.data,packet,feedback.size );
869
870 // find cid.. get context
871 c = c_get_context(comp,feedback.cid);
872 if (c==0){
873 // Error: Context was not found..
874 rohc_debugf(0, "c_deliver_feedback(): Context not found (cid=%d)\n", feedback.cid);
875 kfree(feedback.data);
876 return;
877 }
878
879 c->num_recv_feedbacks++;
880
881 // deliver feedback to profile with the context..
882 c->profile->feedback(c, &feedback);
883
884 kfree(feedback.data);
885
886 }
887
888
889