// __rtnl_unlock(); // rtnl = net->rtnl; { struct netlink_dump_control c = { .dump = dumpit, .min_dump_alloc = min_dump_alloc, }; err = netlink_dump_start(skb, nlh, &c); } // rtnl_lock(); return err; } RTE_LOG(INFO, QoS, "family: %d, type: %d\n", family, type); doit = rtnl_get_doit(family, type); if (doit == NULL) { RTE_LOG(ERR, QoS, "Operation is not supported!\n"); return -EOPNOTSUPP; } return doit(skb, nlh); } //void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err) //{ // struct sk_buff *skb; // struct nlmsghdr *rep; // struct nlmsgerr *errmsg; // size_t payload = sizeof(*errmsg);
static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) { rtnl_doit_func doit; int sz_idx, kind; int min_len; int family; int type; int err; type = nlh->nlmsg_type; if (type > RTM_MAX) return -EOPNOTSUPP; type -= RTM_BASE; /* All the messages must have at least 1 byte length */ if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtgenmsg))) return 0; family = ((struct rtgenmsg*)NLMSG_DATA(nlh))->rtgen_family; if (family >= NPROTO) return -EAFNOSUPPORT; sz_idx = type>>2; kind = type&3; if (kind != 2 && security_netlink_recv(skb, CAP_NET_ADMIN)) return -EPERM; if (kind == 2 && nlh->nlmsg_flags&NLM_F_DUMP) { rtnl_dumpit_func dumpit; dumpit = rtnl_get_dumpit(family, type); if (dumpit == NULL) return -EOPNOTSUPP; __rtnl_unlock(); err = netlink_dump_start(rtnl, skb, nlh, dumpit, NULL); rtnl_lock(); return err; } memset(rta_buf, 0, (rtattr_max * sizeof(struct rtattr *))); min_len = rtm_min[sz_idx]; if (nlh->nlmsg_len < min_len) return -EINVAL; if (nlh->nlmsg_len > min_len) { int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len); struct rtattr *attr = (void*)nlh + NLMSG_ALIGN(min_len); while (RTA_OK(attr, attrlen)) { unsigned flavor = attr->rta_type; if (flavor) { if (flavor > rta_max[sz_idx]) return -EINVAL; rta_buf[flavor-1] = attr; } attr = RTA_NEXT(attr, attrlen); } } doit = rtnl_get_doit(family, type); if (doit == NULL) return -EOPNOTSUPP; return doit(skb, nlh, (void *)&rta_buf[0]); }