1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) 2022 Huawei Device Co., Ltd.
4 *
5 * Description: This file implements the function
6 * of decapsulating the NewIP protocol header.
7 *
8 * Author: Yang Yanjun <yangyanjun@huawei.com>
9 *
10 * Data: 2022-07-18
11 */
12 #include "nip_hdr.h"
13
14 /* Must carry the current field */
_get_nip_hdr_bitmap(struct nip_buff * nbuf,unsigned char bitmap[],unsigned char bitmap_index_max)15 static int _get_nip_hdr_bitmap(struct nip_buff *nbuf,
16 unsigned char bitmap[],
17 unsigned char bitmap_index_max)
18 {
19 int i = 0;
20
21 if (nbuf->remaining_len < sizeof(unsigned char))
22 return -NIP_HDR_RCV_BUF_READ_OUT_RANGE;
23
24 if (*nbuf->data & NIP_BITMAP_INVALID_SET)
25 return -NIP_HDR_BITMAP_INVALID;
26
27 do {
28 if (i >= bitmap_index_max)
29 return -NIP_HDR_BITMAP_NUM_OUT_RANGE;
30
31 if (nbuf->remaining_len < sizeof(unsigned char))
32 return -NIP_HDR_RCV_BUF_READ_OUT_RANGE;
33
34 bitmap[i] = *nbuf->data;
35 nip_buff_pull(nbuf, sizeof(unsigned char));
36 } while (bitmap[i++] & NIP_BITMAP_HAVE_MORE_BIT);
37
38 return i;
39 }
40
41 /* Must carry the current field */
_get_nip_hdr_ttl(struct nip_buff * nbuf,unsigned char bitmap,struct nip_hdr_decap * niph)42 static int _get_nip_hdr_ttl(struct nip_buff *nbuf,
43 unsigned char bitmap,
44 struct nip_hdr_decap *niph)
45 {
46 if (!(bitmap & NIP_BITMAP_INCLUDE_TTL))
47 return -NIP_HDR_NO_TTL;
48
49 if (nbuf->remaining_len < sizeof(niph->ttl))
50 return -NIP_HDR_RCV_BUF_READ_OUT_RANGE;
51
52 niph->ttl = *nbuf->data;
53 niph->include_ttl = 1;
54 nip_buff_pull(nbuf, sizeof(niph->ttl));
55
56 return 0;
57 }
58
59 /* Optional fields */
60 /* Communication between devices of the same version may not carry packet Header length,
61 * but communication between devices of different versions must carry packet header length
62 */
_get_nip_hdr_len(struct nip_buff * nbuf,unsigned char bitmap,struct nip_hdr_decap * niph)63 static int _get_nip_hdr_len(struct nip_buff *nbuf,
64 unsigned char bitmap,
65 struct nip_hdr_decap *niph)
66 {
67 if (!(bitmap & NIP_BITMAP_INCLUDE_HDR_LEN))
68 return 0;
69
70 if (nbuf->remaining_len < sizeof(niph->hdr_len))
71 return -NIP_HDR_RCV_BUF_READ_OUT_RANGE;
72
73 /* Total_len is a network sequence and cannot be
74 * compared directly with the local sequence
75 */
76 niph->hdr_len = *nbuf->data;
77 niph->include_hdr_len = 1;
78 nip_buff_pull(nbuf, sizeof(niph->hdr_len));
79
80 if (niph->include_total_len && niph->hdr_len >= niph->rcv_buf_len)
81 return -NIP_HDR_LEN_OUT_RANGE;
82
83 return 0;
84 }
85
86 /* Must carry the current field */
_get_nip_hdr_nexthdr(struct nip_buff * nbuf,unsigned char bitmap,struct nip_hdr_decap * niph)87 static int _get_nip_hdr_nexthdr(struct nip_buff *nbuf,
88 unsigned char bitmap,
89 struct nip_hdr_decap *niph)
90 {
91 if (!(bitmap & NIP_BITMAP_INCLUDE_NEXT_HDR))
92 return -NIP_HDR_NO_NEXT_HDR;
93
94 if (nbuf->remaining_len < sizeof(niph->nexthdr))
95 return -NIP_HDR_RCV_BUF_READ_OUT_RANGE;
96
97 niph->nexthdr = *nbuf->data;
98 niph->include_nexthdr = 1;
99 nip_buff_pull(nbuf, sizeof(niph->nexthdr));
100
101 return 0;
102 }
103
104 /* Must carry the current field */
105 /* Note: niph->saddr is network order.(big end) */
_get_nip_hdr_daddr(struct nip_buff * nbuf,unsigned char bitmap,struct nip_hdr_decap * niph)106 static int _get_nip_hdr_daddr(struct nip_buff *nbuf,
107 unsigned char bitmap,
108 struct nip_hdr_decap *niph)
109 {
110 unsigned char *p;
111
112 if (!(bitmap & NIP_BITMAP_INCLUDE_DADDR))
113 return -NIP_HDR_NO_DADDR;
114
115 p = decode_nip_addr(nbuf, &niph->daddr);
116 if (!p)
117 return -NIP_HDR_DECAP_DADDR_ERR;
118
119 if (nip_addr_invalid(&niph->daddr))
120 return -NIP_HDR_DADDR_INVALID;
121
122 niph->include_daddr = 1;
123 return 0;
124 }
125
126 /* Optional fields */
127 /* Note: niph->daddr is network order.(big end) */
_get_nip_hdr_saddr(struct nip_buff * nbuf,unsigned char bitmap,struct nip_hdr_decap * niph)128 static int _get_nip_hdr_saddr(struct nip_buff *nbuf,
129 unsigned char bitmap,
130 struct nip_hdr_decap *niph)
131 {
132 unsigned char *p;
133
134 if (!(bitmap & NIP_BITMAP_INCLUDE_SADDR))
135 return 0;
136
137 p = decode_nip_addr(nbuf, &niph->saddr);
138 if (!p)
139 return -NIP_HDR_DECAP_SADDR_ERR;
140
141 if (nip_addr_invalid(&niph->saddr))
142 return -NIP_HDR_SADDR_INVALID;
143
144 niph->include_saddr = 1;
145 return 0;
146 }
147
148 /* Optional fields: tcp/arp need, udp needless */
149 /* Note: niph->total_len is network order.(big end), need change to host order */
_get_nip_total_len(struct nip_buff * nbuf,unsigned char bitmap,struct nip_hdr_decap * niph)150 static int _get_nip_total_len(struct nip_buff *nbuf,
151 unsigned char bitmap,
152 struct nip_hdr_decap *niph)
153 {
154 if (!(bitmap & NIP_BITMAP_INCLUDE_TOTAL_LEN))
155 return 0;
156
157 if (nbuf->remaining_len < sizeof(niph->total_len))
158 return -NIP_HDR_RCV_BUF_READ_OUT_RANGE;
159
160 /* Total_len is a network sequence and cannot be
161 * compared directly with the local sequence
162 */
163 niph->total_len = *((unsigned short *)nbuf->data);
164 niph->include_total_len = 1;
165 nip_buff_pull(nbuf, sizeof(niph->total_len));
166
167 return 0;
168 }
169
_nip_hdr_bitmap0_parse(struct nip_buff * nbuf,unsigned char bitmap,struct nip_hdr_decap * niph)170 static int _nip_hdr_bitmap0_parse(struct nip_buff *nbuf,
171 unsigned char bitmap,
172 struct nip_hdr_decap *niph)
173 {
174 int err;
175
176 err = _get_nip_hdr_ttl(nbuf, bitmap, niph);
177 if (err < 0)
178 return err;
179
180 /* Optional fields */
181 err = _get_nip_total_len(nbuf, bitmap, niph);
182 if (err < 0)
183 return err;
184
185 err = _get_nip_hdr_nexthdr(nbuf, bitmap, niph);
186 if (err < 0)
187 return err;
188
189 err = _get_nip_hdr_daddr(nbuf, bitmap, niph);
190 if (err < 0)
191 return err;
192
193 err = _get_nip_hdr_saddr(nbuf, bitmap, niph);
194 if (err < 0)
195 return err;
196
197 return 0;
198 }
199
_nip_hdr_bitmap1_parse(struct nip_buff * nbuf,unsigned char bitmap,struct nip_hdr_decap * niph)200 static int _nip_hdr_bitmap1_parse(struct nip_buff *nbuf,
201 unsigned char bitmap,
202 struct nip_hdr_decap *niph)
203 {
204 int err;
205
206 /* If add new field needs to be modified with the macro definition */
207 if (bitmap & NIP_INVALID_BITMAP_2)
208 niph->include_unknown_bit = 1;
209
210 /* Optional fields */
211 err = _get_nip_hdr_len(nbuf, bitmap, niph);
212 if (err < 0)
213 return err;
214
215 return 0;
216 }
217
_nip_hdr_unknown_bit_check(struct nip_buff * nbuf,unsigned char bitmap,struct nip_hdr_decap * niph)218 static int _nip_hdr_unknown_bit_check(struct nip_buff *nbuf,
219 unsigned char bitmap,
220 struct nip_hdr_decap *niph)
221 {
222 niph->include_unknown_bit = 1;
223 return 0;
224 }
225
226 #define FACTORY_NUM_MAX 3
227 static int (*hdr_parse_factory[FACTORY_NUM_MAX])(struct nip_buff *,
228 unsigned char,
229 struct nip_hdr_decap *) = {
230 _nip_hdr_bitmap0_parse,
231 _nip_hdr_bitmap1_parse,
232 _nip_hdr_unknown_bit_check,
233 };
234
nip_hdr_check(struct nip_hdr_decap * niph)235 static int nip_hdr_check(struct nip_hdr_decap *niph)
236 {
237 if (niph->include_unknown_bit && !niph->include_hdr_len)
238 /* different ver pkt but no hdr len */
239 return -NIP_HDR_UNKNOWN_AND_NO_HDR_LEN;
240
241 if (niph->include_hdr_len) {
242 if (niph->hdr_len == 0 ||
243 niph->hdr_len < niph->hdr_real_len)
244 return -NIP_HDR_LEN_INVALID;
245 }
246
247 return 0;
248 }
249
250 /* Note:
251 * 1.niph->total_len is network order.(big end), need change to host order
252 * 2.niph->saddr/daddr is network order.(big end)
253 */
nip_hdr_parse(unsigned char * rcv_buf,unsigned int buf_len,struct nip_hdr_decap * niph)254 int nip_hdr_parse(unsigned char *rcv_buf, unsigned int buf_len, struct nip_hdr_decap *niph)
255 {
256 int i = 0;
257 int ret;
258 unsigned char bitmap[BITMAP_MAX] = {0};
259 int num;
260 struct nip_buff nbuf;
261
262 nbuf.data = rcv_buf;
263 if (!nbuf.data)
264 return 0;
265
266 nbuf.remaining_len = buf_len;
267 num = _get_nip_hdr_bitmap(&nbuf, bitmap, BITMAP_MAX);
268 if (num <= 0)
269 return num;
270
271 niph->rcv_buf_len = buf_len;
272 while (i < num) {
273 int err;
274
275 if (i >= FACTORY_NUM_MAX)
276 break;
277
278 err = hdr_parse_factory[i](&nbuf, bitmap[i], niph);
279 if (err < 0)
280 return err;
281
282 i++;
283 }
284
285 if (buf_len < nbuf.remaining_len)
286 return -NIP_HDR_RCV_BUF_READ_OUT_RANGE;
287
288 niph->hdr_real_len = (unsigned char)(buf_len - nbuf.remaining_len);
289 ret = nip_hdr_check(niph);
290 if (ret < 0)
291 return ret;
292
293 return niph->hdr_len > niph->hdr_real_len ?
294 niph->hdr_len : niph->hdr_real_len;
295 }
296
297