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, 2 months 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

# User Rev Content
1 pcg 1.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 pcg 1.3 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
29 pcg 1.1 */
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