Blame view

lib/nlattr.c 22.6 KB
b24413180   Greg Kroah-Hartman   License cleanup: ...
1
  // SPDX-License-Identifier: GPL-2.0
bfa83a9e0   Thomas Graf   [NETLINK]: Type-s...
2
3
4
5
6
7
  /*
   * NETLINK      Netlink attributes
   *
   * 		Authors:	Thomas Graf <tgraf@suug.ch>
   * 				Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
   */
8bc3bcc93   Paul Gortmaker   lib: reduce the u...
8
  #include <linux/export.h>
bfa83a9e0   Thomas Graf   [NETLINK]: Type-s...
9
10
11
  #include <linux/kernel.h>
  #include <linux/errno.h>
  #include <linux/jiffies.h>
bfa83a9e0   Thomas Graf   [NETLINK]: Type-s...
12
13
14
15
  #include <linux/skbuff.h>
  #include <linux/string.h>
  #include <linux/types.h>
  #include <net/netlink.h>
6e237d099   David Ahern   netlink: Relax at...
16
17
18
19
20
  /* For these data types, attribute length should be exactly the given
   * size. However, to maintain compatibility with broken commands, if the
   * attribute length does not match the expected size a warning is emitted
   * to the user that the command is sending invalid data and needs to be fixed.
   */
28033ae4e   David Ahern   net: netlink: Upd...
21
  static const u8 nla_attr_len[NLA_TYPE_MAX+1] = {
bfa83a9e0   Thomas Graf   [NETLINK]: Type-s...
22
23
24
25
  	[NLA_U8]	= sizeof(u8),
  	[NLA_U16]	= sizeof(u16),
  	[NLA_U32]	= sizeof(u32),
  	[NLA_U64]	= sizeof(u64),
9eca2eb99   Julian Anastasov   netlink: add minl...
26
27
28
29
  	[NLA_S8]	= sizeof(s8),
  	[NLA_S16]	= sizeof(s16),
  	[NLA_S32]	= sizeof(s32),
  	[NLA_S64]	= sizeof(s64),
bfa83a9e0   Thomas Graf   [NETLINK]: Type-s...
30
  };
28033ae4e   David Ahern   net: netlink: Upd...
31
  static const u8 nla_attr_minlen[NLA_TYPE_MAX+1] = {
6e237d099   David Ahern   netlink: Relax at...
32
33
34
35
  	[NLA_U8]	= sizeof(u8),
  	[NLA_U16]	= sizeof(u16),
  	[NLA_U32]	= sizeof(u32),
  	[NLA_U64]	= sizeof(u64),
28033ae4e   David Ahern   net: netlink: Upd...
36
37
  	[NLA_MSECS]	= sizeof(u64),
  	[NLA_NESTED]	= NLA_HDRLEN,
6e237d099   David Ahern   netlink: Relax at...
38
39
40
41
  	[NLA_S8]	= sizeof(s8),
  	[NLA_S16]	= sizeof(s16),
  	[NLA_S32]	= sizeof(s32),
  	[NLA_S64]	= sizeof(s64),
28033ae4e   David Ahern   net: netlink: Upd...
42
  };
64c83d837   Jamal Hadi Salim   net netlink: Add ...
43
  static int validate_nla_bitfield32(const struct nlattr *nla,
48fde90a7   Johannes Berg   netlink: make val...
44
  				   const u32 *valid_flags_mask)
64c83d837   Jamal Hadi Salim   net netlink: Add ...
45
46
  {
  	const struct nla_bitfield32 *bf = nla_data(nla);
64c83d837   Jamal Hadi Salim   net netlink: Add ...
47

48fde90a7   Johannes Berg   netlink: make val...
48
  	if (!valid_flags_mask)
64c83d837   Jamal Hadi Salim   net netlink: Add ...
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
  		return -EINVAL;
  
  	/*disallow invalid bit selector */
  	if (bf->selector & ~*valid_flags_mask)
  		return -EINVAL;
  
  	/*disallow invalid bit values */
  	if (bf->value & ~*valid_flags_mask)
  		return -EINVAL;
  
  	/*disallow valid bit values that are not selected*/
  	if (bf->value & ~bf->selector)
  		return -EINVAL;
  
  	return 0;
  }
1501d1359   Johannes Berg   netlink: add nest...
65
66
  static int nla_validate_array(const struct nlattr *head, int len, int maxtype,
  			      const struct nla_policy *policy,
8cb081746   Johannes Berg   netlink: make val...
67
68
  			      struct netlink_ext_ack *extack,
  			      unsigned int validate)
1501d1359   Johannes Berg   netlink: add nest...
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
  {
  	const struct nlattr *entry;
  	int rem;
  
  	nla_for_each_attr(entry, head, len, rem) {
  		int ret;
  
  		if (nla_len(entry) == 0)
  			continue;
  
  		if (nla_len(entry) < NLA_HDRLEN) {
  			NL_SET_ERR_MSG_ATTR(extack, entry,
  					    "Array element too short");
  			return -ERANGE;
  		}
8cb081746   Johannes Berg   netlink: make val...
84
85
  		ret = __nla_validate(nla_data(entry), nla_len(entry),
  				     maxtype, policy, validate, extack);
1501d1359   Johannes Berg   netlink: add nest...
86
87
88
89
90
91
  		if (ret < 0)
  			return ret;
  	}
  
  	return 0;
  }
