static struct nlattr * find_dump_kind(const struct nlmsghdr *n) { struct nlattr *tb1, *tb2[TCA_ACT_MAX + 1]; struct nlattr *tb[TCA_ACT_MAX_PRIO + 1]; struct nlattr *nla[TCAA_MAX + 1]; struct nlattr *kind; if (nlmsg_parse(n, sizeof(struct tcamsg), nla, TCAA_MAX, NULL) < 0) return NULL; tb1 = nla[TCA_ACT_TAB]; if (tb1 == NULL) return NULL; if (nla_parse(tb, TCA_ACT_MAX_PRIO, nla_data(tb1), NLMSG_ALIGN(nla_len(tb1)), NULL) < 0) return NULL; if (tb[1] == NULL) return NULL; if (nla_parse(tb2, TCA_ACT_MAX, nla_data(tb[1]), nla_len(tb[1]), NULL) < 0) return NULL; kind = tb2[TCA_ACT_KIND]; return kind; }
static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) { struct ifinfomsg *ifm; struct nlattr *tb[IFLA_MAX+1]; struct net_device *dev = NULL; struct sk_buff *nskb; char *iw_buf = NULL, *iw = NULL; int iw_buf_len = 0; int err; err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy); if (err < 0) return err; ifm = nlmsg_data(nlh); if (ifm->ifi_index >= 0) { dev = dev_get_by_index(ifm->ifi_index); if (dev == NULL) return -ENODEV; } else return -EINVAL; #ifdef CONFIG_NET_WIRELESS_RTNETLINK if (tb[IFLA_WIRELESS]) { /* Call Wireless Extensions. We need to know the size before * we can alloc. Various stuff checked in there... */ err = wireless_rtnetlink_get(dev, nla_data(tb[IFLA_WIRELESS]), nla_len(tb[IFLA_WIRELESS]), &iw_buf, &iw_buf_len); if (err < 0) goto errout; iw += IW_EV_POINT_OFF; } #endif /* CONFIG_NET_WIRELESS_RTNETLINK */ nskb = nlmsg_new(if_nlmsg_size(iw_buf_len), GFP_KERNEL); if (nskb == NULL) { err = -ENOBUFS; goto errout; } err = rtnl_fill_ifinfo(nskb, dev, iw, iw_buf_len, RTM_NEWLINK, NETLINK_CB(skb).pid, nlh->nlmsg_seq, 0, 0); if (err < 0) { /* -EMSGSIZE implies BUG in if_nlmsg_size */ WARN_ON(err == -EMSGSIZE); kfree_skb(nskb); goto errout; } err = rtnl_unicast(nskb, NETLINK_CB(skb).pid); errout: kfree(iw_buf); dev_put(dev); return err; }
static NMIP6Device * process_newlink (NMIP6Manager *manager, struct nl_msg *msg) { struct nlmsghdr *hdr = nlmsg_hdr (msg); struct ifinfomsg *ifi; NMIP6Device *device; struct nlattr *tb[IFLA_MAX + 1]; struct nlattr *pi[IFLA_INET6_MAX + 1]; int err; /* FIXME: we have to do this manually for now since libnl doesn't yet * support the IFLA_PROTINFO attribute of NEWLINK messages. When it does, * we can get rid of this function and just grab IFLA_PROTINFO from * nm_ip6_device_sync_from_netlink(), then get the IFLA_INET6_FLAGS out of * the PROTINFO. */ err = nlmsg_parse (hdr, sizeof (*ifi), tb, IFLA_MAX, link_policy); if (err < 0) { nm_log_dbg (LOGD_IP6, "ignoring invalid newlink netlink message " "while parsing PROTINFO attribute"); return NULL; } ifi = nlmsg_data (hdr); if (ifi->ifi_family != AF_INET6) { nm_log_dbg (LOGD_IP6, "ignoring netlink message family %d", ifi->ifi_family); return NULL; } device = nm_ip6_manager_get_device (manager, ifi->ifi_index); if (!device || device->addrconf_complete) { nm_log_dbg (LOGD_IP6, "(%s): ignoring unknown or completed device", device ? device->iface : "(none)"); return NULL; } if (!tb[IFLA_PROTINFO]) { nm_log_dbg (LOGD_IP6, "(%s): message had no PROTINFO attribute", device->iface); return NULL; } err = nla_parse_nested (pi, IFLA_INET6_MAX, tb[IFLA_PROTINFO], link_prot_policy); if (err < 0) { nm_log_dbg (LOGD_IP6, "(%s): error parsing PROTINFO flags", device->iface); return NULL; } if (!pi[IFLA_INET6_FLAGS]) { nm_log_dbg (LOGD_IP6, "(%s): message had no PROTINFO flags", device->iface); return NULL; } device->ra_flags = nla_get_u32 (pi[IFLA_INET6_FLAGS]); nm_log_dbg (LOGD_IP6, "(%s): got IPv6 flags 0x%X", device->iface, device->ra_flags); return device; }
static int ct_restore_callback(struct nlmsghdr *nlh) { struct nfgenmsg *msg; struct nlattr *tb[CTA_MAX + 1], *tbp[CTA_PROTOINFO_MAX + 1], *tb_tcp[CTA_PROTOINFO_TCP_MAX + 1]; int err; msg = (nfgenmsg *)NLMSG_DATA(nlh); if (msg->nfgen_family != AF_INET && msg->nfgen_family != AF_INET6) return 0; err = nlmsg_parse(nlh, sizeof(struct nfgenmsg), tb, CTA_MAX, NULL); if (err < 0) return -1; if (restore_mark != 0 || restore_mark_mask != -1) { uint32_t* mark = (uint32_t*)nla_data(tb[CTA_MARK]); //printf("old mark: 0x%08x\n", ntohl(*mark)); *mark = (*mark & restore_mark_mask) ^ restore_mark; //printf("new mark: 0x%08x\n", ntohl(*mark)); } if (!tb[CTA_PROTOINFO]) return 0; err = nla_parse_nested(tbp, CTA_PROTOINFO_MAX, tb[CTA_PROTOINFO], NULL); if (err < 0) return -1; if (!tbp[CTA_PROTOINFO_TCP]) return 0; err = nla_parse_nested(tb_tcp, CTA_PROTOINFO_TCP_MAX, tbp[CTA_PROTOINFO_TCP], NULL); if (err < 0) return -1; if (tb_tcp[CTA_PROTOINFO_TCP_FLAGS_ORIGINAL]) { struct nf_ct_tcp_flags *flags; flags = (nf_ct_tcp_flags *)nla_data(tb_tcp[CTA_PROTOINFO_TCP_FLAGS_ORIGINAL]); flags->flags |= IP_CT_TCP_FLAG_BE_LIBERAL; flags->mask |= IP_CT_TCP_FLAG_BE_LIBERAL; } if (tb_tcp[CTA_PROTOINFO_TCP_FLAGS_REPLY]) { struct nf_ct_tcp_flags *flags; flags = (nf_ct_tcp_flags *)nla_data(tb_tcp[CTA_PROTOINFO_TCP_FLAGS_REPLY]); flags->flags |= IP_CT_TCP_FLAG_BE_LIBERAL; flags->mask |= IP_CT_TCP_FLAG_BE_LIBERAL; } return 0; }
int tipc_nlmsg_parse(const struct nlmsghdr *nlh, struct nlattr ***attr) { u32 maxattr = tipc_genl_family.maxattr; *attr = genl_family_attrbuf(&tipc_genl_family); if (!*attr) return -EOPNOTSUPP; return nlmsg_parse(nlh, GENL_HDRLEN, *attr, maxattr, tipc_nl_policy, NULL); }
static struct sk_buff *brc_send_command(struct sk_buff *request, struct nlattr **attrs) { unsigned long int flags; struct sk_buff *reply; int error; mutex_lock(&brc_serial); /* Increment sequence number first, so that we ignore any replies * to stale requests. */ spin_lock_irqsave(&brc_lock, flags); nlmsg_hdr(request)->nlmsg_seq = ++brc_seq; INIT_COMPLETION(brc_done); spin_unlock_irqrestore(&brc_lock, flags); nlmsg_end(request, nlmsg_hdr(request)); /* Send message. */ error = genlmsg_multicast(request, 0, brc_mc_group.id, GFP_KERNEL); if (error < 0) goto error; /* Wait for reply. */ error = -ETIMEDOUT; if (!wait_for_completion_timeout(&brc_done, BRC_TIMEOUT)) { pr_warn("timed out waiting for userspace\n"); goto error; } /* Grab reply. */ spin_lock_irqsave(&brc_lock, flags); reply = brc_reply; brc_reply = NULL; spin_unlock_irqrestore(&brc_lock, flags); mutex_unlock(&brc_serial); /* Re-parse message. Can't fail, since it parsed correctly once * already. */ error = nlmsg_parse(nlmsg_hdr(reply), GENL_HDRLEN, attrs, BRC_GENL_A_MAX, brc_genl_policy); WARN_ON(error); return reply; error: mutex_unlock(&brc_serial); return ERR_PTR(error); }
static int tc_ctl_action(struct sk_buff *skb, struct nlmsghdr *n, void *arg) { struct net *net = sock_net(skb->sk); struct nlattr *tca[TCA_ACT_MAX + 1]; u32 portid = skb ? NETLINK_CB(skb).portid : 0; int ret = 0, ovr = 0; if ((n->nlmsg_type != RTM_GETACTION) && !capable(CAP_NET_ADMIN)) return -EPERM; ret = nlmsg_parse(n, sizeof(struct tcamsg), tca, TCA_ACT_MAX, NULL); if (ret < 0) return ret; if (tca[TCA_ACT_TAB] == NULL) { pr_notice("tc_ctl_action: received NO action attribs\n"); return -EINVAL; } /* n->nlmsg_flags & NLM_F_CREATE */ switch (n->nlmsg_type) { case RTM_NEWACTION: /* we are going to assume all other flags * imply create only if it doesn't exist * Note that CREATE | EXCL implies that * but since we want avoid ambiguity (eg when flags * is zero) then just set this */ if (n->nlmsg_flags & NLM_F_REPLACE) ovr = 1; replay: ret = tcf_action_add(net, tca[TCA_ACT_TAB], n, portid, ovr); if (ret == -EAGAIN) goto replay; break; case RTM_DELACTION: ret = tca_action_gd(net, tca[TCA_ACT_TAB], n, portid, RTM_DELACTION); break; case RTM_GETACTION: ret = tca_action_gd(net, tca[TCA_ACT_TAB], n, portid, RTM_GETACTION); break; default: BUG(); } return ret; }
static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { struct net *net = sock_net(skb->sk); struct nlattr *tb[IFA_MAX+1]; struct in_device *in_dev; struct ifaddrmsg *ifm; struct in_ifaddr *ifa, **ifap; int err = -EINVAL; ASSERT_RTNL(); err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy); if (err < 0) goto errout; ifm = nlmsg_data(nlh); in_dev = inetdev_by_index(net, ifm->ifa_index); if (in_dev == NULL) { err = -ENODEV; goto errout; } __in_dev_put(in_dev); for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; ifap = &ifa->ifa_next) { if (tb[IFA_LOCAL] && ifa->ifa_local != nla_get_be32(tb[IFA_LOCAL])) continue; if (tb[IFA_LABEL] && nla_strcmp(tb[IFA_LABEL], ifa->ifa_label)) continue; if (tb[IFA_ADDRESS] && (ifm->ifa_prefixlen != ifa->ifa_prefixlen || !inet_ifa_match(nla_get_be32(tb[IFA_ADDRESS]), ifa))) continue; __inet_del_ifa(in_dev, ifap, 1, nlh, NETLINK_CB(skb).pid); return 0; } err = -EADDRNOTAVAIL; errout: return err; }
static int tc_ctl_action(struct sk_buff *skb, struct nlmsghdr *n, void *arg) { struct net *net = sock_net(skb->sk); struct nlattr *tca[TCA_ACT_MAX + 1]; u32 pid = skb ? NETLINK_CB(skb).pid : 0; int ret = 0, ovr = 0; if (net != &init_net) return -EINVAL; ret = nlmsg_parse(n, sizeof(struct tcamsg), tca, TCA_ACT_MAX, NULL); if (ret < 0) return ret; if (tca[TCA_ACT_TAB] == NULL) { printk("tc_ctl_action: received NO action attribs\n"); return -EINVAL; } switch (n->nlmsg_type) { case RTM_NEWACTION: if (n->nlmsg_flags&NLM_F_REPLACE) ovr = 1; replay: ret = tcf_action_add(tca[TCA_ACT_TAB], n, pid, ovr); if (ret == -EAGAIN) goto replay; break; case RTM_DELACTION: ret = tca_action_gd(tca[TCA_ACT_TAB], n, pid, RTM_DELACTION); break; case RTM_GETACTION: ret = tca_action_gd(tca[TCA_ACT_TAB], n, pid, RTM_GETACTION); break; default: BUG(); } return ret; }
static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) { struct ifinfomsg *ifm; struct nlattr *tb[IFLA_MAX+1]; struct net_device *dev = NULL; struct sk_buff *nskb; int err; err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy); if (err < 0) return err; ifm = nlmsg_data(nlh); if (ifm->ifi_index > 0) { dev = dev_get_by_index(ifm->ifi_index); if (dev == NULL) return -ENODEV; } else return -EINVAL; nskb = nlmsg_new(if_nlmsg_size(), GFP_KERNEL); if (nskb == NULL) { err = -ENOBUFS; goto errout; } err = rtnl_fill_ifinfo(nskb, dev, RTM_NEWLINK, NETLINK_CB(skb).pid, nlh->nlmsg_seq, 0, 0); if (err < 0) { /* -EMSGSIZE implies BUG in if_nlmsg_size */ WARN_ON(err == -EMSGSIZE); kfree_skb(nskb); goto errout; } err = rtnl_unicast(nskb, NETLINK_CB(skb).pid); errout: dev_put(dev); return err; }
int netlink_receive_one(struct nlmsghdr *hdr, void *arg) { struct nlattr *tb[NETLINK_DIAG_MAX+1]; struct netlink_diag_msg *m; struct netlink_sk_desc *sd; unsigned long *groups; m = NLMSG_DATA(hdr); pr_debug("Collect netlink sock 0x%x\n", m->ndiag_ino); sd = xmalloc(sizeof(*sd)); if (!sd) return -1; sd->protocol = m->ndiag_protocol; sd->portid = m->ndiag_portid; sd->dst_portid = m->ndiag_dst_portid; sd->dst_group = m->ndiag_dst_group; sd->state = m->ndiag_state; nlmsg_parse(hdr, sizeof(struct netlink_diag_msg), tb, NETLINK_DIAG_MAX, NULL); if (tb[NETLINK_DIAG_GROUPS]) { sd->gsize = nla_len(tb[NETLINK_DIAG_GROUPS]); groups = nla_data(tb[NETLINK_DIAG_GROUPS]); sd->groups = xmalloc(sd->gsize); if (!sd->groups) { xfree(sd); return -1; } memcpy(sd->groups, groups, sd->gsize); } else { sd->groups = NULL; sd->gsize = 0; } return sk_collect_one(m->ndiag_ino, PF_NETLINK, &sd->sd); }
static struct nfc_dev *__get_device_from_cb(struct netlink_callback *cb) { struct nlattr **attrbuf = genl_family_attrbuf(&nfc_genl_family); struct nfc_dev *dev; int rc; u32 idx; rc = nlmsg_parse(cb->nlh, GENL_HDRLEN + nfc_genl_family.hdrsize, attrbuf, nfc_genl_family.maxattr, nfc_genl_policy); if (rc < 0) return ERR_PTR(rc); if (!attrbuf[NFC_ATTR_DEVICE_INDEX]) return ERR_PTR(-EINVAL); idx = nla_get_u32(attrbuf[NFC_ATTR_DEVICE_INDEX]); dev = nfc_get_device(idx); if (!dev) return ERR_PTR(-ENODEV); return dev; }
static int rule_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, struct nlmsghdr *n, struct nl_parser_param *pp) { struct rtnl_rule *rule; struct fib_rule_hdr *frh; struct nlattr *tb[FRA_MAX+1]; int err = 1, family; rule = rtnl_rule_alloc(); if (!rule) { err = -NLE_NOMEM; goto errout; } rule->ce_msgtype = n->nlmsg_type; frh = nlmsg_data(n); err = nlmsg_parse(n, sizeof(*frh), tb, FRA_MAX, rule_policy); if (err < 0) goto errout; rule->r_family = family = frh->family; rule->r_table = frh->table; rule->r_action = frh->action; rule->r_flags = frh->flags; rule->ce_mask = (RULE_ATTR_FAMILY | RULE_ATTR_TABLE | RULE_ATTR_ACTION | RULE_ATTR_FLAGS); /* ipv4 only */ if (frh->tos) { rule->r_dsfield = frh->tos; rule->ce_mask |= RULE_ATTR_DSFIELD; } if (tb[FRA_TABLE]) { rule->r_table = nla_get_u32(tb[FRA_TABLE]); rule->ce_mask |= RULE_ATTR_TABLE; } if (tb[FRA_IIFNAME]) { nla_strlcpy(rule->r_iifname, tb[FRA_IIFNAME], IFNAMSIZ); rule->ce_mask |= RULE_ATTR_IIFNAME; } if (tb[FRA_OIFNAME]) { nla_strlcpy(rule->r_oifname, tb[FRA_OIFNAME], IFNAMSIZ); rule->ce_mask |= RULE_ATTR_OIFNAME; } if (tb[FRA_PRIORITY]) { rule->r_prio = nla_get_u32(tb[FRA_PRIORITY]); rule->ce_mask |= RULE_ATTR_PRIO; } if (tb[FRA_FWMARK]) { rule->r_mark = nla_get_u32(tb[FRA_FWMARK]); rule->ce_mask |= RULE_ATTR_MARK; } if (tb[FRA_FWMASK]) { rule->r_mask = nla_get_u32(tb[FRA_FWMASK]); rule->ce_mask |= RULE_ATTR_MASK; } if (tb[FRA_GOTO]) { rule->r_goto = nla_get_u32(tb[FRA_GOTO]); rule->ce_mask |= RULE_ATTR_GOTO; } if (tb[FRA_SRC]) { if (!(rule->r_src = nl_addr_alloc_attr(tb[FRA_SRC], family))) goto errout_enomem; nl_addr_set_prefixlen(rule->r_src, frh->src_len); rule->ce_mask |= RULE_ATTR_SRC; } if (tb[FRA_DST]) { if (!(rule->r_dst = nl_addr_alloc_attr(tb[FRA_DST], family))) goto errout_enomem; nl_addr_set_prefixlen(rule->r_dst, frh->dst_len); rule->ce_mask |= RULE_ATTR_DST; } /* ipv4 only */ if (tb[FRA_FLOW]) { rule->r_flow = nla_get_u32(tb[FRA_FLOW]); rule->ce_mask |= RULE_ATTR_FLOW; } err = pp->pp_cb((struct nl_object *) rule, pp); errout: rtnl_rule_put(rule); return err; errout_enomem: err = -NLE_NOMEM; goto errout; }
struct nfnl_log *nfnlmsg_log_parse(struct nlmsghdr *nlh) { struct nfnl_log *log; struct nlattr *tb[NFULA_MAX+1]; struct nlattr *attr; int err; log = nfnl_log_alloc(); if (!log) return NULL; log->ce_msgtype = nlh->nlmsg_type; err = nlmsg_parse(nlh, sizeof(struct nfgenmsg), tb, NFULA_MAX, log_policy); if (err < 0) goto errout; nfnl_log_set_family(log, nfnlmsg_family(nlh)); attr = tb[NFULA_PACKET_HDR]; if (attr) { struct nfulnl_msg_packet_hdr *hdr = nla_data(attr); nfnl_log_set_hwproto(log, hdr->hw_protocol); nfnl_log_set_hook(log, hdr->hook); } attr = tb[NFULA_MARK]; if (attr) nfnl_log_set_mark(log, ntohl(nla_get_u32(attr))); attr = tb[NFULA_TIMESTAMP]; if (attr) { struct nfulnl_msg_packet_timestamp *timestamp = nla_data(attr); struct timeval tv; tv.tv_sec = ntohll(timestamp->sec); tv.tv_usec = ntohll(timestamp->usec); nfnl_log_set_timestamp(log, &tv); } attr = tb[NFULA_IFINDEX_INDEV]; if (attr) nfnl_log_set_indev(log, ntohl(nla_get_u32(attr))); attr = tb[NFULA_IFINDEX_OUTDEV]; if (attr) nfnl_log_set_outdev(log, ntohl(nla_get_u32(attr))); attr = tb[NFULA_IFINDEX_PHYSINDEV]; if (attr) nfnl_log_set_physindev(log, ntohl(nla_get_u32(attr))); attr = tb[NFULA_IFINDEX_PHYSOUTDEV]; if (attr) nfnl_log_set_physoutdev(log, ntohl(nla_get_u32(attr))); attr = tb[NFULA_HWADDR]; if (attr) { struct nfulnl_msg_packet_hw *hw = nla_data(attr); nfnl_log_set_hwaddr(log, hw->hw_addr, ntohs(hw->hw_addrlen)); } attr = tb[NFULA_PAYLOAD]; if (attr) { err = nfnl_log_set_payload(log, nla_data(attr), nla_len(attr)); if (err < 0) goto errout; } attr = tb[NFULA_PREFIX]; if (attr) { err = nfnl_log_set_prefix(log, nla_data(attr)); if (err < 0) goto errout; } attr = tb[NFULA_UID]; if (attr) nfnl_log_set_uid(log, ntohl(nla_get_u32(attr))); attr = tb[NFULA_SEQ]; if (attr) nfnl_log_set_seq(log, ntohl(nla_get_u32(attr))); attr = tb[NFULA_SEQ_GLOBAL]; if (attr) nfnl_log_set_seq_global(log, ntohl(nla_get_u32(attr))); return log; errout: nfnl_log_put(log); return NULL; }
static int rtnl_raw_parse_cb(struct nl_msg *msg, void *arg) { struct nl_lookup_arg *lookup_arg = (struct nl_lookup_arg *)arg; struct usnic_rtnl_sk *unlsk = lookup_arg->unlsk; struct nlmsghdr *nlm_hdr = nlmsg_hdr(msg); struct rtmsg *rtm; struct nlattr *tb[RTA_MAX + 1]; int found = 0; int err; #if WANT_DEBUG_MSGS nl_msg_dump(msg, stderr); #endif /* WANT_DEBUG_MSGS */ lookup_arg->nh_addr = 0; lookup_arg->found = 0; lookup_arg->replied = 0; lookup_arg->msg_count++; if (nlm_hdr->nlmsg_pid != nl_socket_get_local_port(unlsk->nlh) || nlm_hdr->nlmsg_seq != unlsk->seq) { usnic_err("Not an expected reply msg pid: %u local pid: %u " "msg seq: %u expected seq: %u\n", nlm_hdr->nlmsg_pid, nl_socket_get_local_port(unlsk->nlh), nlm_hdr->nlmsg_seq, unlsk->seq); return NL_SKIP; } lookup_arg->replied = 1; if (nlm_hdr->nlmsg_type == NLMSG_ERROR) { struct nlmsgerr *e = (struct nlmsgerr *)nlmsg_data(nlm_hdr); if (nlm_hdr->nlmsg_len >= (__u32)nlmsg_msg_size(sizeof(*e))) { usnic_err("Received a netlink error message %d\n", e->error); } else { usnic_err("Received a truncated netlink error message\n"); } return NL_STOP; } if (nlm_hdr->nlmsg_type != RTM_NEWROUTE) { usnic_err("Received an invalid route request reply message\n"); return NL_STOP; } rtm = nlmsg_data(nlm_hdr); if (rtm->rtm_family != AF_INET) { usnic_err("RTM message contains invalid AF family\n"); return NL_STOP; } init_route_policy(route_policy); err = nlmsg_parse(nlm_hdr, sizeof(struct rtmsg), tb, RTA_MAX, route_policy); if (err < 0) { usnic_err("nlmsg parse error %d\n", err); return NL_STOP; } if (tb[RTA_OIF]) { if (nla_get_u32(tb[RTA_OIF]) == (uint32_t)lookup_arg->oif) found = 1; else usnic_err("Retrieved route has a different outgoing interface %d (expected %d)\n", nla_get_u32(tb[RTA_OIF]), lookup_arg->oif); } if (found && tb[RTA_METRICS]) { lookup_arg->metric = (int)nla_get_u32(tb[RTA_METRICS]); } if (found && tb[RTA_GATEWAY]) lookup_arg->nh_addr = nla_get_u32(tb[RTA_GATEWAY]); lookup_arg->found = found; return NL_STOP; }
int tca_msg_parser(struct nlmsghdr *n, struct rtnl_tc *g) { struct nlattr *tb[TCA_MAX + 1]; struct tcmsg *tm; int err; err = nlmsg_parse(n, sizeof(*tm), tb, TCA_MAX, tc_policy); if (err < 0) return err; if (tb[TCA_KIND] == NULL) return -NLE_MISSING_ATTR; nla_strlcpy(g->tc_kind, tb[TCA_KIND], TCKINDSIZ); tm = nlmsg_data(n); g->tc_family = tm->tcm_family; g->tc_ifindex = tm->tcm_ifindex; g->tc_handle = tm->tcm_handle; g->tc_parent = tm->tcm_parent; g->tc_info = tm->tcm_info; g->ce_mask = (TCA_ATTR_FAMILY | TCA_ATTR_IFINDEX | TCA_ATTR_HANDLE | TCA_ATTR_PARENT | TCA_ATTR_INFO | TCA_ATTR_KIND); if (tb[TCA_OPTIONS]) { g->tc_opts = nl_data_alloc_attr(tb[TCA_OPTIONS]); if (!g->tc_opts) return -NLE_NOMEM; g->ce_mask |= TCA_ATTR_OPTS; } if (tb[TCA_STATS2]) { struct nlattr *tbs[TCA_STATS_MAX + 1]; err = nla_parse_nested(tbs, TCA_STATS_MAX, tb[TCA_STATS2], tc_stats2_policy); if (err < 0) return err; if (tbs[TCA_STATS_BASIC]) { struct gnet_stats_basic *bs; bs = nla_data(tbs[TCA_STATS_BASIC]); g->tc_stats[RTNL_TC_BYTES] = bs->bytes; g->tc_stats[RTNL_TC_PACKETS] = bs->packets; } if (tbs[TCA_STATS_RATE_EST]) { struct gnet_stats_rate_est *re; re = nla_data(tbs[TCA_STATS_RATE_EST]); g->tc_stats[RTNL_TC_RATE_BPS] = re->bps; g->tc_stats[RTNL_TC_RATE_PPS] = re->pps; } if (tbs[TCA_STATS_QUEUE]) { struct gnet_stats_queue *q; q = nla_data(tbs[TCA_STATS_QUEUE]); g->tc_stats[RTNL_TC_QLEN] = q->qlen; g->tc_stats[RTNL_TC_BACKLOG] = q->backlog; g->tc_stats[RTNL_TC_DROPS] = q->drops; g->tc_stats[RTNL_TC_REQUEUES] = q->requeues; g->tc_stats[RTNL_TC_OVERLIMITS] = q->overlimits; } g->ce_mask |= TCA_ATTR_STATS; if (tbs[TCA_STATS_APP]) { g->tc_xstats = nl_data_alloc_attr(tbs[TCA_STATS_APP]); if (g->tc_xstats == NULL) return -NLE_NOMEM; } else goto compat_xstats; } else { if (tb[TCA_STATS]) { struct tc_stats *st = nla_data(tb[TCA_STATS]); g->tc_stats[RTNL_TC_BYTES] = st->bytes; g->tc_stats[RTNL_TC_PACKETS] = st->packets; g->tc_stats[RTNL_TC_RATE_BPS] = st->bps; g->tc_stats[RTNL_TC_RATE_PPS] = st->pps; g->tc_stats[RTNL_TC_QLEN] = st->qlen; g->tc_stats[RTNL_TC_BACKLOG] = st->backlog; g->tc_stats[RTNL_TC_DROPS] = st->drops; g->tc_stats[RTNL_TC_OVERLIMITS] = st->overlimits; g->ce_mask |= TCA_ATTR_STATS; } compat_xstats: if (tb[TCA_XSTATS]) { g->tc_xstats = nl_data_alloc_attr(tb[TCA_XSTATS]); if (g->tc_xstats == NULL) return -NLE_NOMEM; g->ce_mask |= TCA_ATTR_XSTATS; } } return 0; }
int rtnl_tc_msg_parse(struct nlmsghdr *n, struct rtnl_tc *tc) { struct nl_cache *link_cache; struct rtnl_tc_ops *ops; struct nlattr *tb[TCA_MAX + 1]; char kind[TCKINDSIZ]; struct tcmsg *tm; int err; tc->ce_msgtype = n->nlmsg_type; err = nlmsg_parse(n, sizeof(*tm), tb, TCA_MAX, tc_policy); if (err < 0) return err; if (tb[TCA_KIND] == NULL) return -NLE_MISSING_ATTR; nla_strlcpy(kind, tb[TCA_KIND], sizeof(kind)); rtnl_tc_set_kind(tc, kind); tm = nlmsg_data(n); tc->tc_family = tm->tcm_family; tc->tc_ifindex = tm->tcm_ifindex; tc->tc_handle = tm->tcm_handle; tc->tc_parent = tm->tcm_parent; tc->tc_info = tm->tcm_info; tc->ce_mask |= (TCA_ATTR_FAMILY | TCA_ATTR_IFINDEX | TCA_ATTR_HANDLE| TCA_ATTR_PARENT | TCA_ATTR_INFO); if (tb[TCA_OPTIONS]) { tc->tc_opts = nl_data_alloc_attr(tb[TCA_OPTIONS]); if (!tc->tc_opts) return -NLE_NOMEM; tc->ce_mask |= TCA_ATTR_OPTS; } if (tb[TCA_STATS2]) { struct nlattr *tbs[TCA_STATS_MAX + 1]; err = nla_parse_nested(tbs, TCA_STATS_MAX, tb[TCA_STATS2], tc_stats2_policy); if (err < 0) return err; if (tbs[TCA_STATS_BASIC]) { struct gnet_stats_basic *bs; bs = nla_data(tbs[TCA_STATS_BASIC]); tc->tc_stats[RTNL_TC_BYTES] = bs->bytes; tc->tc_stats[RTNL_TC_PACKETS] = bs->packets; } if (tbs[TCA_STATS_RATE_EST]) { struct gnet_stats_rate_est *re; re = nla_data(tbs[TCA_STATS_RATE_EST]); tc->tc_stats[RTNL_TC_RATE_BPS] = re->bps; tc->tc_stats[RTNL_TC_RATE_PPS] = re->pps; } if (tbs[TCA_STATS_QUEUE]) { struct gnet_stats_queue *q; q = nla_data(tbs[TCA_STATS_QUEUE]); tc->tc_stats[RTNL_TC_QLEN] = q->qlen; tc->tc_stats[RTNL_TC_BACKLOG] = q->backlog; tc->tc_stats[RTNL_TC_DROPS] = q->drops; tc->tc_stats[RTNL_TC_REQUEUES] = q->requeues; tc->tc_stats[RTNL_TC_OVERLIMITS] = q->overlimits; } tc->ce_mask |= TCA_ATTR_STATS; if (tbs[TCA_STATS_APP]) { tc->tc_xstats = nl_data_alloc_attr(tbs[TCA_STATS_APP]); if (tc->tc_xstats == NULL) return -NLE_NOMEM; tc->ce_mask |= TCA_ATTR_XSTATS; } else goto compat_xstats; } else { if (tb[TCA_STATS]) { struct tc_stats *st = nla_data(tb[TCA_STATS]); tc->tc_stats[RTNL_TC_BYTES] = st->bytes; tc->tc_stats[RTNL_TC_PACKETS] = st->packets; tc->tc_stats[RTNL_TC_RATE_BPS] = st->bps; tc->tc_stats[RTNL_TC_RATE_PPS] = st->pps; tc->tc_stats[RTNL_TC_QLEN] = st->qlen; tc->tc_stats[RTNL_TC_BACKLOG] = st->backlog; tc->tc_stats[RTNL_TC_DROPS] = st->drops; tc->tc_stats[RTNL_TC_OVERLIMITS]= st->overlimits; tc->ce_mask |= TCA_ATTR_STATS; } compat_xstats: if (tb[TCA_XSTATS]) { tc->tc_xstats = nl_data_alloc_attr(tb[TCA_XSTATS]); if (tc->tc_xstats == NULL) return -NLE_NOMEM; tc->ce_mask |= TCA_ATTR_XSTATS; } } ops = rtnl_tc_get_ops(tc); if (ops && ops->to_msg_parser) { void *data = rtnl_tc_data(tc); if (!data) return -NLE_NOMEM; err = ops->to_msg_parser(tc, data); if (err < 0) return err; } if ((link_cache = __nl_cache_mngt_require("route/link"))) { struct rtnl_link *link; if ((link = rtnl_link_get(link_cache, tc->tc_ifindex))) { rtnl_tc_set_link(tc, link); /* rtnl_tc_set_link incs refcnt */ rtnl_link_put(link); } } return 0; }
int packet_receive_one(struct nlmsghdr *hdr, void *arg) { struct packet_diag_msg *m; struct nlattr *tb[PACKET_DIAG_MAX + 1]; struct packet_sock_desc *sd; m = NLMSG_DATA(hdr); nlmsg_parse(hdr, sizeof(struct packet_diag_msg), tb, PACKET_DIAG_MAX, NULL); pr_info("Collect packet sock %u %u\n", m->pdiag_ino, (unsigned int)m->pdiag_num); if (!tb[PACKET_DIAG_INFO]) { pr_err("No packet sock info in nlm\n"); return -1; } if (!tb[PACKET_DIAG_MCLIST]) { pr_err("No packet sock mclist in nlm\n"); return -1; } sd = xmalloc(sizeof(*sd)); if (!sd) return -1; sd->file_id = 0; sd->type = m->pdiag_type; sd->proto = htons(m->pdiag_num); sd->rx = NULL; sd->tx = NULL; memcpy(&sd->nli, nla_data(tb[PACKET_DIAG_INFO]), sizeof(sd->nli)); if (packet_save_mreqs(sd, tb[PACKET_DIAG_MCLIST])) goto err; if (tb[PACKET_DIAG_FANOUT]) sd->fanout = *(__u32 *)RTA_DATA(tb[PACKET_DIAG_FANOUT]); else sd->fanout = NO_FANOUT; if (tb[PACKET_DIAG_RX_RING]) { sd->rx = xmalloc(sizeof(*sd->rx)); if (sd->rx == NULL) goto err; memcpy(sd->rx, RTA_DATA(tb[PACKET_DIAG_RX_RING]), sizeof(*sd->rx)); } if (tb[PACKET_DIAG_TX_RING]) { sd->tx = xmalloc(sizeof(*sd->tx)); if (sd->tx == NULL) goto err; memcpy(sd->tx, RTA_DATA(tb[PACKET_DIAG_TX_RING]), sizeof(*sd->tx)); } return sk_collect_one(m->pdiag_ino, PF_PACKET, &sd->sd); err: xfree(sd->tx); xfree(sd->rx); xfree(sd); return -1; }
/* Filter by network address */ bool conditional_filter(struct nlmsghdr *nlh) { struct nfgenmsg *msg; msg = (nfgenmsg *)NLMSG_DATA(nlh); if (filter_af != 0 && msg->nfgen_family != filter_af) return false; if (filter == NULL) { return true; } //Root data storage struct nlattr *tb[CTA_MAX + 1]; //Pointer to the current tb being queried struct nlattr ** tb_cur = tb; int err; char* data; bool ret = true; err = nlmsg_parse(nlh, sizeof(struct nfgenmsg), tb, CTA_MAX, NULL); if (err < 0) goto out; //printf("root: %d\n", CTA_MAX + 1); for (int i = 0; i < filter_len; i++) { cr_filter* f = &filter[i]; if (f->key == CTA_UNSPEC) { assert(i != 0); //printf("&&\n"); // && tb_cur = tb; } else if (f->max != 0) { //printf("nested: %d, %d\n", f->key, f->max); err = nla_parse_nested((struct nlattr **)f->internal, f->max, tb_cur[f->key], NULL); if (err < 0) { return true;//error } tb_cur = (nlattr **)f->internal; } else if (f->compare_len != 0) { //printf("compare len: %d\n", f->compare_len); data = (char *)nla_data(tb_cur[f->key]); ret = memcmp(data, f->compare, f->compare_len) == 0; if (!ret) { return ret; } } } out: return ret; }
struct rtnl_addr *rtnl_addr_alloc_from_msg(struct nl_msg *msg) { struct nlattr *tb[IFA_MAX+1]; struct rtnl_addr *addr; struct ifaddrmsg *ifa; struct nlmsghdr *nlh; int err, peer_prefix = 0; nlh = nlmsg_hdr(msg); addr = rtnl_addr_alloc(); if (!addr) goto errout; err = nlmsg_parse(nlh, sizeof(*ifa), tb, IFA_MAX, addr_policy); if (err < 0) goto errout_free; ifa = nlmsg_data(nlh); addr->a_family = ifa->ifa_family; addr->a_prefixlen = ifa->ifa_prefixlen; addr->a_flags = ifa->ifa_flags; addr->a_scope = ifa->ifa_scope; addr->a_ifindex = ifa->ifa_index; addr->a_mask = (ADDR_ATTR_FAMILY | ADDR_ATTR_PREFIXLEN | ADDR_ATTR_FLAGS | ADDR_ATTR_SCOPE | ADDR_ATTR_IFINDEX); if (tb[IFA_LABEL]) { nla_strlcpy(addr->a_label, tb[IFA_LABEL], IFNAMSIZ); addr->a_mask |= ADDR_ATTR_LABEL; } if (tb[IFA_CACHEINFO]) { struct ifa_cacheinfo *ca; ca = nla_data(tb[IFA_CACHEINFO]); addr->a_cacheinfo.aci_prefered = ca->ifa_prefered; addr->a_cacheinfo.aci_valid = ca->ifa_valid; addr->a_cacheinfo.aci_cstamp = ca->cstamp; addr->a_cacheinfo.aci_tstamp = ca->tstamp; addr->a_mask |= ADDR_ATTR_CACHEINFO; } if (tb[IFA_LOCAL]) { addr->a_local = nla_get_addr(tb[IFA_LOCAL], addr->a_family); if (!addr->a_local) goto errout_free; addr->a_mask |= ADDR_ATTR_LOCAL; } if (tb[IFA_ADDRESS]) { struct nl_addr *a; a = nla_get_addr(tb[IFA_ADDRESS], addr->a_family); if (!a) goto errout_free; /* IPv6 sends the local address as IFA_ADDRESS with * no IFA_LOCAL, IPv4 sends both IFA_LOCAL and IFA_ADDRESS * with IFA_ADDRESS being the peer address if they differ */ if (!tb[IFA_LOCAL] || !nl_addr_cmp(a, addr->a_local)) { addr->a_local = a; addr->a_mask |= ADDR_ATTR_LOCAL; } else { addr->a_peer = a; addr->a_mask |= ADDR_ATTR_PEER; peer_prefix = 1; } } nl_addr_set_prefixlen(peer_prefix ? addr->a_peer : addr->a_local, addr->a_prefixlen); if (tb[IFA_BROADCAST]) { addr->a_bcast = nla_get_addr(tb[IFA_BROADCAST], addr->a_family); if (!addr->a_bcast) goto errout_free; addr->a_mask |= ADDR_ATTR_BROADCAST; } if (tb[IFA_ANYCAST]) { addr->a_anycast = nla_get_addr(tb[IFA_ANYCAST], addr->a_family); if (!addr->a_anycast) goto errout_free; addr->a_mask |= ADDR_ATTR_ANYCAST; } if (tb[IFA_MULTICAST]) { addr->a_multicast = nla_get_addr(tb[IFA_MULTICAST], addr->a_family); if (!addr->a_multicast) goto errout_free; addr->a_mask |= ADDR_ATTR_MULTICAST; } return addr; errout_free: rtnl_addr_free(addr); errout: return NULL; }
static int addr_msg_parser(struct sockaddr_nl *who, struct nlmsghdr *nlh, void *arg) { struct rtnl_addr *addr; struct nl_parser_param *pp = arg; struct ifaddrmsg *ifa; struct nlattr *tb[IFA_MAX+1]; int err = -ENOMEM, peer_prefix = 0; addr = rtnl_addr_alloc(); if (!addr) { err = nl_errno(ENOMEM); goto errout; } addr->ce_msgtype = nlh->nlmsg_type; err = nlmsg_parse(nlh, sizeof(*ifa), tb, IFA_MAX, addr_policy); if (err < 0) goto errout_free; ifa = nlmsg_data(nlh); addr->a_family = ifa->ifa_family; addr->a_prefixlen = ifa->ifa_prefixlen; addr->a_flags = ifa->ifa_flags; addr->a_scope = ifa->ifa_scope; addr->a_ifindex = ifa->ifa_index; addr->a_mask = (ADDR_ATTR_FAMILY | ADDR_ATTR_PREFIXLEN | ADDR_ATTR_FLAGS | ADDR_ATTR_SCOPE | ADDR_ATTR_IFINDEX); if (tb[IFA_LABEL]) { nla_strlcpy(addr->a_label, tb[IFA_LABEL], IFNAMSIZ); addr->a_mask |= ADDR_ATTR_LABEL; } if (tb[IFA_CACHEINFO]) { struct ifa_cacheinfo *ca; ca = nla_data(tb[IFA_CACHEINFO]); addr->a_cacheinfo.aci_prefered = ca->ifa_prefered; addr->a_cacheinfo.aci_valid = ca->ifa_valid; addr->a_cacheinfo.aci_cstamp = ca->cstamp; addr->a_cacheinfo.aci_tstamp = ca->tstamp; addr->a_mask |= ADDR_ATTR_CACHEINFO; } if (tb[IFA_LOCAL]) { addr->a_local = nla_get_addr(tb[IFA_LOCAL], addr->a_family); if (!addr->a_local) goto errout_free; addr->a_mask |= ADDR_ATTR_LOCAL; } if (tb[IFA_ADDRESS]) { struct nl_addr *a; a = nla_get_addr(tb[IFA_ADDRESS], addr->a_family); if (!a) goto errout_free; /* IPv6 sends the local address as IFA_ADDRESS with * no IFA_LOCAL, IPv4 sends both IFA_LOCAL and IFA_ADDRESS * with IFA_ADDRESS being the peer address if they differ */ if (!tb[IFA_LOCAL] || !nl_addr_cmp(a, addr->a_local)) { nl_addr_put(addr->a_local); addr->a_local = a; addr->a_mask |= ADDR_ATTR_LOCAL; } else { addr->a_peer = a; addr->a_mask |= ADDR_ATTR_PEER; peer_prefix = 1; } } nl_addr_set_prefixlen(peer_prefix ? addr->a_peer : addr->a_local, addr->a_prefixlen); if (tb[IFA_BROADCAST]) { addr->a_bcast = nla_get_addr(tb[IFA_BROADCAST], addr->a_family); if (!addr->a_bcast) goto errout_free; addr->a_mask |= ADDR_ATTR_BROADCAST; } if (tb[IFA_ANYCAST]) { addr->a_anycast = nla_get_addr(tb[IFA_ANYCAST], addr->a_family); if (!addr->a_anycast) goto errout_free; addr->a_mask |= ADDR_ATTR_ANYCAST; } if (tb[IFA_MULTICAST]) { addr->a_multicast = nla_get_addr(tb[IFA_MULTICAST], addr->a_family); if (!addr->a_multicast) goto errout_free; addr->a_mask |= ADDR_ATTR_MULTICAST; } err = pp->pp_cb((struct nl_object *) addr, pp); if (err < 0) goto errout_free; return P_ACCEPT; errout_free: rtnl_addr_free(addr); errout: return err; }
int nfnlmsg_exp_parse(struct nlmsghdr *nlh, struct nfnl_exp **result) { struct nfnl_exp *exp; struct nlattr *tb[CTA_MAX+1]; int err; exp = nfnl_exp_alloc(); if (!exp) return -NLE_NOMEM; exp->ce_msgtype = nlh->nlmsg_type; err = nlmsg_parse(nlh, sizeof(struct nfgenmsg), tb, CTA_EXPECT_MAX, exp_policy); if (err < 0) goto errout; nfnl_exp_set_family(exp, nfnlmsg_family(nlh)); if (tb[CTA_EXPECT_TUPLE]) { err = exp_parse_tuple(exp, NFNL_EXP_TUPLE_EXPECT, tb[CTA_EXPECT_TUPLE]); if (err < 0) goto errout; } if (tb[CTA_EXPECT_MASTER]) { err = exp_parse_tuple(exp, NFNL_EXP_TUPLE_MASTER, tb[CTA_EXPECT_MASTER]); if (err < 0) goto errout; } if (tb[CTA_EXPECT_MASK]) { err = exp_parse_tuple(exp, NFNL_EXP_TUPLE_MASK, tb[CTA_EXPECT_MASK]); if (err < 0) goto errout; } if (tb[CTA_EXPECT_NAT]) { err = exp_parse_nat(exp, tb[CTA_EXPECT_MASK]); if (err < 0) goto errout; } if (tb[CTA_EXPECT_CLASS]) nfnl_exp_set_class(exp, ntohl(nla_get_u32(tb[CTA_EXPECT_CLASS]))); if (tb[CTA_EXPECT_FN]) nfnl_exp_set_fn(exp, nla_data(tb[CTA_EXPECT_FN])); if (tb[CTA_EXPECT_TIMEOUT]) nfnl_exp_set_timeout(exp, ntohl(nla_get_u32(tb[CTA_EXPECT_TIMEOUT]))); if (tb[CTA_EXPECT_ID]) nfnl_exp_set_id(exp, ntohl(nla_get_u32(tb[CTA_EXPECT_ID]))); if (tb[CTA_EXPECT_HELP_NAME]) nfnl_exp_set_helper_name(exp, nla_data(tb[CTA_EXPECT_HELP_NAME])); if (tb[CTA_EXPECT_ZONE]) nfnl_exp_set_zone(exp, ntohs(nla_get_u16(tb[CTA_EXPECT_ZONE]))); if (tb[CTA_EXPECT_FLAGS]) nfnl_exp_set_flags(exp, ntohl(nla_get_u32(tb[CTA_EXPECT_FLAGS]))); *result = exp; return 0; errout: nfnl_exp_put(exp); return err; }
static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n) { struct net *net = sock_net(skb->sk); struct nlattr *tca[TCA_MAX + 1]; spinlock_t *root_lock; struct tcmsg *t; u32 protocol; u32 prio; u32 nprio; u32 parent; struct net_device *dev; struct Qdisc *q; struct tcf_proto **back, **chain; struct tcf_proto *tp; const struct tcf_proto_ops *tp_ops; const struct Qdisc_class_ops *cops; unsigned long cl; unsigned long fh; int err; int tp_created = 0; if ((n->nlmsg_type != RTM_GETTFILTER) && !netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN)) return -EPERM; replay: err = nlmsg_parse(n, sizeof(*t), tca, TCA_MAX, NULL); if (err < 0) return err; t = nlmsg_data(n); protocol = TC_H_MIN(t->tcm_info); prio = TC_H_MAJ(t->tcm_info); nprio = prio; parent = t->tcm_parent; cl = 0; if (prio == 0) { /* If no priority is given, user wants we allocated it. */ if (n->nlmsg_type != RTM_NEWTFILTER || !(n->nlmsg_flags & NLM_F_CREATE)) return -ENOENT; prio = TC_H_MAKE(0x80000000U, 0U); } /* Find head of filter chain. */ /* Find link */ dev = __dev_get_by_index(net, t->tcm_ifindex); if (dev == NULL) return -ENODEV; /* Find qdisc */ if (!parent) { q = dev->qdisc; parent = q->handle; } else { q = qdisc_lookup(dev, TC_H_MAJ(t->tcm_parent)); if (q == NULL) return -EINVAL; } /* Is it classful? */ cops = q->ops->cl_ops; if (!cops) return -EINVAL; if (cops->tcf_chain == NULL) return -EOPNOTSUPP; /* Do we search for filter, attached to class? */ if (TC_H_MIN(parent)) { cl = cops->get(q, parent); if (cl == 0) return -ENOENT; } /* And the last stroke */ chain = cops->tcf_chain(q, cl); err = -EINVAL; if (chain == NULL) goto errout; /* Check the chain for existence of proto-tcf with this priority */ for (back = chain; (tp = *back) != NULL; back = &tp->next) { if (tp->prio >= prio) { if (tp->prio == prio) { if (!nprio || (tp->protocol != protocol && protocol)) goto errout; } else tp = NULL; break; } } root_lock = qdisc_root_sleeping_lock(q); if (tp == NULL) { /* Proto-tcf does not exist, create new one */ if (tca[TCA_KIND] == NULL || !protocol) goto errout; err = -ENOENT; if (n->nlmsg_type != RTM_NEWTFILTER || !(n->nlmsg_flags & NLM_F_CREATE)) goto errout; /* Create new proto tcf */ err = -ENOBUFS; tp = kzalloc(sizeof(*tp), GFP_KERNEL); if (tp == NULL) goto errout; err = -ENOENT; tp_ops = tcf_proto_lookup_ops(tca[TCA_KIND]); if (tp_ops == NULL) { #ifdef CONFIG_MODULES struct nlattr *kind = tca[TCA_KIND]; char name[IFNAMSIZ]; if (kind != NULL && nla_strlcpy(name, kind, IFNAMSIZ) < IFNAMSIZ) { rtnl_unlock(); request_module("cls_%s", name); rtnl_lock(); tp_ops = tcf_proto_lookup_ops(kind); /* We dropped the RTNL semaphore in order to * perform the module load. So, even if we * succeeded in loading the module we have to * replay the request. We indicate this using * -EAGAIN. */ if (tp_ops != NULL) { module_put(tp_ops->owner); err = -EAGAIN; } } #endif kfree(tp); goto errout; } tp->ops = tp_ops; tp->protocol = protocol; tp->prio = nprio ? : TC_H_MAJ(tcf_auto_prio(*back)); tp->q = q; tp->classify = tp_ops->classify; tp->classid = parent; err = tp_ops->init(tp); if (err != 0) { module_put(tp_ops->owner); kfree(tp); goto errout; } tp_created = 1; } else if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], tp->ops->kind))
/** * virNetlinkCommand: * @nlmsg: pointer to netlink message * @respbuf: pointer to pointer where response buffer will be allocated * @respbuflen: pointer to integer holding the size of the response buffer * on return of the function. * @src_pid: the pid of the process to send a message * @dst_pid: the pid of the process to talk to, i.e., pid = 0 for kernel * @protocol: netlink protocol * @groups: the group identifier * * Send the given message to the netlink layer and receive response. * Returns 0 on success, -1 on error. In case of error, no response * buffer will be returned. */ int virNetlinkCommand(struct nl_msg *nl_msg, struct nlmsghdr **resp, unsigned int *respbuflen, uint32_t src_pid, uint32_t dst_pid, unsigned int protocol, unsigned int groups) { int ret = -1; struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK, .nl_pid = dst_pid, .nl_groups = 0, }; ssize_t nbytes; struct pollfd fds[1]; int fd; int n; struct nlmsghdr *nlmsg = nlmsg_hdr(nl_msg); virNetlinkHandle *nlhandle = NULL; int len = 0; if (protocol >= MAX_LINKS) { virReportSystemError(EINVAL, _("invalid protocol argument: %d"), protocol); goto cleanup; } if (!(nlhandle = virNetlinkCreateSocket(protocol))) goto cleanup; fd = nl_socket_get_fd(nlhandle); if (fd < 0) { virReportSystemError(errno, "%s", _("cannot get netlink socket fd")); goto cleanup; } if (groups && nl_socket_add_membership(nlhandle, groups) < 0) { virReportSystemError(errno, "%s", _("cannot add netlink membership")); goto cleanup; } nlmsg_set_dst(nl_msg, &nladdr); nlmsg->nlmsg_pid = src_pid ? src_pid : getpid(); nbytes = nl_send_auto_complete(nlhandle, nl_msg); if (nbytes < 0) { virReportSystemError(errno, "%s", _("cannot send to netlink socket")); goto cleanup; } memset(fds, 0, sizeof(fds)); fds[0].fd = fd; fds[0].events = POLLIN; n = poll(fds, ARRAY_CARDINALITY(fds), NETLINK_ACK_TIMEOUT_S); if (n <= 0) { if (n < 0) virReportSystemError(errno, "%s", _("error in poll call")); if (n == 0) virReportSystemError(ETIMEDOUT, "%s", _("no valid netlink response was received")); goto cleanup; } len = nl_recv(nlhandle, &nladdr, (unsigned char **)resp, NULL); if (len == 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nl_recv failed - returned 0 bytes")); goto cleanup; } if (len < 0) { virReportSystemError(errno, "%s", _("nl_recv failed")); goto cleanup; } ret = 0; *respbuflen = len; cleanup: if (ret < 0) { *resp = NULL; *respbuflen = 0; } virNetlinkFree(nlhandle); return ret; } /** * virNetlinkDumpLink: * * @ifname: The name of the interface; only use if ifindex <= 0 * @ifindex: The interface index; may be <= 0 if ifname is given * @data: Gets a pointer to the raw data from netlink. MUST BE FREED BY CALLER! * @nlattr: Pointer to a pointer of netlink attributes that will contain * the results * @src_pid: pid used for nl_pid of the local end of the netlink message * (0 == "use getpid()") * @dst_pid: pid of destination nl_pid if the kernel * is not the target of the netlink message but it is to be * sent to another process (0 if sending to the kernel) * * Get information from netlink about an interface given its name or index. * * Returns 0 on success, -1 on fatal error. */ int virNetlinkDumpLink(const char *ifname, int ifindex, void **nlData, struct nlattr **tb, uint32_t src_pid, uint32_t dst_pid) { int rc = -1; struct nlmsghdr *resp = NULL; struct nlmsgerr *err; struct ifinfomsg ifinfo = { .ifi_family = AF_UNSPEC, .ifi_index = ifindex }; unsigned int recvbuflen; struct nl_msg *nl_msg; if (ifname && ifindex <= 0 && virNetDevGetIndex(ifname, &ifindex) < 0) return -1; ifinfo.ifi_index = ifindex; nl_msg = nlmsg_alloc_simple(RTM_GETLINK, NLM_F_REQUEST); if (!nl_msg) { virReportOOMError(); return -1; } if (nlmsg_append(nl_msg, &ifinfo, sizeof(ifinfo), NLMSG_ALIGNTO) < 0) goto buffer_too_small; if (ifname) { if (nla_put(nl_msg, IFLA_IFNAME, strlen(ifname)+1, ifname) < 0) goto buffer_too_small; } # ifdef RTEXT_FILTER_VF /* if this filter exists in the kernel's netlink implementation, * we need to set it, otherwise the response message will not * contain the IFLA_VFINFO_LIST that we're looking for. */ { uint32_t ifla_ext_mask = RTEXT_FILTER_VF; if (nla_put(nl_msg, IFLA_EXT_MASK, sizeof(ifla_ext_mask), &ifla_ext_mask) < 0) { goto buffer_too_small; } } # endif if (virNetlinkCommand(nl_msg, &resp, &recvbuflen, src_pid, dst_pid, NETLINK_ROUTE, 0) < 0) goto cleanup; if (recvbuflen < NLMSG_LENGTH(0) || resp == NULL) goto malformed_resp; switch (resp->nlmsg_type) { case NLMSG_ERROR: err = (struct nlmsgerr *)NLMSG_DATA(resp); if (resp->nlmsg_len < NLMSG_LENGTH(sizeof(*err))) goto malformed_resp; if (err->error) { virReportSystemError(-err->error, _("error dumping %s (%d) interface"), ifname, ifindex); goto cleanup; } break; case GENL_ID_CTRL: case NLMSG_DONE: rc = nlmsg_parse(resp, sizeof(struct ifinfomsg), tb, IFLA_MAX, NULL); if (rc < 0) goto malformed_resp; break; default: goto malformed_resp; } rc = 0; cleanup: nlmsg_free(nl_msg); if (rc < 0) VIR_FREE(resp); *nlData = resp; return rc; malformed_resp: virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("malformed netlink response message")); goto cleanup; buffer_too_small: virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("allocated netlink buffer is too small")); goto cleanup; }
/* Extract a field */ bool cr_extract_field(cr_filter* filter, int filter_len, struct nlmsghdr *nlh, void* output, int output_len) { struct nfgenmsg *msg; msg = (nfgenmsg *)NLMSG_DATA(nlh); //Root data storage struct nlattr *tb[CTA_MAX + 1]; struct nlattr ** tb_buf; //Pointer to the current tb being queried struct nlattr ** tb_cur = tb; int err; char* data; err = nlmsg_parse(nlh, sizeof(struct nfgenmsg), tb, CTA_MAX, NULL); if (err < 0) return false; for (int i = 0; i < filter_len; i++) { cr_filter* f = &filter[i]; if (f->max != 0) { if (tb_cur[f->key] == NULL) { goto free_err; } tb_buf = (struct nlattr **)malloc(sizeof(struct nlattr *) * (f->max + 1)); err = nla_parse_nested(tb_buf, f->max, tb_cur[f->key], NULL); if (err < 0) { goto free_err; } if (tb_cur != tb) { free(tb_cur); } tb_cur = tb_buf; } else { //printf("compare len: %d\n", f->compare_len); data = (char *)nla_data(tb_cur[f->key]); if (data == NULL) { goto free_err; } memcpy(output, data, output_len); if (tb_cur != tb) { free(tb_cur); } return true; } } free_err: if (tb_cur != tb) { free(tb_cur); } return false; }
int nfnlmsg_ct_parse(struct nlmsghdr *nlh, struct nfnl_ct **result) { struct nfnl_ct *ct; struct nlattr *tb[CTA_MAX+1]; int err; ct = nfnl_ct_alloc(); if (!ct) return -NLE_NOMEM; ct->ce_msgtype = nlh->nlmsg_type; err = nlmsg_parse(nlh, sizeof(struct nfgenmsg), tb, CTA_MAX, ct_policy); if (err < 0) goto errout; nfnl_ct_set_family(ct, nfnlmsg_family(nlh)); if (tb[CTA_TUPLE_ORIG]) { err = ct_parse_tuple(ct, 0, tb[CTA_TUPLE_ORIG]); if (err < 0) goto errout; } if (tb[CTA_TUPLE_REPLY]) { err = ct_parse_tuple(ct, 1, tb[CTA_TUPLE_REPLY]); if (err < 0) goto errout; } if (tb[CTA_PROTOINFO]) { err = ct_parse_protoinfo(ct, tb[CTA_PROTOINFO]); if (err < 0) goto errout; } if (tb[CTA_STATUS]) nfnl_ct_set_status(ct, ntohl(nla_get_u32(tb[CTA_STATUS]))); if (tb[CTA_TIMEOUT]) nfnl_ct_set_timeout(ct, ntohl(nla_get_u32(tb[CTA_TIMEOUT]))); if (tb[CTA_MARK]) nfnl_ct_set_mark(ct, ntohl(nla_get_u32(tb[CTA_MARK]))); if (tb[CTA_USE]) nfnl_ct_set_use(ct, ntohl(nla_get_u32(tb[CTA_USE]))); if (tb[CTA_ID]) nfnl_ct_set_id(ct, ntohl(nla_get_u32(tb[CTA_ID]))); if (tb[CTA_ZONE]) nfnl_ct_set_zone(ct, ntohs(nla_get_u16(tb[CTA_ZONE]))); if (tb[CTA_COUNTERS_ORIG]) { err = ct_parse_counters(ct, 0, tb[CTA_COUNTERS_ORIG]); if (err < 0) goto errout; } if (tb[CTA_COUNTERS_REPLY]) { err = ct_parse_counters(ct, 1, tb[CTA_COUNTERS_REPLY]); if (err < 0) goto errout; } if (tb[CTA_TIMESTAMP]) { err = ct_parse_timestamp(ct, tb[CTA_TIMESTAMP]); if (err < 0) goto errout; } *result = ct; return 0; errout: nfnl_ct_put(ct); return err; }
static void copy_cacheinfo_into_route(struct rta_cacheinfo *ci, struct rtnl_route *route) { struct rtnl_rtcacheinfo nci = { .rtci_clntref = ci->rta_clntref, .rtci_last_use = ci->rta_lastuse, .rtci_expires = ci->rta_expires, .rtci_error = ci->rta_error, .rtci_used = ci->rta_used, .rtci_id = ci->rta_id, .rtci_ts = ci->rta_ts, .rtci_tsage = ci->rta_tsage, }; rtnl_route_set_cacheinfo(route, &nci); } static int route_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, struct nlmsghdr *nlh, struct nl_parser_param *pp) { struct rtmsg *rtm; struct rtnl_route *route; struct nlattr *tb[RTA_MAX + 1]; struct nl_addr *src = NULL, *dst = NULL, *addr; int err; route = rtnl_route_alloc(); if (!route) { err = nl_errno(ENOMEM); goto errout; } route->ce_msgtype = nlh->nlmsg_type; err = nlmsg_parse(nlh, sizeof(struct rtmsg), tb, RTA_MAX, route_policy); if (err < 0) goto errout; rtm = nlmsg_data(nlh); rtnl_route_set_family(route, rtm->rtm_family); rtnl_route_set_tos(route, rtm->rtm_tos); rtnl_route_set_table(route, rtm->rtm_table); rtnl_route_set_type(route, rtm->rtm_type); rtnl_route_set_scope(route, rtm->rtm_scope); rtnl_route_set_protocol(route, rtm->rtm_protocol); rtnl_route_set_flags(route, rtm->rtm_flags); if (tb[RTA_DST]) { dst = nla_get_addr(tb[RTA_DST], rtm->rtm_family); if (dst == NULL) goto errout_errno; } else { dst = nl_addr_alloc(0); nl_addr_set_family(dst, rtm->rtm_family); } nl_addr_set_prefixlen(dst, rtm->rtm_dst_len); err = rtnl_route_set_dst(route, dst); if (err < 0) goto errout; nl_addr_put(dst); if (tb[RTA_SRC]) { src = nla_get_addr(tb[RTA_SRC], rtm->rtm_family); if (src == NULL) goto errout_errno; } else if (rtm->rtm_src_len) src = nl_addr_alloc(0); if (src) { nl_addr_set_prefixlen(src, rtm->rtm_src_len); rtnl_route_set_src(route, src); nl_addr_put(src); } if (tb[RTA_IIF]) rtnl_route_set_iif(route, nla_get_string(tb[RTA_IIF])); if (tb[RTA_OIF]) rtnl_route_set_oif(route, nla_get_u32(tb[RTA_OIF])); if (tb[RTA_GATEWAY]) { addr = nla_get_addr(tb[RTA_GATEWAY], route->rt_family); if (addr == NULL) goto errout_errno; rtnl_route_set_gateway(route, addr); nl_addr_put(addr); } if (tb[RTA_PRIORITY]) rtnl_route_set_prio(route, nla_get_u32(tb[RTA_PRIORITY])); if (tb[RTA_PREFSRC]) { addr = nla_get_addr(tb[RTA_PREFSRC], route->rt_family); if (addr == NULL) goto errout_errno; rtnl_route_set_pref_src(route, addr); nl_addr_put(addr); } if (tb[RTA_METRICS]) { struct nlattr *mtb[RTAX_MAX + 1]; int i; err = nla_parse_nested(mtb, RTAX_MAX, tb[RTA_METRICS], NULL); if (err < 0) goto errout; for (i = 1; i <= RTAX_MAX; i++) { if (mtb[i] && nla_len(mtb[i]) >= sizeof(uint32_t)) { uint32_t m = nla_get_u32(mtb[i]); if (rtnl_route_set_metric(route, i, m) < 0) goto errout_errno; } } } if (tb[RTA_MULTIPATH]) { struct rtnl_nexthop *nh; struct rtnexthop *rtnh = nla_data(tb[RTA_MULTIPATH]); size_t tlen = nla_len(tb[RTA_MULTIPATH]); while (tlen >= sizeof(*rtnh) && tlen >= rtnh->rtnh_len) { nh = rtnl_route_nh_alloc(); if (!nh) goto errout; rtnl_route_nh_set_weight(nh, rtnh->rtnh_hops); rtnl_route_nh_set_ifindex(nh, rtnh->rtnh_ifindex); rtnl_route_nh_set_flags(nh, rtnh->rtnh_flags); if (rtnh->rtnh_len > sizeof(*rtnh)) { struct nlattr *ntb[RTA_MAX + 1]; nla_parse(ntb, RTA_MAX, (struct nlattr *) RTNH_DATA(rtnh), rtnh->rtnh_len - sizeof(*rtnh), route_policy); if (ntb[RTA_GATEWAY]) { nh->rtnh_gateway = nla_get_addr( ntb[RTA_GATEWAY], route->rt_family); nh->rtnh_mask = NEXTHOP_HAS_GATEWAY; } } rtnl_route_add_nexthop(route, nh); tlen -= RTNH_ALIGN(rtnh->rtnh_len); rtnh = RTNH_NEXT(rtnh); } } if (tb[RTA_FLOW]) rtnl_route_set_realms(route, nla_get_u32(tb[RTA_FLOW])); if (tb[RTA_CACHEINFO]) copy_cacheinfo_into_route(nla_data(tb[RTA_CACHEINFO]), route); if (tb[RTA_MP_ALGO]) rtnl_route_set_mp_algo(route, nla_get_u32(tb[RTA_MP_ALGO])); err = pp->pp_cb((struct nl_object *) route, pp); if (err < 0) goto errout; err = P_ACCEPT; errout: rtnl_route_put(route); return err; errout_errno: err = nl_get_errno(); goto errout; } static int route_request_update(struct nl_cache *c, struct nl_handle *h) { return nl_rtgen_request(h, RTM_GETROUTE, AF_UNSPEC, NLM_F_DUMP); } /** * @name Cache Management * @{ */ /** * Build a route cache holding all routes currently configured in the kernel * @arg handle netlink handle * * Allocates a new cache, initializes it properly and updates it to * contain all routes currently configured in the kernel. * * @note The caller is responsible for destroying and freeing the * cache after using it. * @return The cache or NULL if an error has occured. */ struct nl_cache *rtnl_route_alloc_cache(struct nl_handle *handle) { struct nl_cache *cache; cache = nl_cache_alloc(&rtnl_route_ops); if (!cache) return NULL; if (handle && nl_cache_refill(handle, cache) < 0) { free(cache); return NULL; } return cache; } /** @} */ /** * @name Route Addition * @{ */ static struct nl_msg *build_route_msg(struct rtnl_route *tmpl, int cmd, int flags) { struct nl_msg *msg; struct nl_addr *addr; int scope, i, oif, nmetrics = 0; struct nlattr *metrics; struct rtmsg rtmsg = { .rtm_family = rtnl_route_get_family(tmpl), .rtm_dst_len = rtnl_route_get_dst_len(tmpl), .rtm_src_len = rtnl_route_get_src_len(tmpl), .rtm_tos = rtnl_route_get_tos(tmpl), .rtm_table = rtnl_route_get_table(tmpl), .rtm_type = rtnl_route_get_type(tmpl), .rtm_protocol = rtnl_route_get_protocol(tmpl), .rtm_flags = rtnl_route_get_flags(tmpl), }; if (rtmsg.rtm_family == AF_UNSPEC) { nl_error(EINVAL, "Cannot build route message, address " \ "family is unknown."); return NULL; } scope = rtnl_route_get_scope(tmpl); if (scope == RT_SCOPE_NOWHERE) { if (rtmsg.rtm_type == RTN_LOCAL) scope = RT_SCOPE_HOST; else { /* XXX Change to UNIVERSE if gw || nexthops */ scope = RT_SCOPE_LINK; } } rtmsg.rtm_scope = scope; msg = nlmsg_alloc_simple(cmd, flags); if (msg == NULL) return NULL; if (nlmsg_append(msg, &rtmsg, sizeof(rtmsg), NLMSG_ALIGNTO) < 0) goto nla_put_failure; addr = rtnl_route_get_dst(tmpl); if (addr) NLA_PUT_ADDR(msg, RTA_DST, addr); addr = rtnl_route_get_src(tmpl); if (addr) NLA_PUT_ADDR(msg, RTA_SRC, addr); addr = rtnl_route_get_gateway(tmpl); if (addr) NLA_PUT_ADDR(msg, RTA_GATEWAY, addr); addr = rtnl_route_get_pref_src(tmpl); if (addr) NLA_PUT_ADDR(msg, RTA_PREFSRC, addr); NLA_PUT_U32(msg, RTA_PRIORITY, rtnl_route_get_prio(tmpl)); oif = rtnl_route_get_oif(tmpl); if (oif != RTNL_LINK_NOT_FOUND) NLA_PUT_U32(msg, RTA_OIF, oif); for (i = 1; i <= RTAX_MAX; i++) if (rtnl_route_get_metric(tmpl, i) != UINT_MAX) nmetrics++; if (nmetrics > 0) { unsigned int val; metrics = nla_nest_start(msg, RTA_METRICS); if (metrics == NULL) goto nla_put_failure; for (i = 1; i <= RTAX_MAX; i++) { val = rtnl_route_get_metric(tmpl, i); if (val != UINT_MAX) NLA_PUT_U32(msg, i, val); } nla_nest_end(msg, metrics); } #if 0 RTA_IIF, RTA_MULTIPATH, RTA_PROTOINFO, RTA_FLOW, RTA_CACHEINFO, RTA_SESSION, RTA_MP_ALGO, #endif return msg; nla_put_failure: nlmsg_free(msg); return NULL; } struct nl_msg *rtnl_route_build_add_request(struct rtnl_route *tmpl, int flags) { return build_route_msg(tmpl, RTM_NEWROUTE, NLM_F_CREATE | flags); } int rtnl_route_add(struct nl_handle *handle, struct rtnl_route *route, int flags) { struct nl_msg *msg; int err; msg = rtnl_route_build_add_request(route, flags); if (!msg) return nl_get_errno(); err = nl_send_auto_complete(handle, msg); nlmsg_free(msg); if (err < 0) return err; return nl_wait_for_ack(handle); } struct nl_msg *rtnl_route_build_del_request(struct rtnl_route *tmpl, int flags) { return build_route_msg(tmpl, RTM_DELROUTE, flags); } int rtnl_route_del(struct nl_handle *handle, struct rtnl_route *route, int flags) { struct nl_msg *msg; int err; msg = rtnl_route_build_del_request(route, flags); if (!msg) return nl_get_errno(); err = nl_send_auto_complete(handle, msg); nlmsg_free(msg); if (err < 0) return err; return nl_wait_for_ack(handle); } /** @} */ static struct nl_af_group route_groups[] = { { AF_INET, RTNLGRP_IPV4_ROUTE }, { AF_INET6, RTNLGRP_IPV6_ROUTE }, { AF_DECnet, RTNLGRP_DECnet_ROUTE }, { END_OF_GROUP_LIST }, }; static struct nl_cache_ops rtnl_route_ops = { .co_name = "route/route", .co_hdrsize = sizeof(struct rtmsg), .co_msgtypes = { { RTM_NEWROUTE, NL_ACT_NEW, "new" }, { RTM_DELROUTE, NL_ACT_DEL, "del" }, { RTM_GETROUTE, NL_ACT_GET, "get" }, END_OF_MSGTYPES_LIST, }, .co_protocol = NETLINK_ROUTE, .co_groups = route_groups, .co_request_update = route_request_update, .co_msg_parser = route_msg_parser, .co_obj_ops = &route_obj_ops, }; static void __init route_init(void) { nl_cache_mngt_register(&rtnl_route_ops); } static void __exit route_exit(void) { nl_cache_mngt_unregister(&rtnl_route_ops); }
static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { struct ifinfomsg *ifm; struct net_device *dev; int err, send_addr_notify = 0, modified = 0; struct nlattr *tb[IFLA_MAX+1]; char ifname[IFNAMSIZ]; err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy); if (err < 0) goto errout; if (tb[IFLA_IFNAME]) nla_strlcpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ); else ifname[0] = '\0'; err = -EINVAL; ifm = nlmsg_data(nlh); if (ifm->ifi_index > 0) dev = dev_get_by_index(ifm->ifi_index); else if (tb[IFLA_IFNAME]) dev = dev_get_by_name(ifname); else goto errout; if (dev == NULL) { err = -ENODEV; goto errout; } if (tb[IFLA_ADDRESS] && nla_len(tb[IFLA_ADDRESS]) < dev->addr_len) goto errout_dev; if (tb[IFLA_BROADCAST] && nla_len(tb[IFLA_BROADCAST]) < dev->addr_len) goto errout_dev; if (tb[IFLA_MAP]) { struct rtnl_link_ifmap *u_map; struct ifmap k_map; if (!dev->set_config) { err = -EOPNOTSUPP; goto errout_dev; } if (!netif_device_present(dev)) { err = -ENODEV; goto errout_dev; } u_map = nla_data(tb[IFLA_MAP]); k_map.mem_start = (unsigned long) u_map->mem_start; k_map.mem_end = (unsigned long) u_map->mem_end; k_map.base_addr = (unsigned short) u_map->base_addr; k_map.irq = (unsigned char) u_map->irq; k_map.dma = (unsigned char) u_map->dma; k_map.port = (unsigned char) u_map->port; err = dev->set_config(dev, &k_map); if (err < 0) goto errout_dev; modified = 1; } if (tb[IFLA_ADDRESS]) { struct sockaddr *sa; int len; if (!dev->set_mac_address) { err = -EOPNOTSUPP; goto errout_dev; } if (!netif_device_present(dev)) { err = -ENODEV; goto errout_dev; } len = sizeof(sa_family_t) + dev->addr_len; sa = kmalloc(len, GFP_KERNEL); if (!sa) { err = -ENOMEM; goto errout_dev; } sa->sa_family = dev->type; memcpy(sa->sa_data, nla_data(tb[IFLA_ADDRESS]), dev->addr_len); err = dev->set_mac_address(dev, sa); kfree(sa); if (err) goto errout_dev; send_addr_notify = 1; modified = 1; } if (tb[IFLA_MTU]) { err = dev_set_mtu(dev, nla_get_u32(tb[IFLA_MTU])); if (err < 0) goto errout_dev; modified = 1; } /* * Interface selected by interface index but interface * name provided implies that a name change has been * requested. */ if (ifm->ifi_index > 0 && ifname[0]) { err = dev_change_name(dev, ifname); if (err < 0) goto errout_dev; modified = 1; } if (tb[IFLA_BROADCAST]) { nla_memcpy(dev->broadcast, tb[IFLA_BROADCAST], dev->addr_len); send_addr_notify = 1; } if (ifm->ifi_flags || ifm->ifi_change) { unsigned int flags = ifm->ifi_flags; /* bugwards compatibility: ifi_change == 0 is treated as ~0 */ if (ifm->ifi_change) flags = (flags & ifm->ifi_change) | (dev->flags & ~ifm->ifi_change); dev_change_flags(dev, flags); } if (tb[IFLA_TXQLEN]) dev->tx_queue_len = nla_get_u32(tb[IFLA_TXQLEN]); if (tb[IFLA_WEIGHT]) dev->weight = nla_get_u32(tb[IFLA_WEIGHT]); if (tb[IFLA_OPERSTATE]) set_operstate(dev, nla_get_u8(tb[IFLA_OPERSTATE])); if (tb[IFLA_LINKMODE]) { write_lock_bh(&dev_base_lock); dev->link_mode = nla_get_u8(tb[IFLA_LINKMODE]); write_unlock_bh(&dev_base_lock); } err = 0; errout_dev: if (err < 0 && modified && net_ratelimit()) printk(KERN_WARNING "A link change request failed with " "some changes comitted already. Interface %s may " "have been left with an inconsistent configuration, " "please check.\n", dev->name); if (send_addr_notify) call_netdevice_notifiers(NETDEV_CHANGEADDR, dev); dev_put(dev); errout: return err; }
static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh) { struct nlattr *tb[IFA_MAX+1]; struct in_ifaddr *ifa; struct ifaddrmsg *ifm; struct net_device *dev; struct in_device *in_dev; int err; err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy); if (err < 0) goto errout; ifm = nlmsg_data(nlh); err = -EINVAL; if (ifm->ifa_prefixlen > 32 || tb[IFA_LOCAL] == NULL) goto errout; dev = __dev_get_by_index(net, ifm->ifa_index); err = -ENODEV; if (dev == NULL) goto errout; in_dev = __in_dev_get_rtnl(dev); err = -ENOBUFS; if (in_dev == NULL) goto errout; ifa = inet_alloc_ifa(); if (ifa == NULL) /* * A potential indev allocation can be left alive, it stays * assigned to its device and is destroy with it. */ goto errout; ipv4_devconf_setall(in_dev); in_dev_hold(in_dev); if (tb[IFA_ADDRESS] == NULL) tb[IFA_ADDRESS] = tb[IFA_LOCAL]; ifa->ifa_prefixlen = ifm->ifa_prefixlen; ifa->ifa_mask = inet_make_mask(ifm->ifa_prefixlen); ifa->ifa_flags = ifm->ifa_flags; ifa->ifa_scope = ifm->ifa_scope; ifa->ifa_dev = in_dev; ifa->ifa_local = nla_get_be32(tb[IFA_LOCAL]); ifa->ifa_address = nla_get_be32(tb[IFA_ADDRESS]); if (tb[IFA_BROADCAST]) ifa->ifa_broadcast = nla_get_be32(tb[IFA_BROADCAST]); if (tb[IFA_LABEL]) nla_strlcpy(ifa->ifa_label, tb[IFA_LABEL], IFNAMSIZ); else memcpy(ifa->ifa_label, dev->name, IFNAMSIZ); return ifa; errout: return ERR_PTR(err); }
static int rule_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, struct nlmsghdr *n, struct nl_parser_param *pp) { struct rtnl_rule *rule; struct rtmsg *r; struct nlattr *tb[RTA_MAX+1]; int err = 1, family; rule = rtnl_rule_alloc(); if (!rule) { err = -NLE_NOMEM; goto errout; } rule->ce_msgtype = n->nlmsg_type; r = nlmsg_data(n); err = nlmsg_parse(n, sizeof(*r), tb, RTA_MAX, rule_policy); if (err < 0) goto errout; rule->r_family = family = r->rtm_family; rule->r_type = r->rtm_type; rule->r_dsfield = r->rtm_tos; rule->r_src_len = r->rtm_src_len; rule->r_dst_len = r->rtm_dst_len; rule->r_table = r->rtm_table; rule->ce_mask = (RULE_ATTR_FAMILY | RULE_ATTR_TYPE | RULE_ATTR_DSFIELD | RULE_ATTR_SRC_LEN | RULE_ATTR_DST_LEN |RULE_ATTR_TYPE | RULE_ATTR_TABLE); if (tb[RTA_PRIORITY]) { rule->r_prio = nla_get_u32(tb[RTA_PRIORITY]); rule->ce_mask |= RULE_ATTR_PRIO; } if (tb[RTA_SRC]) { if (!(rule->r_src = nl_addr_alloc_attr(tb[RTA_SRC], family))) goto errout_enomem; nl_addr_set_prefixlen(rule->r_src, r->rtm_src_len); rule->ce_mask |= RULE_ATTR_SRC; } if (tb[RTA_DST]) { if (!(rule->r_dst = nl_addr_alloc_attr(tb[RTA_DST], family))) goto errout_enomem; nl_addr_set_prefixlen(rule->r_dst, r->rtm_dst_len); rule->ce_mask |= RULE_ATTR_DST; } if (tb[RTA_PROTOINFO]) { rule->r_mark = nla_get_u32(tb[RTA_PROTOINFO]); rule->ce_mask |= RULE_ATTR_MARK; } if (tb[RTA_IIF]) { nla_strlcpy(rule->r_iif, tb[RTA_IIF], IFNAMSIZ); rule->ce_mask |= RULE_ATTR_IIF; } if (tb[RTA_FLOW]) { rule->r_realms = nla_get_u32(tb[RTA_FLOW]); rule->ce_mask |= RULE_ATTR_REALMS; } if (tb[RTA_GATEWAY]) { rule->r_srcmap = nl_addr_alloc_attr(tb[RTA_GATEWAY], family); if (!rule->r_srcmap) goto errout_enomem; rule->ce_mask |= RULE_ATTR_SRCMAP; } if (tb[RTA_TABLE]) { rule->r_table = nla_get_u32(tb[RTA_TABLE]); rule->ce_mask |= RULE_ATTR_TABLE; } err = pp->pp_cb((struct nl_object *) rule, pp); errout: rtnl_rule_put(rule); return err; errout_enomem: err = -NLE_NOMEM; goto errout; }