• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2018, Sam Kumar <samkumar@cs.berkeley.edu>
3  *  Copyright (c) 2018, University of California, Berkeley
4  *  All rights reserved.
5  *
6  *  Redistribution and use in source and binary forms, with or without
7  *  modification, are permitted provided that the following conditions are met:
8  *  1. Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  *  2. Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  *  3. Neither the name of the copyright holder nor the
14  *     names of its contributors may be used to endorse or promote products
15  *     derived from this software without specific prior written permission.
16  *
17  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  *  POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 /* CIRCULAR BUFFER */
31 #include "cbuf.h"
32 #include "bitmap.h"
33 
34 #include <stdint.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <sys/types.h>
38 
39 #include <openthread/message.h>
40 #include <openthread/tcp.h>
41 
42 /*
43  * Copiers for copying from/into cbufs into/from arrays or OpenThraed messages
44  */
45 
cbuf_copy_into_buffer(void * buffer,size_t buffer_offset,const void * arr,size_t arr_offset,size_t num_bytes)46 void cbuf_copy_into_buffer(void* buffer, size_t buffer_offset, const void* arr, size_t arr_offset, size_t num_bytes) {
47     uint8_t* bufptr = (uint8_t*) buffer;
48     const uint8_t* arrptr = (const uint8_t*) arr;
49     memcpy(bufptr + buffer_offset, arrptr + arr_offset, num_bytes);
50 }
51 
cbuf_copy_from_buffer(void * arr,size_t arr_offset,const void * buffer,size_t buffer_offset,size_t num_bytes)52 void cbuf_copy_from_buffer(void* arr, size_t arr_offset, const void* buffer, size_t buffer_offset, size_t num_bytes) {
53     uint8_t* arrptr = (uint8_t*) arr;
54     const uint8_t* bufptr = (const uint8_t*) buffer;
55     memcpy(arrptr + arr_offset, bufptr + buffer_offset, num_bytes);
56 }
57 
cbuf_copy_into_message(void * buffer,size_t buffer_offset,const void * arr,size_t arr_offset,size_t num_bytes)58 void cbuf_copy_into_message(void* buffer, size_t buffer_offset, const void* arr, size_t arr_offset, size_t num_bytes) {
59     otMessage* message = (otMessage*) buffer;
60     uint8_t* arrptr = (uint8_t*) arr;
61     otMessageWrite(message, (uint16_t) buffer_offset, arrptr + arr_offset, (uint16_t) num_bytes);
62 }
63 
cbuf_copy_from_message(void * arr,size_t arr_offset,const void * buffer,size_t buffer_offset,size_t num_bytes)64 void cbuf_copy_from_message(void* arr, size_t arr_offset, const void* buffer, size_t buffer_offset, size_t num_bytes) {
65     uint8_t* arrptr = (uint8_t*) arr;
66     const otMessage* message = (const otMessage*) buffer;
67     otMessageRead(message, (uint16_t) buffer_offset, arrptr + arr_offset, (uint16_t) num_bytes);
68 }
69 
70 /*
71  * Cbuf implementation.
72  */
73 
cbuf_init(struct cbufhead * chdr,uint8_t * buf,size_t len)74 void cbuf_init(struct cbufhead* chdr, uint8_t* buf, size_t len) {
75     chdr->r_index = 0;
76     chdr->w_index = 0;
77     chdr->size = len;
78     chdr->buf = buf;
79 }
80 
cbuf_used_space(struct cbufhead * chdr)81 size_t cbuf_used_space(struct cbufhead* chdr) {
82     if (chdr->w_index >= chdr->r_index) {
83         return chdr->w_index - chdr->r_index;
84     } else {
85         return chdr->size + chdr->w_index - chdr->r_index;
86     }
87 }
88 
89 /* There's always one byte of lost space so I can distinguish between a full
90    buffer and an empty buffer. */
cbuf_free_space(struct cbufhead * chdr)91 size_t cbuf_free_space(struct cbufhead* chdr) {
92     return chdr->size - 1 - cbuf_used_space(chdr);
93 }
94 
cbuf_size(struct cbufhead * chdr)95 size_t cbuf_size(struct cbufhead* chdr) {
96     return chdr->size - 1;
97 }
98 
cbuf_empty(struct cbufhead * chdr)99 bool cbuf_empty(struct cbufhead* chdr) {
100     return (chdr->w_index == chdr->r_index);
101 }
102 
cbuf_write(struct cbufhead * chdr,const void * data,size_t data_offset,size_t data_len,cbuf_copier_t copy_from)103 size_t cbuf_write(struct cbufhead* chdr, const void* data, size_t data_offset, size_t data_len, cbuf_copier_t copy_from) {
104     size_t free_space = cbuf_free_space(chdr);
105     uint8_t* buf_data;
106     size_t fw_index;
107     size_t bytes_to_end;
108     if (free_space < data_len) {
109         data_len = free_space;
110     }
111     buf_data = chdr->buf;
112     fw_index = (chdr->w_index + data_len) % chdr->size;
113     if (fw_index >= chdr->w_index) {
114         copy_from(buf_data, chdr->w_index, data, data_offset, data_len);
115     } else {
116         bytes_to_end = chdr->size - chdr->w_index;
117         copy_from(buf_data, chdr->w_index, data, data_offset, bytes_to_end);
118         copy_from(buf_data, 0, data, data_offset + bytes_to_end, data_len - bytes_to_end);
119     }
120     chdr->w_index = fw_index;
121     return data_len;
122 }
123 
cbuf_read_unsafe(struct cbufhead * chdr,void * data,size_t data_offset,size_t numbytes,int pop,cbuf_copier_t copy_into)124 void cbuf_read_unsafe(struct cbufhead* chdr, void* data, size_t data_offset, size_t numbytes, int pop, cbuf_copier_t copy_into) {
125     uint8_t* buf_data = chdr->buf;
126     size_t fr_index = (chdr->r_index + numbytes) % chdr->size;
127     size_t bytes_to_end;
128     if (fr_index >= chdr->r_index) {
129         copy_into(data, data_offset, buf_data, chdr->r_index, numbytes);
130     } else {
131         bytes_to_end = chdr->size - chdr->r_index;
132         copy_into(data, data_offset, buf_data, chdr->r_index, bytes_to_end);
133         copy_into(data, data_offset + bytes_to_end, buf_data, 0, numbytes - bytes_to_end);
134     }
135     if (pop) {
136         chdr->r_index = fr_index;
137     }
138 }
139 
cbuf_read(struct cbufhead * chdr,void * data,size_t data_offset,size_t numbytes,int pop,cbuf_copier_t copy_into)140 size_t cbuf_read(struct cbufhead* chdr, void* data, size_t data_offset, size_t numbytes, int pop, cbuf_copier_t copy_into) {
141     size_t used_space = cbuf_used_space(chdr);
142     if (used_space < numbytes) {
143         numbytes = used_space;
144     }
145     cbuf_read_unsafe(chdr, data, data_offset, numbytes, pop, copy_into);
146     return numbytes;
147 }
148 
cbuf_read_offset(struct cbufhead * chdr,void * data,size_t data_offset,size_t numbytes,size_t offset,cbuf_copier_t copy_into)149 size_t cbuf_read_offset(struct cbufhead* chdr, void* data, size_t data_offset, size_t numbytes, size_t offset, cbuf_copier_t copy_into) {
150     size_t used_space = cbuf_used_space(chdr);
151     size_t oldpos;
152     if (used_space <= offset) {
153         return 0;
154     } else if (used_space < offset + numbytes) {
155         numbytes = used_space - offset;
156     }
157     oldpos = chdr->r_index;
158     chdr->r_index = (chdr->r_index + offset) % chdr->size;
159     cbuf_read_unsafe(chdr, data, data_offset, numbytes, 0, copy_into);
160     chdr->r_index = oldpos;
161     return numbytes;
162 }
163 
cbuf_pop(struct cbufhead * chdr,size_t numbytes)164 size_t cbuf_pop(struct cbufhead* chdr, size_t numbytes) {
165     size_t used_space = cbuf_used_space(chdr);
166     if (used_space < numbytes) {
167         numbytes = used_space;
168     }
169     chdr->r_index = (chdr->r_index + numbytes) % chdr->size;
170     return numbytes;
171 }
172 
cbuf_reference(const struct cbufhead * chdr,otLinkedBuffer * first,otLinkedBuffer * second)173 void cbuf_reference(const struct cbufhead* chdr, otLinkedBuffer* first, otLinkedBuffer* second) {
174     if (chdr->w_index >= chdr->r_index) {
175         first->mNext = NULL;
176         first->mData = &chdr->buf[chdr->r_index];
177         first->mLength = (uint16_t) (chdr->w_index - chdr->r_index);
178     } else {
179         first->mNext = second;
180         first->mData = &chdr->buf[chdr->r_index];
181         first->mLength = (uint16_t) (chdr->size - chdr->r_index);
182 
183         second->mNext = NULL;
184         second->mData = &chdr->buf[0];
185         second->mLength = (uint16_t) chdr->w_index;
186     }
187 }
188 
cbuf_reass_write(struct cbufhead * chdr,size_t offset,const void * data,size_t data_offset,size_t numbytes,uint8_t * bitmap,size_t * firstindex,cbuf_copier_t copy_from)189 size_t cbuf_reass_write(struct cbufhead* chdr, size_t offset, const void* data, size_t data_offset, size_t numbytes, uint8_t* bitmap, size_t* firstindex, cbuf_copier_t copy_from) {
190     uint8_t* buf_data = chdr->buf;
191     size_t free_space = cbuf_free_space(chdr);
192     size_t start_index;
193     size_t end_index;
194     size_t bytes_to_end;
195     if (offset > free_space) {
196         return 0;
197     } else if (offset + numbytes > free_space) {
198         numbytes = free_space - offset;
199     }
200     start_index = (chdr->w_index + offset) % chdr->size;
201     end_index = (start_index + numbytes) % chdr->size;
202     if (end_index >= start_index) {
203         copy_from(buf_data, start_index, data, data_offset, numbytes);
204         if (bitmap) {
205             bmp_setrange(bitmap, start_index, numbytes);
206         }
207     } else {
208         bytes_to_end = chdr->size - start_index;
209         copy_from(buf_data, start_index, data, data_offset, bytes_to_end);
210         copy_from(buf_data, 0, data, data_offset + bytes_to_end, numbytes - bytes_to_end);
211         if (bitmap) {
212             bmp_setrange(bitmap, start_index, bytes_to_end);
213             bmp_setrange(bitmap, 0, numbytes - bytes_to_end);
214         }
215     }
216     if (firstindex) {
217         *firstindex = start_index;
218     }
219     return numbytes;
220 }
221 
cbuf_reass_merge(struct cbufhead * chdr,size_t numbytes,uint8_t * bitmap)222 size_t cbuf_reass_merge(struct cbufhead* chdr, size_t numbytes, uint8_t* bitmap) {
223     size_t old_w = chdr->w_index;
224     size_t free_space = cbuf_free_space(chdr);
225     size_t bytes_to_end;
226     if (numbytes > free_space) {
227         numbytes = free_space;
228     }
229     chdr->w_index = (chdr->w_index + numbytes) % chdr->size;
230     if (bitmap) {
231         if (chdr->w_index >= old_w) {
232             bmp_clrrange(bitmap, old_w, numbytes);
233         } else {
234             bytes_to_end = chdr->size - old_w;
235             bmp_clrrange(bitmap, old_w, bytes_to_end);
236             bmp_clrrange(bitmap, 0, numbytes - bytes_to_end);
237         }
238     }
239     return numbytes;
240 }
241 
cbuf_reass_count_set(struct cbufhead * chdr,size_t offset,uint8_t * bitmap,size_t limit)242 size_t cbuf_reass_count_set(struct cbufhead* chdr, size_t offset, uint8_t* bitmap, size_t limit) {
243     size_t bitmap_size = BITS_TO_BYTES(chdr->size);
244     size_t until_end;
245     offset = (chdr->w_index + offset) % chdr->size;
246     until_end = bmp_countset(bitmap, bitmap_size, offset, limit);
247     if (until_end >= limit || until_end < (chdr->size - offset)) {
248         // If we already hit the limit, or if the streak ended before wrapping, then stop here
249         return until_end;
250     }
251     limit -= until_end; // effectively, this is our limit when continuing
252     // Continue until either the new limit or until we have scanned OFFSET bits (if we scan more than OFFSET bits, we'll wrap and scan some parts twice)
253     return until_end + bmp_countset(bitmap, bitmap_size, 0, limit < offset ? limit : offset);
254 }
255 
cbuf_reass_within_offset(struct cbufhead * chdr,size_t offset,size_t index)256 int cbuf_reass_within_offset(struct cbufhead* chdr, size_t offset, size_t index) {
257     size_t range_start = chdr->w_index;
258     size_t range_end = (range_start + offset) % chdr->size;
259     if (range_end >= range_start) {
260         return index >= range_start && index < range_end;
261     } else {
262         return index < range_end || (index >= range_start && index < chdr->size);
263     }
264 }
265