3e48be05f   Johannes Berg   netlink: add attr...
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
  static int nla_validate_int_range(const struct nla_policy *pt,
  				  const struct nlattr *nla,
  				  struct netlink_ext_ack *extack)
  {
  	bool validate_min, validate_max;
  	s64 value;
  
  	validate_min = pt->validation_type == NLA_VALIDATE_RANGE ||
  		       pt->validation_type == NLA_VALIDATE_MIN;
  	validate_max = pt->validation_type == NLA_VALIDATE_RANGE ||
  		       pt->validation_type == NLA_VALIDATE_MAX;
  
  	switch (pt->type) {
  	case NLA_U8:
  		value = nla_get_u8(nla);
  		break;
  	case NLA_U16:
  		value = nla_get_u16(nla);
  		break;
  	case NLA_U32:
  		value = nla_get_u32(nla);
  		break;
  	case NLA_S8:
  		value = nla_get_s8(nla);
  		break;
  	case NLA_S16:
  		value = nla_get_s16(nla);
  		break;
  	case NLA_S32:
  		value = nla_get_s32(nla);
  		break;
  	case NLA_S64:
  		value = nla_get_s64(nla);
  		break;
  	case NLA_U64:
  		/* treat this one specially, since it may not fit into s64 */
  		if ((validate_min && nla_get_u64(nla) < pt->min) ||
  		    (validate_max && nla_get_u64(nla) > pt->max)) {
  			NL_SET_ERR_MSG_ATTR(extack, nla,
  					    "integer out of range");
  			return -ERANGE;
  		}
  		return 0;
  	default:
  		WARN_ON(1);
  		return -EINVAL;
  	}
  
  	if ((validate_min && value < pt->min) ||
  	    (validate_max && value > pt->max)) {
  		NL_SET_ERR_MSG_ATTR(extack, nla,
  				    "integer out of range");
  		return -ERANGE;
  	}
  
  	return 0;
  }
3654654f7   Jan Engelhardt   netlink: let nlms...
149
  static int validate_nla(const struct nlattr *nla, int maxtype,
8cb081746   Johannes Berg   netlink: make val...
150
  			const struct nla_policy *policy, unsigned int validate,
c29f1845b   Johannes Berg   netlink: move ext...
151
  			struct netlink_ext_ack *extack)
