Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.15-rc4 328 lines 8.2 kB view raw
1/* 2 * NETLINK Netlink attributes 3 * 4 * Authors: Thomas Graf <tgraf@suug.ch> 5 * Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> 6 */ 7 8#include <linux/config.h> 9#include <linux/module.h> 10#include <linux/kernel.h> 11#include <linux/errno.h> 12#include <linux/jiffies.h> 13#include <linux/netdevice.h> 14#include <linux/skbuff.h> 15#include <linux/string.h> 16#include <linux/types.h> 17#include <net/netlink.h> 18 19static u16 nla_attr_minlen[NLA_TYPE_MAX+1] __read_mostly = { 20 [NLA_U8] = sizeof(u8), 21 [NLA_U16] = sizeof(u16), 22 [NLA_U32] = sizeof(u32), 23 [NLA_U64] = sizeof(u64), 24 [NLA_STRING] = 1, 25 [NLA_NESTED] = NLA_HDRLEN, 26}; 27 28static int validate_nla(struct nlattr *nla, int maxtype, 29 struct nla_policy *policy) 30{ 31 struct nla_policy *pt; 32 int minlen = 0; 33 34 if (nla->nla_type <= 0 || nla->nla_type > maxtype) 35 return 0; 36 37 pt = &policy[nla->nla_type]; 38 39 BUG_ON(pt->type > NLA_TYPE_MAX); 40 41 if (pt->minlen) 42 minlen = pt->minlen; 43 else if (pt->type != NLA_UNSPEC) 44 minlen = nla_attr_minlen[pt->type]; 45 46 if (pt->type == NLA_FLAG && nla_len(nla) > 0) 47 return -ERANGE; 48 49 if (nla_len(nla) < minlen) 50 return -ERANGE; 51 52 return 0; 53} 54 55/** 56 * nla_validate - Validate a stream of attributes 57 * @head: head of attribute stream 58 * @len: length of attribute stream 59 * @maxtype: maximum attribute type to be expected 60 * @policy: validation policy 61 * 62 * Validates all attributes in the specified attribute stream against the 63 * specified policy. Attributes with a type exceeding maxtype will be 64 * ignored. See documenation of struct nla_policy for more details. 65 * 66 * Returns 0 on success or a negative error code. 67 */ 68int nla_validate(struct nlattr *head, int len, int maxtype, 69 struct nla_policy *policy) 70{ 71 struct nlattr *nla; 72 int rem, err; 73 74 nla_for_each_attr(nla, head, len, rem) { 75 err = validate_nla(nla, maxtype, policy); 76 if (err < 0) 77 goto errout; 78 } 79 80 err = 0; 81errout: 82 return err; 83} 84 85/** 86 * nla_parse - Parse a stream of attributes into a tb buffer 87 * @tb: destination array with maxtype+1 elements 88 * @maxtype: maximum attribute type to be expected 89 * @head: head of attribute stream 90 * @len: length of attribute stream 91 * 92 * Parses a stream of attributes and stores a pointer to each attribute in 93 * the tb array accessable via the attribute type. Attributes with a type 94 * exceeding maxtype will be silently ignored for backwards compatibility 95 * reasons. policy may be set to NULL if no validation is required. 96 * 97 * Returns 0 on success or a negative error code. 98 */ 99int nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head, int len, 100 struct nla_policy *policy) 101{ 102 struct nlattr *nla; 103 int rem, err; 104 105 memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1)); 106 107 nla_for_each_attr(nla, head, len, rem) { 108 u16 type = nla->nla_type; 109 110 if (type > 0 && type <= maxtype) { 111 if (policy) { 112 err = validate_nla(nla, maxtype, policy); 113 if (err < 0) 114 goto errout; 115 } 116 117 tb[type] = nla; 118 } 119 } 120 121 if (unlikely(rem > 0)) 122 printk(KERN_WARNING "netlink: %d bytes leftover after parsing " 123 "attributes.\n", rem); 124 125 err = 0; 126errout: 127 return err; 128} 129 130/** 131 * nla_find - Find a specific attribute in a stream of attributes 132 * @head: head of attribute stream 133 * @len: length of attribute stream 134 * @attrtype: type of attribute to look for 135 * 136 * Returns the first attribute in the stream matching the specified type. 137 */ 138struct nlattr *nla_find(struct nlattr *head, int len, int attrtype) 139{ 140 struct nlattr *nla; 141 int rem; 142 143 nla_for_each_attr(nla, head, len, rem) 144 if (nla->nla_type == attrtype) 145 return nla; 146 147 return NULL; 148} 149 150/** 151 * nla_strlcpy - Copy string attribute payload into a sized buffer 152 * @dst: where to copy the string to 153 * @src: attribute to copy the string from 154 * @dstsize: size of destination buffer 155 * 156 * Copies at most dstsize - 1 bytes into the destination buffer. 157 * The result is always a valid NUL-terminated string. Unlike 158 * strlcpy the destination buffer is always padded out. 159 * 160 * Returns the length of the source buffer. 161 */ 162size_t nla_strlcpy(char *dst, const struct nlattr *nla, size_t dstsize) 163{ 164 size_t srclen = nla_len(nla); 165 char *src = nla_data(nla); 166 167 if (srclen > 0 && src[srclen - 1] == '\0') 168 srclen--; 169 170 if (dstsize > 0) { 171 size_t len = (srclen >= dstsize) ? dstsize - 1 : srclen; 172 173 memset(dst, 0, dstsize); 174 memcpy(dst, src, len); 175 } 176 177 return srclen; 178} 179 180/** 181 * nla_memcpy - Copy a netlink attribute into another memory area 182 * @dest: where to copy to memcpy 183 * @src: netlink attribute to copy from 184 * @count: size of the destination area 185 * 186 * Note: The number of bytes copied is limited by the length of 187 * attribute's payload. memcpy 188 * 189 * Returns the number of bytes copied. 190 */ 191int nla_memcpy(void *dest, struct nlattr *src, int count) 192{ 193 int minlen = min_t(int, count, nla_len(src)); 194 195 memcpy(dest, nla_data(src), minlen); 196 197 return minlen; 198} 199 200/** 201 * nla_memcmp - Compare an attribute with sized memory area 202 * @nla: netlink attribute 203 * @data: memory area 204 * @size: size of memory area 205 */ 206int nla_memcmp(const struct nlattr *nla, const void *data, 207 size_t size) 208{ 209 int d = nla_len(nla) - size; 210 211 if (d == 0) 212 d = memcmp(nla_data(nla), data, size); 213 214 return d; 215} 216 217/** 218 * nla_strcmp - Compare a string attribute against a string 219 * @nla: netlink string attribute 220 * @str: another string 221 */ 222int nla_strcmp(const struct nlattr *nla, const char *str) 223{ 224 int len = strlen(str) + 1; 225 int d = nla_len(nla) - len; 226 227 if (d == 0) 228 d = memcmp(nla_data(nla), str, len); 229 230 return d; 231} 232 233/** 234 * __nla_reserve - reserve room for attribute on the skb 235 * @skb: socket buffer to reserve room on 236 * @attrtype: attribute type 237 * @attrlen: length of attribute payload 238 * 239 * Adds a netlink attribute header to a socket buffer and reserves 240 * room for the payload but does not copy it. 241 * 242 * The caller is responsible to ensure that the skb provides enough 243 * tailroom for the attribute header and payload. 244 */ 245struct nlattr *__nla_reserve(struct sk_buff *skb, int attrtype, int attrlen) 246{ 247 struct nlattr *nla; 248 249 nla = (struct nlattr *) skb_put(skb, nla_total_size(attrlen)); 250 nla->nla_type = attrtype; 251 nla->nla_len = nla_attr_size(attrlen); 252 253 memset((unsigned char *) nla + nla->nla_len, 0, nla_padlen(attrlen)); 254 255 return nla; 256} 257 258/** 259 * nla_reserve - reserve room for attribute on the skb 260 * @skb: socket buffer to reserve room on 261 * @attrtype: attribute type 262 * @attrlen: length of attribute payload 263 * 264 * Adds a netlink attribute header to a socket buffer and reserves 265 * room for the payload but does not copy it. 266 * 267 * Returns NULL if the tailroom of the skb is insufficient to store 268 * the attribute header and payload. 269 */ 270struct nlattr *nla_reserve(struct sk_buff *skb, int attrtype, int attrlen) 271{ 272 if (unlikely(skb_tailroom(skb) < nla_total_size(attrlen))) 273 return NULL; 274 275 return __nla_reserve(skb, attrtype, attrlen); 276} 277 278/** 279 * __nla_put - Add a netlink attribute to a socket buffer 280 * @skb: socket buffer to add attribute to 281 * @attrtype: attribute type 282 * @attrlen: length of attribute payload 283 * @data: head of attribute payload 284 * 285 * The caller is responsible to ensure that the skb provides enough 286 * tailroom for the attribute header and payload. 287 */ 288void __nla_put(struct sk_buff *skb, int attrtype, int attrlen, 289 const void *data) 290{ 291 struct nlattr *nla; 292 293 nla = __nla_reserve(skb, attrtype, attrlen); 294 memcpy(nla_data(nla), data, attrlen); 295} 296 297 298/** 299 * nla_put - Add a netlink attribute to a socket buffer 300 * @skb: socket buffer to add attribute to 301 * @attrtype: attribute type 302 * @attrlen: length of attribute payload 303 * @data: head of attribute payload 304 * 305 * Returns -1 if the tailroom of the skb is insufficient to store 306 * the attribute header and payload. 307 */ 308int nla_put(struct sk_buff *skb, int attrtype, int attrlen, const void *data) 309{ 310 if (unlikely(skb_tailroom(skb) < nla_total_size(attrlen))) 311 return -1; 312 313 __nla_put(skb, attrtype, attrlen, data); 314 return 0; 315} 316 317 318EXPORT_SYMBOL(nla_validate); 319EXPORT_SYMBOL(nla_parse); 320EXPORT_SYMBOL(nla_find); 321EXPORT_SYMBOL(nla_strlcpy); 322EXPORT_SYMBOL(__nla_reserve); 323EXPORT_SYMBOL(nla_reserve); 324EXPORT_SYMBOL(__nla_put); 325EXPORT_SYMBOL(nla_put); 326EXPORT_SYMBOL(nla_memcpy); 327EXPORT_SYMBOL(nla_memcmp); 328EXPORT_SYMBOL(nla_strcmp);