libmnl  1.0.3
attr.c
00001 /*
00002  * (C) 2008-2012 by Pablo Neira Ayuso <pablo@netfilter.org>
00003  *
00004  * This program is free software; you can redistribute it and/or modify
00005  * it under the terms of the GNU Lesser General Public License as published
00006  * by the Free Software Foundation; either version 2.1 of the License, or
00007  * (at your option) any later version.
00008  */
00009 #include <limits.h>     /* for INT_MAX */
00010 #include <libmnl/libmnl.h>
00011 #include <string.h>
00012 #include <errno.h>
00013 #include "internal.h"
00014 
00038 uint16_t mnl_attr_get_type(const struct nlattr *attr)
00039 {
00040         return attr->nla_type & NLA_TYPE_MASK;
00041 }
00042 EXPORT_SYMBOL(mnl_attr_get_type);
00043 
00051 uint16_t mnl_attr_get_len(const struct nlattr *attr)
00052 {
00053         return attr->nla_len;
00054 }
00055 EXPORT_SYMBOL(mnl_attr_get_len);
00056 
00063 uint16_t mnl_attr_get_payload_len(const struct nlattr *attr)
00064 {
00065         return attr->nla_len - MNL_ATTR_HDRLEN;
00066 }
00067 EXPORT_SYMBOL(mnl_attr_get_payload_len);
00068 
00075 void *mnl_attr_get_payload(const struct nlattr *attr)
00076 {
00077         return (void *)attr + MNL_ATTR_HDRLEN;
00078 }
00079 EXPORT_SYMBOL(mnl_attr_get_payload);
00080 
00097 bool mnl_attr_ok(const struct nlattr *attr, int len)
00098 {
00099         return len >= (int)sizeof(struct nlattr) &&
00100                attr->nla_len >= sizeof(struct nlattr) &&
00101                (int)attr->nla_len <= len;
00102 }
00103 EXPORT_SYMBOL(mnl_attr_ok);
00104 
00114 struct nlattr *mnl_attr_next(const struct nlattr *attr)
00115 {
00116         return (struct nlattr *)((void *)attr + MNL_ALIGN(attr->nla_len));
00117 }
00118 EXPORT_SYMBOL(mnl_attr_next);
00119 
00134 int mnl_attr_type_valid(const struct nlattr *attr, uint16_t max)
00135 {
00136         if (mnl_attr_get_type(attr) > max) {
00137                 errno = EOPNOTSUPP;
00138                 return -1;
00139         }
00140         return 1;
00141 }
00142 EXPORT_SYMBOL(mnl_attr_type_valid);
00143 
00144 static int __mnl_attr_validate(const struct nlattr *attr,
00145                                enum mnl_attr_data_type type, size_t exp_len)
00146 {
00147         uint16_t attr_len = mnl_attr_get_payload_len(attr);
00148         const char *attr_data = mnl_attr_get_payload(attr);
00149 
00150         if (attr_len < exp_len) {
00151                 errno = ERANGE;
00152                 return -1;
00153         }
00154         switch(type) {
00155         case MNL_TYPE_FLAG:
00156                 if (attr_len > 0) {
00157                         errno = ERANGE;
00158                         return -1;
00159                 }
00160                 break;
00161         case MNL_TYPE_NUL_STRING:
00162                 if (attr_len == 0) {
00163                         errno = ERANGE;
00164                         return -1;
00165                 }
00166                 if (attr_data[attr_len-1] != '\0') {
00167                         errno = EINVAL;
00168                         return -1;
00169                 }
00170                 break;
00171         case MNL_TYPE_STRING:
00172                 if (attr_len == 0) {
00173                         errno = ERANGE;
00174                         return -1;
00175                 }
00176                 break;
00177         case MNL_TYPE_NESTED:
00178                 /* empty nested attributes are OK. */
00179                 if (attr_len == 0)
00180                         break;
00181                 /* if not empty, they must contain one header, eg. flag */
00182                 if (attr_len < MNL_ATTR_HDRLEN) {
00183                         errno = ERANGE;
00184                         return -1;
00185                 }
00186                 break;
00187         default:
00188                 /* make gcc happy. */
00189                 break;
00190         }
00191         if (exp_len && attr_len > exp_len) {
00192                 errno = ERANGE;
00193                 return -1;
00194         }
00195         return 0;
00196 }
00197 
00198 static const size_t mnl_attr_data_type_len[MNL_TYPE_MAX] = {
00199         [MNL_TYPE_U8]           = sizeof(uint8_t),
00200         [MNL_TYPE_U16]          = sizeof(uint16_t),
00201         [MNL_TYPE_U32]          = sizeof(uint32_t),
00202         [MNL_TYPE_U64]          = sizeof(uint64_t),
00203 };
00204 
00214 int mnl_attr_validate(const struct nlattr *attr, enum mnl_attr_data_type type)
00215 {
00216         int exp_len;
00217 
00218         if (type >= MNL_TYPE_MAX) {
00219                 errno = EINVAL;
00220                 return -1;
00221         }
00222         exp_len = mnl_attr_data_type_len[type];
00223         return __mnl_attr_validate(attr, type, exp_len);
00224 }
00225 EXPORT_SYMBOL(mnl_attr_validate);
00226 
00237 int
00238 mnl_attr_validate2(const struct nlattr *attr, enum mnl_attr_data_type type,
00239                    size_t exp_len)
00240 {
00241         if (type >= MNL_TYPE_MAX) {
00242                 errno = EINVAL;
00243                 return -1;
00244         }
00245         return __mnl_attr_validate(attr, type, exp_len);
00246 }
00247 EXPORT_SYMBOL(mnl_attr_validate2);
00248 
00264 int
00265 mnl_attr_parse(const struct nlmsghdr *nlh, unsigned int offset,
00266                mnl_attr_cb_t cb, void *data)
00267 {
00268         int ret = MNL_CB_OK;
00269         const struct nlattr *attr;
00270 
00271         mnl_attr_for_each(attr, nlh, offset)
00272                 if ((ret = cb(attr, data)) <= MNL_CB_STOP)
00273                         return ret;
00274         return ret;
00275 }
00276 EXPORT_SYMBOL(mnl_attr_parse);
00277 
00292 int
00293 mnl_attr_parse_nested(const struct nlattr *nested, mnl_attr_cb_t cb,
00294                       void *data)
00295 {
00296         int ret = MNL_CB_OK;
00297         const struct nlattr *attr;
00298 
00299         mnl_attr_for_each_nested(attr, nested)
00300                 if ((ret = cb(attr, data)) <= MNL_CB_STOP)
00301                         return ret;
00302         return ret;
00303 }
00304 EXPORT_SYMBOL(mnl_attr_parse_nested);
00305 
00325 int
00326 mnl_attr_parse_payload(const void *payload, size_t payload_len,
00327                        mnl_attr_cb_t cb, void *data)
00328 {
00329         int ret = MNL_CB_OK;
00330         const struct nlattr *attr;
00331 
00332         mnl_attr_for_each_payload(payload, payload_len)
00333                 if ((ret = cb(attr, data)) <= MNL_CB_STOP)
00334                         return ret;
00335         return ret;
00336 }
00337 EXPORT_SYMBOL(mnl_attr_parse_payload);
00338 
00345 uint8_t mnl_attr_get_u8(const struct nlattr *attr)
00346 {
00347         return *((uint8_t *)mnl_attr_get_payload(attr));
00348 }
00349 EXPORT_SYMBOL(mnl_attr_get_u8);
00350 
00357 uint16_t mnl_attr_get_u16(const struct nlattr *attr)
00358 {
00359         return *((uint16_t *)mnl_attr_get_payload(attr));
00360 }
00361 EXPORT_SYMBOL(mnl_attr_get_u16);
00362 
00369 uint32_t mnl_attr_get_u32(const struct nlattr *attr)
00370 {
00371         return *((uint32_t *)mnl_attr_get_payload(attr));
00372 }
00373 EXPORT_SYMBOL(mnl_attr_get_u32);
00374 
00383 uint64_t mnl_attr_get_u64(const struct nlattr *attr)
00384 {
00385         uint64_t tmp;
00386         memcpy(&tmp, mnl_attr_get_payload(attr), sizeof(tmp));
00387         return tmp;
00388 }
00389 EXPORT_SYMBOL(mnl_attr_get_u64);
00390 
00397 const char *mnl_attr_get_str(const struct nlattr *attr)
00398 {
00399         return mnl_attr_get_payload(attr);
00400 }
00401 EXPORT_SYMBOL(mnl_attr_get_str);
00402 
00413 void
00414 mnl_attr_put(struct nlmsghdr *nlh, uint16_t type, size_t len, const void *data)
00415 {
00416         struct nlattr *attr = mnl_nlmsg_get_payload_tail(nlh);
00417         uint16_t payload_len = MNL_ALIGN(sizeof(struct nlattr)) + len;
00418 
00419         attr->nla_type = type;
00420         attr->nla_len = payload_len;
00421         memcpy(mnl_attr_get_payload(attr), data, len);
00422         nlh->nlmsg_len += MNL_ALIGN(payload_len);
00423 }
00424 EXPORT_SYMBOL(mnl_attr_put);
00425 
00436 void mnl_attr_put_u8(struct nlmsghdr *nlh, uint16_t type, uint8_t data)
00437 {
00438         mnl_attr_put(nlh, type, sizeof(uint8_t), &data);
00439 }
00440 EXPORT_SYMBOL(mnl_attr_put_u8);
00441 
00451 void mnl_attr_put_u16(struct nlmsghdr *nlh, uint16_t type, uint16_t data)
00452 {
00453         mnl_attr_put(nlh, type, sizeof(uint16_t), &data);
00454 }
00455 EXPORT_SYMBOL(mnl_attr_put_u16);
00456 
00466 void mnl_attr_put_u32(struct nlmsghdr *nlh, uint16_t type, uint32_t data)
00467 {
00468         mnl_attr_put(nlh, type, sizeof(uint32_t), &data);
00469 }
00470 EXPORT_SYMBOL(mnl_attr_put_u32);
00471 
00481 void mnl_attr_put_u64(struct nlmsghdr *nlh, uint16_t type, uint64_t data)
00482 {
00483         mnl_attr_put(nlh, type, sizeof(uint64_t), &data);
00484 }
00485 EXPORT_SYMBOL(mnl_attr_put_u64);
00486 
00496 void mnl_attr_put_str(struct nlmsghdr *nlh, uint16_t type, const char *data)
00497 {
00498         mnl_attr_put(nlh, type, strlen(data), data);
00499 }
00500 EXPORT_SYMBOL(mnl_attr_put_str);
00501 
00514 void mnl_attr_put_strz(struct nlmsghdr *nlh, uint16_t type, const char *data)
00515 {
00516         mnl_attr_put(nlh, type, strlen(data)+1, data);
00517 }
00518 EXPORT_SYMBOL(mnl_attr_put_strz);
00519 
00529 struct nlattr *mnl_attr_nest_start(struct nlmsghdr *nlh, uint16_t type)
00530 {
00531         struct nlattr *start = mnl_nlmsg_get_payload_tail(nlh);
00532 
00533         /* set start->nla_len in mnl_attr_nest_end() */
00534         start->nla_type = NLA_F_NESTED | type;
00535         nlh->nlmsg_len += MNL_ALIGN(sizeof(struct nlattr));
00536 
00537         return start;
00538 }
00539 EXPORT_SYMBOL(mnl_attr_nest_start);
00540 
00555 bool
00556 mnl_attr_put_check(struct nlmsghdr *nlh, size_t buflen,
00557                    uint16_t type, size_t len, const void *data)
00558 {
00559         if (nlh->nlmsg_len + MNL_ATTR_HDRLEN + MNL_ALIGN(len) > buflen)
00560                 return false;
00561         mnl_attr_put(nlh, type, len, data);
00562         return true;
00563 }
00564 EXPORT_SYMBOL(mnl_attr_put_check);
00565 
00580 bool
00581 mnl_attr_put_u8_check(struct nlmsghdr *nlh, size_t buflen,
00582                       uint16_t type, uint8_t data)
00583 {
00584         return mnl_attr_put_check(nlh, buflen, type, sizeof(uint8_t), &data);
00585 }
00586 EXPORT_SYMBOL(mnl_attr_put_u8_check);
00587 
00603 bool
00604 mnl_attr_put_u16_check(struct nlmsghdr *nlh, size_t buflen,
00605                        uint16_t type, uint16_t data)
00606 {
00607         return mnl_attr_put_check(nlh, buflen, type, sizeof(uint16_t), &data);
00608 }
00609 EXPORT_SYMBOL(mnl_attr_put_u16_check);
00610 
00626 bool
00627 mnl_attr_put_u32_check(struct nlmsghdr *nlh, size_t buflen,
00628                        uint16_t type, uint32_t data)
00629 {
00630         return mnl_attr_put_check(nlh, buflen, type, sizeof(uint32_t), &data);
00631 }
00632 EXPORT_SYMBOL(mnl_attr_put_u32_check);
00633 
00649 bool
00650 mnl_attr_put_u64_check(struct nlmsghdr *nlh, size_t buflen,
00651                        uint16_t type, uint64_t data)
00652 {
00653         return mnl_attr_put_check(nlh, buflen, type, sizeof(uint64_t), &data);
00654 }
00655 EXPORT_SYMBOL(mnl_attr_put_u64_check);
00656 
00672 bool
00673 mnl_attr_put_str_check(struct nlmsghdr *nlh, size_t buflen,
00674                        uint16_t type, const char *data)
00675 {
00676         return mnl_attr_put_check(nlh, buflen, type, strlen(data), data);
00677 }
00678 EXPORT_SYMBOL(mnl_attr_put_str_check);
00679 
00696 bool
00697 mnl_attr_put_strz_check(struct nlmsghdr *nlh, size_t buflen,
00698                         uint16_t type, const char *data)
00699 {
00700         return mnl_attr_put_check(nlh, buflen, type, strlen(data)+1, data);
00701 }
00702 EXPORT_SYMBOL(mnl_attr_put_strz_check);
00703 
00714 struct nlattr *
00715 mnl_attr_nest_start_check(struct nlmsghdr *nlh, size_t buflen, uint16_t type)
00716 {
00717         if (nlh->nlmsg_len + MNL_ATTR_HDRLEN > buflen)
00718                 return NULL;
00719         return mnl_attr_nest_start(nlh, type);
00720 }
00721 EXPORT_SYMBOL(mnl_attr_nest_start_check);
00722 
00730 void
00731 mnl_attr_nest_end(struct nlmsghdr *nlh, struct nlattr *start)
00732 {
00733         start->nla_len = mnl_nlmsg_get_payload_tail(nlh) - (void *)start;
00734 }
00735 EXPORT_SYMBOL(mnl_attr_nest_end);
00736 
00744 void
00745 mnl_attr_nest_cancel(struct nlmsghdr *nlh, struct nlattr *start)
00746 {
00747         nlh->nlmsg_len -= mnl_nlmsg_get_payload_tail(nlh) - (void *)start;
00748 }
00749 EXPORT_SYMBOL(mnl_attr_nest_cancel);
00750