bfa83a9e0   Thomas Graf   [NETLINK]: Type-s...
152
  {
56738f460   Johannes Berg   netlink: add stri...
153
  	u16 strict_start_type = policy[0].strict_start_type;
ef7c79ed6   Patrick McHardy   [NETLINK]: Mark n...
154
  	const struct nla_policy *pt;
8f4c1f9b0   Thomas Graf   [NETLINK]: Introd...
155
  	int minlen = 0, attrlen = nla_len(nla), type = nla_type(nla);
c29f1845b   Johannes Berg   netlink: move ext...
156
  	int err = -ERANGE;
bfa83a9e0   Thomas Graf   [NETLINK]: Type-s...
157

56738f460   Johannes Berg   netlink: add stri...
158
159
  	if (strict_start_type && type >= strict_start_type)
  		validate |= NL_VALIDATE_STRICT;
8f4c1f9b0   Thomas Graf   [NETLINK]: Introd...
160
  	if (type <= 0 || type > maxtype)
bfa83a9e0   Thomas Graf   [NETLINK]: Type-s...
161
  		return 0;
8f4c1f9b0   Thomas Graf   [NETLINK]: Introd...
162
  	pt = &policy[type];
bfa83a9e0   Thomas Graf   [NETLINK]: Type-s...
163
164
  
  	BUG_ON(pt->type > NLA_TYPE_MAX);
b60b87fc2   Johannes Berg   netlink: add ethe...
165
166
  	if ((nla_attr_len[pt->type] && attrlen != nla_attr_len[pt->type]) ||
  	    (pt->type == NLA_EXACT_LEN_WARN && attrlen != pt->len)) {
6e237d099   David Ahern   netlink: Relax at...
167
168
169
  		pr_warn_ratelimited("netlink: '%s': attribute type %d has an invalid length.
  ",
  				    current->comm, type);
8cb081746   Johannes Berg   netlink: make val...
170
171
172
173
174
  		if (validate & NL_VALIDATE_STRICT_ATTRS) {
  			NL_SET_ERR_MSG_ATTR(extack, nla,
  					    "invalid attribute length");
  			return -EINVAL;
  		}
28033ae4e   David Ahern   net: netlink: Upd...
175
  	}
b424e432e   Michal Kubecek   netlink: add vali...
176
177
178
179
180
181
182
183
184
185
186
187
188
189
  	if (validate & NL_VALIDATE_NESTED) {
  		if ((pt->type == NLA_NESTED || pt->type == NLA_NESTED_ARRAY) &&
  		    !(nla->nla_type & NLA_F_NESTED)) {
  			NL_SET_ERR_MSG_ATTR(extack, nla,
  					    "NLA_F_NESTED is missing");
  			return -EINVAL;
  		}
  		if (pt->type != NLA_NESTED && pt->type != NLA_NESTED_ARRAY &&
  		    pt->type != NLA_UNSPEC && (nla->nla_type & NLA_F_NESTED)) {
  			NL_SET_ERR_MSG_ATTR(extack, nla,
  					    "NLA_F_NESTED not expected");
  			return -EINVAL;
  		}
  	}
a5531a5d8   Thomas Graf   [NETLINK]: Improv...
190
  	switch (pt->type) {
b60b87fc2   Johannes Berg   netlink: add ethe...
191
192
  	case NLA_EXACT_LEN:
  		if (attrlen != pt->len)
c29f1845b   Johannes Berg   netlink: move ext...
193
  			goto out_err;
b60b87fc2   Johannes Berg   netlink: add ethe...
194
  		break;
568b742a9   Johannes Berg   netlink: add NLA_...
195
  	case NLA_REJECT:
c29f1845b   Johannes Berg   netlink: move ext...
196
197
198
199
200
201
202
  		if (extack && pt->validation_data) {
  			NL_SET_BAD_ATTR(extack, nla);
  			extack->_msg = pt->validation_data;
  			return -EINVAL;
  		}
  		err = -EINVAL;
  		goto out_err;
568b742a9   Johannes Berg   netlink: add NLA_...
203

a5531a5d8   Thomas Graf   [NETLINK]: Improv...
204
205
  	case NLA_FLAG:
  		if (attrlen > 0)
c29f1845b   Johannes Berg   netlink: move ext...
206
  			goto out_err;
a5531a5d8   Thomas Graf   [NETLINK]: Improv...
207
  		break;
bfa83a9e0   Thomas Graf   [NETLINK]: Type-s...
208

64c83d837   Jamal Hadi Salim   net netlink: Add ...
209
210
  	case NLA_BITFIELD32:
  		if (attrlen != sizeof(struct nla_bitfield32))
c29f1845b   Johannes Berg   netlink: move ext...
211
  			goto out_err;
64c83d837   Jamal Hadi Salim   net netlink: Add ...
212

c29f1845b   Johannes Berg   netlink: move ext...
213
214
215
216
  		err = validate_nla_bitfield32(nla, pt->validation_data);
  		if (err)
  			goto out_err;
  		break;
64c83d837   Jamal Hadi Salim   net netlink: Add ...
217

a5531a5d8   Thomas Graf   [NETLINK]: Improv...
218
219
220
221
222
  	case NLA_NUL_STRING:
  		if (pt->len)
  			minlen = min_t(int, attrlen, pt->len + 1);
  		else
  			minlen = attrlen;
bfa83a9e0   Thomas Graf   [NETLINK]: Type-s...
223

c29f1845b   Johannes Berg   netlink: move ext...
224
225
226
227
  		if (!minlen || memchr(nla_data(nla), '\0', minlen) == NULL) {
  			err = -EINVAL;
  			goto out_err;
  		}
a5531a5d8   Thomas Graf   [NETLINK]: Improv...
228
229
230
231
  		/* fall through */
  
  	case NLA_STRING:
  		if (attrlen < 1)
c29f1845b   Johannes Berg   netlink: move ext...
232
  			goto out_err;
a5531a5d8   Thomas Graf   [NETLINK]: Improv...
233
234
235
236
237
238
239
240
  
  		if (pt->len) {
  			char *buf = nla_data(nla);
  
  			if (buf[attrlen - 1] == '\0')
  				attrlen--;
  
  			if (attrlen > pt->len)
c29f1845b   Johannes Berg   netlink: move ext...
241
  				goto out_err;
a5531a5d8   Thomas Graf   [NETLINK]: Improv...
242
243
  		}
  		break;
d30045a0b   Johannes Berg   [NETLINK]: introd...
244
245
  	case NLA_BINARY:
  		if (pt->len && attrlen > pt->len)
c29f1845b   Johannes Berg   netlink: move ext...
246
  			goto out_err;
d30045a0b   Johannes Berg   [NETLINK]: introd...
247
  		break;
ea5693ccc   Patrick McHardy   netlink: allow em...
248
249
250
251
252
253
  	case NLA_NESTED:
  		/* a nested attributes is allowed to be empty; if its not,
  		 * it must have a size of at least NLA_HDRLEN.
  		 */
  		if (attrlen == 0)
  			break;
9a659a35b   Johannes Berg   netlink: allow NL...
254
255
256
  		if (attrlen < NLA_HDRLEN)
  			goto out_err;
  		if (pt->validation_data) {
8cb081746   Johannes Berg   netlink: make val...
257
258
259
  			err = __nla_validate(nla_data(nla), nla_len(nla), pt->len,
  					     pt->validation_data, validate,
  					     extack);
9a659a35b   Johannes Berg   netlink: allow NL...
260
261
262
263
264
265
266
267
268
  			if (err < 0) {
  				/*
  				 * return directly to preserve the inner
  				 * error message/attribute pointer
  				 */
  				return err;
  			}
  		}
  		break;
1501d1359   Johannes Berg   netlink: add nest...
269
270
271
272
273
274
275
276
277
278
279
280
281
  	case NLA_NESTED_ARRAY:
  		/* a nested array attribute is allowed to be empty; if its not,
  		 * it must have a size of at least NLA_HDRLEN.
  		 */
  		if (attrlen == 0)
  			break;
  		if (attrlen < NLA_HDRLEN)
  			goto out_err;
  		if (pt->validation_data) {
  			int err;
  
  			err = nla_validate_array(nla_data(nla), nla_len(nla),
  						 pt->len, pt->validation_data,
8cb081746   Johannes Berg   netlink: make val...
282
  						 extack, validate);
1501d1359   Johannes Berg   netlink: add nest...
283
284
285
286
287
288
289
290
291
  			if (err < 0) {
  				/*
  				 * return directly to preserve the inner
  				 * error message/attribute pointer
  				 */
  				return err;
  			}
  		}
  		break;
6f455f5f4   Johannes Berg   netlink: add NLA_...
292
293
  
  	case NLA_UNSPEC:
8cb081746   Johannes Berg   netlink: make val...
294
295
296
297
298
299
  		if (validate & NL_VALIDATE_UNSPEC) {
  			NL_SET_ERR_MSG_ATTR(extack, nla,
  					    "Unsupported attribute");
  			return -EINVAL;
  		}
  		/* fall through */
6f455f5f4   Johannes Berg   netlink: add NLA_...
300
301
302
303
  	case NLA_MIN_LEN:
  		if (attrlen < pt->len)
  			goto out_err;
  		break;
a5531a5d8   Thomas Graf   [NETLINK]: Improv...
304
305
306
  	default:
  		if (pt->len)
  			minlen = pt->len;
6f455f5f4   Johannes Berg   netlink: add NLA_...
307
  		else
a5531a5d8   Thomas Graf   [NETLINK]: Improv...
308
309
310
  			minlen = nla_attr_minlen[pt->type];
  
  		if (attrlen < minlen)
c29f1845b   Johannes Berg   netlink: move ext...
311
  			goto out_err;
a5531a5d8   Thomas Graf   [NETLINK]: Improv...
312
  	}
bfa83a9e0   Thomas Graf   [NETLINK]: Type-s...
313

3e48be05f   Johannes Berg   netlink: add attr...
314
315
316
317
318
319
320
321
322
323
324
325
  	/* further validation */
  	switch (pt->validation_type) {
  	case NLA_VALIDATE_NONE:
  		/* nothing to do */
  		break;
  	case NLA_VALIDATE_RANGE:
  	case NLA_VALIDATE_MIN:
  	case NLA_VALIDATE_MAX:
  		err = nla_validate_int_range(pt, nla, extack);
  		if (err)
  			return err;
  		break;
33188bd64   Johannes Berg   netlink: add vali...
326
327
328
329
330
331
332
  	case NLA_VALIDATE_FUNCTION:
  		if (pt->validate) {
  			err = pt->validate(nla, extack);
  			if (err)
  				return err;
  		}
  		break;
3e48be05f   Johannes Berg   netlink: add attr...
333
  	}
bfa83a9e0   Thomas Graf   [NETLINK]: Type-s...
334
  	return 0;
c29f1845b   Johannes Berg   netlink: move ext...
335
336
337
  out_err:
  	NL_SET_ERR_MSG_ATTR(extack, nla, "Attribute failed policy validation");
  	return err;
bfa83a9e0   Thomas Graf   [NETLINK]: Type-s...
338
  }
8cb081746   Johannes Berg   netlink: make val...
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
  static int __nla_validate_parse(const struct nlattr *head, int len, int maxtype,
  				const struct nla_policy *policy,
  				unsigned int validate,
  				struct netlink_ext_ack *extack,
  				struct nlattr **tb)
  {
  	const struct nlattr *nla;
  	int rem;
  
  	if (tb)
  		memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1));
  
  	nla_for_each_attr(nla, head, len, rem) {
  		u16 type = nla_type(nla);
  
  		if (type == 0 || type > maxtype) {
  			if (validate & NL_VALIDATE_MAXTYPE) {
d54a16b20   Michal Kubecek   netlink: set bad ...
356
357
  				NL_SET_ERR_MSG_ATTR(extack, nla,
  						    "Unknown attribute type");
8cb081746   Johannes Berg   netlink: make val...
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
  				return -EINVAL;
  			}
  			continue;
  		}
  		if (policy) {
  			int err = validate_nla(nla, maxtype, policy,
  					       validate, extack);
  
  			if (err < 0)
  				return err;
  		}
  
  		if (tb)
  			tb[type] = (struct nlattr *)nla;
  	}
  
  	if (unlikely(rem > 0)) {
  		pr_warn_ratelimited("netlink: %d bytes leftover after parsing attributes in process `%s'.
  ",
  				    rem, current->comm);
  		NL_SET_ERR_MSG(extack, "bytes leftover after parsing attributes");
  		if (validate & NL_VALIDATE_TRAILING)
  			return -EINVAL;
  	}
  
  	return 0;
  }
bfa83a9e0   Thomas Graf   [NETLINK]: Type-s...
385
  /**
8cb081746   Johannes Berg   netlink: make val...
386
   * __nla_validate - Validate a stream of attributes
bfa83a9e0   Thomas Graf   [NETLINK]: Type-s...
387
388
389
390
   * @head: head of attribute stream
   * @len: length of attribute stream
   * @maxtype: maximum attribute type to be expected
   * @policy: validation policy
8cb081746   Johannes Berg   netlink: make val...
391
   * @validate: validation strictness
fceb6435e   Johannes Berg   netlink: pass ext...
392
   * @extack: extended ACK report struct
bfa83a9e0   Thomas Graf   [NETLINK]: Type-s...
393
394
   *
   * Validates all attributes in the specified attribute stream against the
8cb081746   Johannes Berg   netlink: make val...
395
396
397
   * specified policy. Validation depends on the validate flags passed, see
   * &enum netlink_validation for more details on that.
   * See documenation of struct nla_policy for more details.
bfa83a9e0   Thomas Graf   [NETLINK]: Type-s...
398
399
400
   *
   * Returns 0 on success or a negative error code.
   */
8cb081746   Johannes Berg   netlink: make val...
401
402
403
  int __nla_validate(const struct nlattr *head, int len, int maxtype,
  		   const struct nla_policy *policy, unsigned int validate,
  		   struct netlink_ext_ack *extack)
bfa83a9e0   Thomas Graf   [NETLINK]: Type-s...
404
  {
8cb081746   Johannes Berg   netlink: make val...
405
406
  	return __nla_validate_parse(head, len, maxtype, policy, validate,
  				    extack, NULL);
bfa83a9e0   Thomas Graf   [NETLINK]: Type-s...
407
  }
8cb081746   Johannes Berg   netlink: make val...
408
  EXPORT_SYMBOL(__nla_validate);
bfa83a9e0   Thomas Graf   [NETLINK]: Type-s...
409
410
  
  /**
e487eb99c   Holger Eitzenberger   netlink: add nla_...
411
412
413
414
415
416
417
418
419
420
421
422
423
424
   * nla_policy_len - Determin the max. length of a policy
   * @policy: policy to use
   * @n: number of policies
   *
   * Determines the max. length of the policy.  It is currently used
   * to allocated Netlink buffers roughly the size of the actual
   * message.
   *
   * Returns 0 on success or a negative error code.
   */
  int
  nla_policy_len(const struct nla_policy *p, int n)
  {
  	int i, len = 0;
e3fa3aff0   Lars Ellenberg   net: fix nla_poli...
425
  	for (i = 0; i < n; i++, p++) {
e487eb99c   Holger Eitzenberger   netlink: add nla_...
426
427
  		if (p->len)
  			len += nla_total_size(p->len);
28033ae4e   David Ahern   net: netlink: Upd...
428
429
  		else if (nla_attr_len[p->type])
  			len += nla_total_size(nla_attr_len[p->type]);
e487eb99c   Holger Eitzenberger   netlink: add nla_...
430
431
432
433
434
435
  		else if (nla_attr_minlen[p->type])
  			len += nla_total_size(nla_attr_minlen[p->type]);
  	}
  
  	return len;
  }
6d6a138f1   Fabian Frederick   lib/nlattr.c: mov...
436
  EXPORT_SYMBOL(nla_policy_len);
e487eb99c   Holger Eitzenberger   netlink: add nla_...
437
438
  
  /**
8cb081746   Johannes Berg   netlink: make val...
439
   * __nla_parse - Parse a stream of attributes into a tb buffer
bfa83a9e0   Thomas Graf   [NETLINK]: Type-s...
440
441
442
443
   * @tb: destination array with maxtype+1 elements
   * @maxtype: maximum attribute type to be expected
   * @head: head of attribute stream
   * @len: length of attribute stream
10b595aff   Julius Volz   netlink: Fix some...
444
   * @policy: validation policy
8cb081746   Johannes Berg   netlink: make val...
445
446
   * @validate: validation strictness
   * @extack: extended ACK pointer
bfa83a9e0   Thomas Graf   [NETLINK]: Type-s...
447
448
   *
   * Parses a stream of attributes and stores a pointer to each attribute in
8cb081746   Johannes Berg   netlink: make val...
449
450
   * the tb array accessible via the attribute type.
   * Validation is controlled by the @validate parameter.
bfa83a9e0   Thomas Graf   [NETLINK]: Type-s...
451
452
453
   *
   * Returns 0 on success or a negative error code.
   */
8cb081746   Johannes Berg   netlink: make val...
454
455
456
457
  int __nla_parse(struct nlattr **tb, int maxtype,
  		const struct nlattr *head, int len,
  		const struct nla_policy *policy, unsigned int validate,
  		struct netlink_ext_ack *extack)
a5f6cba29   David Ahern   netlink: Add stri...
458
  {
8cb081746   Johannes Berg   netlink: make val...
459
460
  	return __nla_validate_parse(head, len, maxtype, policy, validate,
  				    extack, tb);
a5f6cba29   David Ahern   netlink: Add stri...
461
  }
8cb081746   Johannes Berg   netlink: make val...
462
  EXPORT_SYMBOL(__nla_parse);
a5f6cba29   David Ahern   netlink: Add stri...
463

bfa83a9e0   Thomas Graf   [NETLINK]: Type-s...
464
465
466
467
468
469
470
471
  /**
   * nla_find - Find a specific attribute in a stream of attributes
   * @head: head of attribute stream
   * @len: length of attribute stream
   * @attrtype: type of attribute to look for
   *
   * Returns the first attribute in the stream matching the specified type.
   */
3654654f7   Jan Engelhardt   netlink: let nlms...
472
  struct nlattr *nla_find(const struct nlattr *head, int len, int attrtype)
bfa83a9e0   Thomas Graf   [NETLINK]: Type-s...
473
  {
3654654f7   Jan Engelhardt   netlink: let nlms...
474
  	const struct nlattr *nla;
bfa83a9e0   Thomas Graf   [NETLINK]: Type-s...
475
476
477
  	int rem;
  
  	nla_for_each_attr(nla, head, len, rem)
8f4c1f9b0   Thomas Graf   [NETLINK]: Introd...
478
  		if (nla_type(nla) == attrtype)
3654654f7   Jan Engelhardt   netlink: let nlms...
479
  			return (struct nlattr *)nla;
bfa83a9e0   Thomas Graf   [NETLINK]: Type-s...
480
481
482
  
  	return NULL;
  }
6d6a138f1   Fabian Frederick   lib/nlattr.c: mov...
483
  EXPORT_SYMBOL(nla_find);
bfa83a9e0   Thomas Graf   [NETLINK]: Type-s...
484
485
486
487
  
  /**
   * nla_strlcpy - Copy string attribute payload into a sized buffer
   * @dst: where to copy the string to
10b595aff   Julius Volz   netlink: Fix some...
488
   * @nla: attribute to copy the string from
bfa83a9e0   Thomas Graf   [NETLINK]: Type-s...
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
   * @dstsize: size of destination buffer
   *
   * Copies at most dstsize - 1 bytes into the destination buffer.
   * The result is always a valid NUL-terminated string. Unlike
   * strlcpy the destination buffer is always padded out.
   *
   * Returns the length of the source buffer.
   */
  size_t nla_strlcpy(char *dst, const struct nlattr *nla, size_t dstsize)
  {
  	size_t srclen = nla_len(nla);
  	char *src = nla_data(nla);
  
  	if (srclen > 0 && src[srclen - 1] == '\0')
  		srclen--;
  
  	if (dstsize > 0) {
  		size_t len = (srclen >= dstsize) ? dstsize - 1 : srclen;
  
  		memset(dst, 0, dstsize);
  		memcpy(dst, src, len);
  	}
  
  	return srclen;
  }
6d6a138f1   Fabian Frederick   lib/nlattr.c: mov...
514
  EXPORT_SYMBOL(nla_strlcpy);
bfa83a9e0   Thomas Graf   [NETLINK]: Type-s...
515
516
  
  /**
2cf0c8b3e   Phil Sutter   netlink: Introduc...
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
   * nla_strdup - Copy string attribute payload into a newly allocated buffer
   * @nla: attribute to copy the string from
   * @flags: the type of memory to allocate (see kmalloc).
   *
   * Returns a pointer to the allocated buffer or NULL on error.
   */
  char *nla_strdup(const struct nlattr *nla, gfp_t flags)
  {
  	size_t srclen = nla_len(nla);
  	char *src = nla_data(nla), *dst;
  
  	if (srclen > 0 && src[srclen - 1] == '\0')
  		srclen--;
  
  	dst = kmalloc(srclen + 1, flags);
  	if (dst != NULL) {
  		memcpy(dst, src, srclen);
  		dst[srclen] = '\0';
  	}
  	return dst;
  }
  EXPORT_SYMBOL(nla_strdup);
  
  /**
bfa83a9e0   Thomas Graf   [NETLINK]: Type-s...
541
542
543
544
545
546
547
548
549
550
   * nla_memcpy - Copy a netlink attribute into another memory area
   * @dest: where to copy to memcpy
   * @src: netlink attribute to copy from
   * @count: size of the destination area
   *
   * Note: The number of bytes copied is limited by the length of
   *       attribute's payload. memcpy
   *
   * Returns the number of bytes copied.
   */
b057efd4d   Patrick McHardy   netlink: constify...
551
  int nla_memcpy(void *dest, const struct nlattr *src, int count)
bfa83a9e0   Thomas Graf   [NETLINK]: Type-s...
552
553
554
555
  {
  	int minlen = min_t(int, count, nla_len(src));
  
  	memcpy(dest, nla_data(src), minlen);
5899f0478   Jiri Benc   netlink: pad nla_...
556
557
  	if (count > minlen)
  		memset(dest + minlen, 0, count - minlen);
bfa83a9e0   Thomas Graf   [NETLINK]: Type-s...
558
559
560
  
  	return minlen;
  }
6d6a138f1   Fabian Frederick   lib/nlattr.c: mov...
561
  EXPORT_SYMBOL(nla_memcpy);
bfa83a9e0   Thomas Graf   [NETLINK]: Type-s...
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
  
  /**
   * nla_memcmp - Compare an attribute with sized memory area
   * @nla: netlink attribute
   * @data: memory area
   * @size: size of memory area
   */
  int nla_memcmp(const struct nlattr *nla, const void *data,
  			     size_t size)
  {
  	int d = nla_len(nla) - size;
  
  	if (d == 0)
  		d = memcmp(nla_data(nla), data, size);
  
  	return d;
  }
6d6a138f1   Fabian Frederick   lib/nlattr.c: mov...
579
  EXPORT_SYMBOL(nla_memcmp);
bfa83a9e0   Thomas Graf   [NETLINK]: Type-s...
580
581
582
583
584
585
586
587
  
  /**
   * nla_strcmp - Compare a string attribute against a string
   * @nla: netlink string attribute
   * @str: another string
   */
  int nla_strcmp(const struct nlattr *nla, const char *str)
  {
8b7b93243   Pablo Neira   netlink: don't co...
588
589
590
591
  	int len = strlen(str);
  	char *buf = nla_data(nla);
  	int attrlen = nla_len(nla);
  	int d;
bfa83a9e0   Thomas Graf   [NETLINK]: Type-s...
592

8b7b93243   Pablo Neira   netlink: don't co...
593
594
595
596
  	if (attrlen > 0 && buf[attrlen - 1] == '\0')
  		attrlen--;
  
  	d = attrlen - len;
bfa83a9e0   Thomas Graf   [NETLINK]: Type-s...
597
598
599
600
601
  	if (d == 0)
  		d = memcmp(nla_data(nla), str, len);
  
  	return d;
  }
6d6a138f1   Fabian Frederick   lib/nlattr.c: mov...
602
  EXPORT_SYMBOL(nla_strcmp);
bfa83a9e0   Thomas Graf   [NETLINK]: Type-s...
603

908002161   Herbert Xu   nlattr: Fix build...
604
  #ifdef CONFIG_NET
bfa83a9e0   Thomas Graf   [NETLINK]: Type-s...
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
  /**
   * __nla_reserve - reserve room for attribute on the skb
   * @skb: socket buffer to reserve room on
   * @attrtype: attribute type
   * @attrlen: length of attribute payload
   *
   * Adds a netlink attribute header to a socket buffer and reserves
   * room for the payload but does not copy it.
   *
   * The caller is responsible to ensure that the skb provides enough
   * tailroom for the attribute header and payload.
   */
  struct nlattr *__nla_reserve(struct sk_buff *skb, int attrtype, int attrlen)
  {
  	struct nlattr *nla;
4df864c1d   Johannes Berg   networking: make ...
620
  	nla = skb_put(skb, nla_total_size(attrlen));
bfa83a9e0   Thomas Graf   [NETLINK]: Type-s...
621
622
623
624
625
626
627
  	nla->nla_type = attrtype;
  	nla->nla_len = nla_attr_size(attrlen);
  
  	memset((unsigned char *) nla + nla->nla_len, 0, nla_padlen(attrlen));
  
  	return nla;
  }
908002161   Herbert Xu   nlattr: Fix build...
628
  EXPORT_SYMBOL(__nla_reserve);
bfa83a9e0   Thomas Graf   [NETLINK]: Type-s...
629
630
  
  /**
089bf1a6a   Nicolas Dichtel   libnl: add more h...
631
632
633
634
   * __nla_reserve_64bit - reserve room for attribute on the skb and align it
   * @skb: socket buffer to reserve room on
   * @attrtype: attribute type
   * @attrlen: length of attribute payload
11a995730   Nicolas Dichtel   libnl: fix help o...
635
   * @padattr: attribute type for the padding
089bf1a6a   Nicolas Dichtel   libnl: add more h...
636
637
638
   *
   * Adds a netlink attribute header to a socket buffer and reserves
   * room for the payload but does not copy it. It also ensure that this
11a995730   Nicolas Dichtel   libnl: fix help o...
639
   * attribute will have a 64-bit aligned nla_data() area.
089bf1a6a   Nicolas Dichtel   libnl: add more h...
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
   *
   * The caller is responsible to ensure that the skb provides enough
   * tailroom for the attribute header and payload.
   */
  struct nlattr *__nla_reserve_64bit(struct sk_buff *skb, int attrtype,
  				   int attrlen, int padattr)
  {
  	if (nla_need_padding_for_64bit(skb))
  		nla_align_64bit(skb, padattr);
  
  	return __nla_reserve(skb, attrtype, attrlen);
  }
  EXPORT_SYMBOL(__nla_reserve_64bit);
  
  /**
fe4944e59   Thomas Graf   [NETLINK]: Extend...
655
656
657
658
659
660
661
662
663
664
665
   * __nla_reserve_nohdr - reserve room for attribute without header
   * @skb: socket buffer to reserve room on
   * @attrlen: length of attribute payload
   *
   * Reserves room for attribute payload without a header.
   *
   * The caller is responsible to ensure that the skb provides enough
   * tailroom for the payload.
   */
  void *__nla_reserve_nohdr(struct sk_buff *skb, int attrlen)
  {
b952f4dff   yuan linyu   net: manual clean...
666
  	return skb_put_zero(skb, NLA_ALIGN(attrlen));
fe4944e59   Thomas Graf   [NETLINK]: Extend...
667
  }
908002161   Herbert Xu   nlattr: Fix build...
668
  EXPORT_SYMBOL(__nla_reserve_nohdr);
fe4944e59   Thomas Graf   [NETLINK]: Extend...
669
670
  
  /**
bfa83a9e0   Thomas Graf   [NETLINK]: Type-s...
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
   * nla_reserve - reserve room for attribute on the skb
   * @skb: socket buffer to reserve room on
   * @attrtype: attribute type
   * @attrlen: length of attribute payload
   *
   * Adds a netlink attribute header to a socket buffer and reserves
   * room for the payload but does not copy it.
   *
   * Returns NULL if the tailroom of the skb is insufficient to store
   * the attribute header and payload.
   */
  struct nlattr *nla_reserve(struct sk_buff *skb, int attrtype, int attrlen)
  {
  	if (unlikely(skb_tailroom(skb) < nla_total_size(attrlen)))
  		return NULL;
  
  	return __nla_reserve(skb, attrtype, attrlen);
  }
908002161   Herbert Xu   nlattr: Fix build...
689
  EXPORT_SYMBOL(nla_reserve);
bfa83a9e0   Thomas Graf   [NETLINK]: Type-s...
690
691
  
  /**
089bf1a6a   Nicolas Dichtel   libnl: add more h...
692
693
694
695
   * nla_reserve_64bit - reserve room for attribute on the skb and align it
   * @skb: socket buffer to reserve room on
   * @attrtype: attribute type
   * @attrlen: length of attribute payload
11a995730   Nicolas Dichtel   libnl: fix help o...
696
   * @padattr: attribute type for the padding
089bf1a6a   Nicolas Dichtel   libnl: add more h...
697
698
699
   *
   * Adds a netlink attribute header to a socket buffer and reserves
   * room for the payload but does not copy it. It also ensure that this
11a995730   Nicolas Dichtel   libnl: fix help o...
700
   * attribute will have a 64-bit aligned nla_data() area.
089bf1a6a   Nicolas Dichtel   libnl: add more h...
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
   *
   * Returns NULL if the tailroom of the skb is insufficient to store
   * the attribute header and payload.
   */
  struct nlattr *nla_reserve_64bit(struct sk_buff *skb, int attrtype, int attrlen,
  				 int padattr)
  {
  	size_t len;
  
  	if (nla_need_padding_for_64bit(skb))
  		len = nla_total_size_64bit(attrlen);
  	else
  		len = nla_total_size(attrlen);
  	if (unlikely(skb_tailroom(skb) < len))
  		return NULL;
  
  	return __nla_reserve_64bit(skb, attrtype, attrlen, padattr);
  }
  EXPORT_SYMBOL(nla_reserve_64bit);
  
  /**
10b595aff   Julius Volz   netlink: Fix some...
722
   * nla_reserve_nohdr - reserve room for attribute without header
fe4944e59   Thomas Graf   [NETLINK]: Extend...
723
   * @skb: socket buffer to reserve room on
10b595aff   Julius Volz   netlink: Fix some...
724
   * @attrlen: length of attribute payload
fe4944e59   Thomas Graf   [NETLINK]: Extend...
725
726
727
728
729
730
731
732
733
734
735
736
737
   *
   * Reserves room for attribute payload without a header.
   *
   * Returns NULL if the tailroom of the skb is insufficient to store
   * the attribute payload.
   */
  void *nla_reserve_nohdr(struct sk_buff *skb, int attrlen)
  {
  	if (unlikely(skb_tailroom(skb) < NLA_ALIGN(attrlen)))
  		return NULL;
  
  	return __nla_reserve_nohdr(skb, attrlen);
  }
908002161   Herbert Xu   nlattr: Fix build...
738
  EXPORT_SYMBOL(nla_reserve_nohdr);
fe4944e59   Thomas Graf   [NETLINK]: Extend...
739
740
  
  /**
bfa83a9e0   Thomas Graf   [NETLINK]: Type-s...
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
   * __nla_put - Add a netlink attribute to a socket buffer
   * @skb: socket buffer to add attribute to
   * @attrtype: attribute type
   * @attrlen: length of attribute payload
   * @data: head of attribute payload
   *
   * The caller is responsible to ensure that the skb provides enough
   * tailroom for the attribute header and payload.
   */
  void __nla_put(struct sk_buff *skb, int attrtype, int attrlen,
  			     const void *data)
  {
  	struct nlattr *nla;
  
  	nla = __nla_reserve(skb, attrtype, attrlen);
  	memcpy(nla_data(nla), data, attrlen);
  }
908002161   Herbert Xu   nlattr: Fix build...
758
  EXPORT_SYMBOL(__nla_put);
bfa83a9e0   Thomas Graf   [NETLINK]: Type-s...
759

fe4944e59   Thomas Graf   [NETLINK]: Extend...
760
  /**
089bf1a6a   Nicolas Dichtel   libnl: add more h...
761
762
763
764
765
   * __nla_put_64bit - Add a netlink attribute to a socket buffer and align it
   * @skb: socket buffer to add attribute to
   * @attrtype: attribute type
   * @attrlen: length of attribute payload
   * @data: head of attribute payload
11a995730   Nicolas Dichtel   libnl: fix help o...
766
   * @padattr: attribute type for the padding
089bf1a6a   Nicolas Dichtel   libnl: add more h...
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
   *
   * The caller is responsible to ensure that the skb provides enough
   * tailroom for the attribute header and payload.
   */
  void __nla_put_64bit(struct sk_buff *skb, int attrtype, int attrlen,
  		     const void *data, int padattr)
  {
  	struct nlattr *nla;
  
  	nla = __nla_reserve_64bit(skb, attrtype, attrlen, padattr);
  	memcpy(nla_data(nla), data, attrlen);
  }
  EXPORT_SYMBOL(__nla_put_64bit);
  
  /**
fe4944e59   Thomas Graf   [NETLINK]: Extend...
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
   * __nla_put_nohdr - Add a netlink attribute without header
   * @skb: socket buffer to add attribute to
   * @attrlen: length of attribute payload
   * @data: head of attribute payload
   *
   * The caller is responsible to ensure that the skb provides enough
   * tailroom for the attribute payload.
   */
  void __nla_put_nohdr(struct sk_buff *skb, int attrlen, const void *data)
  {
  	void *start;
  
  	start = __nla_reserve_nohdr(skb, attrlen);
  	memcpy(start, data, attrlen);
  }
908002161   Herbert Xu   nlattr: Fix build...
797
  EXPORT_SYMBOL(__nla_put_nohdr);
bfa83a9e0   Thomas Graf   [NETLINK]: Type-s...
798
799
800
801
802
803
804
805
  
  /**
   * nla_put - Add a netlink attribute to a socket buffer
   * @skb: socket buffer to add attribute to
   * @attrtype: attribute type
   * @attrlen: length of attribute payload
   * @data: head of attribute payload
   *
bc3ed28ca   Thomas Graf   netlink: Improve ...
806
   * Returns -EMSGSIZE if the tailroom of the skb is insufficient to store
bfa83a9e0   Thomas Graf   [NETLINK]: Type-s...
807
808
809
810
811
   * the attribute header and payload.
   */
  int nla_put(struct sk_buff *skb, int attrtype, int attrlen, const void *data)
  {
  	if (unlikely(skb_tailroom(skb) < nla_total_size(attrlen)))
bc3ed28ca   Thomas Graf   netlink: Improve ...
812
  		return -EMSGSIZE;
bfa83a9e0   Thomas Graf   [NETLINK]: Type-s...
813
814
815
816
  
  	__nla_put(skb, attrtype, attrlen, data);
  	return 0;
  }
908002161   Herbert Xu   nlattr: Fix build...
817
  EXPORT_SYMBOL(nla_put);
bfa83a9e0   Thomas Graf   [NETLINK]: Type-s...
818

fe4944e59   Thomas Graf   [NETLINK]: Extend...
819
  /**
089bf1a6a   Nicolas Dichtel   libnl: add more h...
820
821
822
823
824
   * nla_put_64bit - Add a netlink attribute to a socket buffer and align it
   * @skb: socket buffer to add attribute to
   * @attrtype: attribute type
   * @attrlen: length of attribute payload
   * @data: head of attribute payload
11a995730   Nicolas Dichtel   libnl: fix help o...
825
   * @padattr: attribute type for the padding
089bf1a6a   Nicolas Dichtel   libnl: add more h...
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
   *
   * Returns -EMSGSIZE if the tailroom of the skb is insufficient to store
   * the attribute header and payload.
   */
  int nla_put_64bit(struct sk_buff *skb, int attrtype, int attrlen,
  		  const void *data, int padattr)
  {
  	size_t len;
  
  	if (nla_need_padding_for_64bit(skb))
  		len = nla_total_size_64bit(attrlen);
  	else
  		len = nla_total_size(attrlen);
  	if (unlikely(skb_tailroom(skb) < len))
  		return -EMSGSIZE;
  
  	__nla_put_64bit(skb, attrtype, attrlen, data, padattr);
  	return 0;
  }
  EXPORT_SYMBOL(nla_put_64bit);
  
  /**
fe4944e59   Thomas Graf   [NETLINK]: Extend...
848
849
850
851
852
   * nla_put_nohdr - Add a netlink attribute without header
   * @skb: socket buffer to add attribute to
   * @attrlen: length of attribute payload
   * @data: head of attribute payload
   *
bc3ed28ca   Thomas Graf   netlink: Improve ...
853
   * Returns -EMSGSIZE if the tailroom of the skb is insufficient to store
fe4944e59   Thomas Graf   [NETLINK]: Extend...
854
855
856
857
858
   * the attribute payload.
   */
  int nla_put_nohdr(struct sk_buff *skb, int attrlen, const void *data)
  {
  	if (unlikely(skb_tailroom(skb) < NLA_ALIGN(attrlen)))
bc3ed28ca   Thomas Graf   netlink: Improve ...
859
  		return -EMSGSIZE;
fe4944e59   Thomas Graf   [NETLINK]: Extend...
860
861
862
863
  
  	__nla_put_nohdr(skb, attrlen, data);
  	return 0;
  }
908002161   Herbert Xu   nlattr: Fix build...
864
  EXPORT_SYMBOL(nla_put_nohdr);
bfa83a9e0   Thomas Graf   [NETLINK]: Type-s...
865

01480e1cf   Patrick McHardy   [NETLINK]: Add nl...
866
867
868
869
870
871
  /**
   * nla_append - Add a netlink attribute without header or padding
   * @skb: socket buffer to add attribute to
   * @attrlen: length of attribute payload
   * @data: head of attribute payload
   *
bc3ed28ca   Thomas Graf   netlink: Improve ...
872
   * Returns -EMSGSIZE if the tailroom of the skb is insufficient to store
01480e1cf   Patrick McHardy   [NETLINK]: Add nl...
873
874
875
876
877
   * the attribute payload.
   */
  int nla_append(struct sk_buff *skb, int attrlen, const void *data)
  {
  	if (unlikely(skb_tailroom(skb) < NLA_ALIGN(attrlen)))
bc3ed28ca   Thomas Graf   netlink: Improve ...
878
  		return -EMSGSIZE;
01480e1cf   Patrick McHardy   [NETLINK]: Add nl...
879

59ae1d127   Johannes Berg   networking: intro...
880
  	skb_put_data(skb, data, attrlen);
01480e1cf   Patrick McHardy   [NETLINK]: Add nl...
881
882
  	return 0;
  }
908002161   Herbert Xu   nlattr: Fix build...
883
884
  EXPORT_SYMBOL(nla_append);
  #endif