static void ipmr_cache_resolve(struct mfc_cache *uc, struct mfc_cache *c) { struct sk_buff *skb; struct nlmsgerr *e; /* * Play the pending entries through our router */ while ((skb = __skb_dequeue(&uc->mfc_un.unres.unresolved))) { if (ip_hdr(skb)->version == 0) { struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct iphdr)); if (ipmr_fill_mroute(skb, c, NLMSG_DATA(nlh)) > 0) { nlh->nlmsg_len = (skb_tail_pointer(skb) - (u8 *)nlh); } else { nlh->nlmsg_type = NLMSG_ERROR; nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr)); skb_trim(skb, nlh->nlmsg_len); e = NLMSG_DATA(nlh); e->error = -EMSGSIZE; memset(&e->msg, 0, sizeof(e->msg)); } rtnl_unicast(skb, mfc_net(c), NETLINK_CB(skb).pid); } else ip_mr_forward(skb, c, 0); } }
static void ipmr_destroy_unres(struct mfc_cache *c) { struct sk_buff *skb; struct nlmsgerr *e; struct net *net = mfc_net(c); atomic_dec(&net->ipv4.cache_resolve_queue_len); while ((skb = skb_dequeue(&c->mfc_un.unres.unresolved))) { if (ip_hdr(skb)->version == 0) { struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct iphdr)); nlh->nlmsg_type = NLMSG_ERROR; nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr)); skb_trim(skb, nlh->nlmsg_len); e = NLMSG_DATA(nlh); e->error = -ETIMEDOUT; memset(&e->msg, 0, sizeof(e->msg)); rtnl_unicast(skb, net, NETLINK_CB(skb).pid); } else kfree_skb(skb); } ipmr_cache_free(c); }
/* standard netlink reply call */ static int dcbnl_reply(u8 value, u8 event, u8 cmd, u8 attr, u32 pid, u32 seq, u16 flags) { struct sk_buff *dcbnl_skb; struct dcbmsg *dcb; struct nlmsghdr *nlh; int ret = -EINVAL; dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!dcbnl_skb) return ret; nlh = NLMSG_NEW(dcbnl_skb, pid, seq, event, sizeof(*dcb), flags); dcb = NLMSG_DATA(nlh); dcb->dcb_family = AF_UNSPEC; dcb->cmd = cmd; dcb->dcb_pad = 0; ret = nla_put_u8(dcbnl_skb, attr, value); if (ret) goto err; /* end the message, assign the nlmsg_len. */ nlmsg_end(dcbnl_skb, nlh); ret = rtnl_unicast(dcbnl_skb, &init_net, pid); if (ret) return -EINVAL; return 0; nlmsg_failure: err: kfree_skb(dcbnl_skb); return ret; }
static void ip6mr_cache_resolve(struct mfc6_cache *uc, struct mfc6_cache *c) { struct sk_buff *skb; /* * Play the pending entries through our router */ while((skb = __skb_dequeue(&uc->mfc_un.unres.unresolved))) { if (ipv6_hdr(skb)->version == 0) { int err; struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct ipv6hdr)); if (ip6mr_fill_mroute(skb, c, NLMSG_DATA(nlh)) > 0) { nlh->nlmsg_len = skb_tail_pointer(skb) - (u8 *)nlh; } else { nlh->nlmsg_type = NLMSG_ERROR; nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr)); skb_trim(skb, nlh->nlmsg_len); ((struct nlmsgerr *)NLMSG_DATA(nlh))->error = -EMSGSIZE; } err = rtnl_unicast(skb, &init_net, NETLINK_CB(skb).pid); } else ip6_mr_forward(skb, c); } }
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 int act_get_notify(u32 pid, struct nlmsghdr *n, struct tc_action *a, int event) { struct sk_buff *skb; skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); if (!skb) return -ENOBUFS; if (tca_get_fill(skb, a, pid, n->nlmsg_seq, 0, event, 0, 0) <= 0) { kfree_skb(skb); return -EINVAL; } return rtnl_unicast(skb, pid); }
static void ip6mr_destroy_unres(struct mfc6_cache *c) { struct sk_buff *skb; atomic_dec(&cache_resolve_queue_len); while((skb = skb_dequeue(&c->mfc_un.unres.unresolved)) != NULL) { if (ipv6_hdr(skb)->version == 0) { struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct ipv6hdr)); nlh->nlmsg_type = NLMSG_ERROR; nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr)); skb_trim(skb, nlh->nlmsg_len); ((struct nlmsgerr *)NLMSG_DATA(nlh))->error = -ETIMEDOUT; rtnl_unicast(skb, NETLINK_CB(skb).pid); } else kfree_skb(skb); } kmem_cache_free(mrt_cachep, c); }
static int dcbnl_getperm_hwaddr(struct net_device *netdev, struct nlattr **tb, u32 pid, u32 seq, u16 flags) { struct sk_buff *dcbnl_skb; struct nlmsghdr *nlh; struct dcbmsg *dcb; u8 perm_addr[MAX_ADDR_LEN]; int ret = -EINVAL; if (!netdev->dcbnl_ops->getpermhwaddr) return ret; dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!dcbnl_skb) goto err_out; nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); dcb = NLMSG_DATA(nlh); dcb->dcb_family = AF_UNSPEC; dcb->cmd = DCB_CMD_GPERM_HWADDR; memset(perm_addr, 0, sizeof(perm_addr)); netdev->dcbnl_ops->getpermhwaddr(netdev, perm_addr); ret = nla_put(dcbnl_skb, DCB_ATTR_PERM_HWADDR, sizeof(perm_addr), perm_addr); nlmsg_end(dcbnl_skb, nlh); ret = rtnl_unicast(dcbnl_skb, &init_net, pid); if (ret) goto err_out; return 0; nlmsg_failure: kfree_skb(dcbnl_skb); err_out: return -EINVAL; }
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; }
/* * This is called by both endnodes and routers now. */ int dn_cache_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, void *arg) { struct rtattr **rta = arg; struct rtmsg *rtm = NLMSG_DATA(nlh); struct dn_route *rt = NULL; struct dn_skb_cb *cb; int err; struct sk_buff *skb; struct flowi fl; memset(&fl, 0, sizeof(fl)); fl.proto = DNPROTO_NSP; skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); if (skb == NULL) return -ENOBUFS; skb->mac.raw = skb->data; cb = DN_SKB_CB(skb); if (rta[RTA_SRC-1]) memcpy(&fl.fld_src, RTA_DATA(rta[RTA_SRC-1]), 2); if (rta[RTA_DST-1]) memcpy(&fl.fld_dst, RTA_DATA(rta[RTA_DST-1]), 2); if (rta[RTA_IIF-1]) memcpy(&fl.iif, RTA_DATA(rta[RTA_IIF-1]), sizeof(int)); if (fl.iif) { struct net_device *dev; if ((dev = dev_get_by_index(fl.iif)) == NULL) { kfree_skb(skb); return -ENODEV; } if (!dev->dn_ptr) { dev_put(dev); kfree_skb(skb); return -ENODEV; } skb->protocol = __constant_htons(ETH_P_DNA_RT); skb->dev = dev; cb->src = fl.fld_src; cb->dst = fl.fld_dst; local_bh_disable(); err = dn_route_input(skb); local_bh_enable(); memset(cb, 0, sizeof(struct dn_skb_cb)); rt = (struct dn_route *)skb->dst; if (!err && -rt->u.dst.error) err = rt->u.dst.error; } else { int oif = 0; if (rta[RTA_OIF - 1]) memcpy(&oif, RTA_DATA(rta[RTA_OIF - 1]), sizeof(int)); fl.oif = oif; err = dn_route_output_key((struct dst_entry **)&rt, &fl, 0); } if (skb->dev) dev_put(skb->dev); skb->dev = NULL; if (err) goto out_free; skb->dst = &rt->u.dst; if (rtm->rtm_flags & RTM_F_NOTIFY) rt->rt_flags |= RTCF_NOTIFY; NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid; err = dn_rt_fill_info(skb, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq, RTM_NEWROUTE, 0, 0); if (err == 0) goto out_free; if (err < 0) { err = -EMSGSIZE; goto out_free; } return rtnl_unicast(skb, NETLINK_CB(in_skb).pid); out_free: kfree_skb(skb); return err; }
static int dcbnl_bcn_getcfg(struct net_device *netdev, struct nlattr **tb, u32 pid, u32 seq, u16 flags) { struct sk_buff *dcbnl_skb; struct nlmsghdr *nlh; struct dcbmsg *dcb; struct nlattr *bcn_nest; struct nlattr *bcn_tb[DCB_BCN_ATTR_MAX + 1]; u8 value_byte; u32 value_integer; int ret = -EINVAL; bool getall = false; int i; if (!tb[DCB_ATTR_BCN] || !netdev->dcbnl_ops->getbcnrp || !netdev->dcbnl_ops->getbcncfg) return ret; ret = nla_parse_nested(bcn_tb, DCB_BCN_ATTR_MAX, tb[DCB_ATTR_BCN], dcbnl_bcn_nest); if (ret) goto err_out; dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!dcbnl_skb) goto err_out; nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); dcb = NLMSG_DATA(nlh); dcb->dcb_family = AF_UNSPEC; dcb->cmd = DCB_CMD_BCN_GCFG; bcn_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_BCN); if (!bcn_nest) goto err; if (bcn_tb[DCB_BCN_ATTR_ALL]) getall = true; for (i = DCB_BCN_ATTR_RP_0; i <= DCB_BCN_ATTR_RP_7; i++) { if (!getall && !bcn_tb[i]) continue; netdev->dcbnl_ops->getbcnrp(netdev, i - DCB_BCN_ATTR_RP_0, &value_byte); ret = nla_put_u8(dcbnl_skb, i, value_byte); if (ret) goto err_bcn; } for (i = DCB_BCN_ATTR_BCNA_0; i <= DCB_BCN_ATTR_RI; i++) { if (!getall && !bcn_tb[i]) continue; netdev->dcbnl_ops->getbcncfg(netdev, i, &value_integer); ret = nla_put_u32(dcbnl_skb, i, value_integer); if (ret) goto err_bcn; } nla_nest_end(dcbnl_skb, bcn_nest); nlmsg_end(dcbnl_skb, nlh); ret = rtnl_unicast(dcbnl_skb, &init_net, pid); if (ret) goto err_out; return 0; err_bcn: nla_nest_cancel(dcbnl_skb, bcn_nest); nlmsg_failure: err: kfree_skb(dcbnl_skb); err_out: ret = -EINVAL; return ret; }
static int __dcbnl_pg_getcfg(struct net_device *netdev, struct nlattr **tb, u32 pid, u32 seq, u16 flags, int dir) { struct sk_buff *dcbnl_skb; struct nlmsghdr *nlh; struct dcbmsg *dcb; struct nlattr *pg_nest, *param_nest, *data; struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1]; struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1]; u8 prio, pgid, tc_pct, up_map; int ret = -EINVAL; int getall = 0; int i; if (!tb[DCB_ATTR_PG_CFG] || !netdev->dcbnl_ops->getpgtccfgtx || !netdev->dcbnl_ops->getpgtccfgrx || !netdev->dcbnl_ops->getpgbwgcfgtx || !netdev->dcbnl_ops->getpgbwgcfgrx) return ret; ret = nla_parse_nested(pg_tb, DCB_PG_ATTR_MAX, tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest); if (ret) goto err_out; dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!dcbnl_skb) goto err_out; nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); dcb = NLMSG_DATA(nlh); dcb->dcb_family = AF_UNSPEC; dcb->cmd = (dir) ? DCB_CMD_PGRX_GCFG : DCB_CMD_PGTX_GCFG; pg_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_PG_CFG); if (!pg_nest) goto err; if (pg_tb[DCB_PG_ATTR_TC_ALL]) getall = 1; for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) { if (!getall && !pg_tb[i]) continue; if (pg_tb[DCB_PG_ATTR_TC_ALL]) data = pg_tb[DCB_PG_ATTR_TC_ALL]; else data = pg_tb[i]; ret = nla_parse_nested(param_tb, DCB_TC_ATTR_PARAM_MAX, data, dcbnl_tc_param_nest); if (ret) goto err_pg; param_nest = nla_nest_start(dcbnl_skb, i); if (!param_nest) goto err_pg; pgid = DCB_ATTR_VALUE_UNDEFINED; prio = DCB_ATTR_VALUE_UNDEFINED; tc_pct = DCB_ATTR_VALUE_UNDEFINED; up_map = DCB_ATTR_VALUE_UNDEFINED; if (dir) { /* Rx */ netdev->dcbnl_ops->getpgtccfgrx(netdev, i - DCB_PG_ATTR_TC_0, &prio, &pgid, &tc_pct, &up_map); } else { /* Tx */ netdev->dcbnl_ops->getpgtccfgtx(netdev, i - DCB_PG_ATTR_TC_0, &prio, &pgid, &tc_pct, &up_map); } if (param_tb[DCB_TC_ATTR_PARAM_PGID] || param_tb[DCB_TC_ATTR_PARAM_ALL]) { ret = nla_put_u8(dcbnl_skb, DCB_TC_ATTR_PARAM_PGID, pgid); if (ret) goto err_param; } if (param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING] || param_tb[DCB_TC_ATTR_PARAM_ALL]) { ret = nla_put_u8(dcbnl_skb, DCB_TC_ATTR_PARAM_UP_MAPPING, up_map); if (ret) goto err_param; } if (param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO] || param_tb[DCB_TC_ATTR_PARAM_ALL]) { ret = nla_put_u8(dcbnl_skb, DCB_TC_ATTR_PARAM_STRICT_PRIO, prio); if (ret) goto err_param; } if (param_tb[DCB_TC_ATTR_PARAM_BW_PCT] || param_tb[DCB_TC_ATTR_PARAM_ALL]) { ret = nla_put_u8(dcbnl_skb, DCB_TC_ATTR_PARAM_BW_PCT, tc_pct); if (ret) goto err_param; } nla_nest_end(dcbnl_skb, param_nest); } if (pg_tb[DCB_PG_ATTR_BW_ID_ALL]) getall = 1; else getall = 0; for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) { if (!getall && !pg_tb[i]) continue; tc_pct = DCB_ATTR_VALUE_UNDEFINED; if (dir) { /* Rx */ netdev->dcbnl_ops->getpgbwgcfgrx(netdev, i - DCB_PG_ATTR_BW_ID_0, &tc_pct); } else { /* Tx */ netdev->dcbnl_ops->getpgbwgcfgtx(netdev, i - DCB_PG_ATTR_BW_ID_0, &tc_pct); } ret = nla_put_u8(dcbnl_skb, i, tc_pct); if (ret) goto err_pg; } nla_nest_end(dcbnl_skb, pg_nest); nlmsg_end(dcbnl_skb, nlh); ret = rtnl_unicast(dcbnl_skb, &init_net, pid); if (ret) goto err_out; return 0; err_param: nla_nest_cancel(dcbnl_skb, param_nest); err_pg: nla_nest_cancel(dcbnl_skb, pg_nest); nlmsg_failure: err: kfree_skb(dcbnl_skb); err_out: ret = -EINVAL; return ret; }
static int dcbnl_getapp(struct net_device *netdev, struct nlattr **tb, u32 pid, u32 seq, u16 flags) { struct sk_buff *dcbnl_skb; struct nlmsghdr *nlh; struct dcbmsg *dcb; struct nlattr *app_nest; struct nlattr *app_tb[DCB_APP_ATTR_MAX + 1]; u16 id; u8 up, idtype; int ret = -EINVAL; if (!tb[DCB_ATTR_APP] || !netdev->dcbnl_ops->getapp) goto out; ret = nla_parse_nested(app_tb, DCB_APP_ATTR_MAX, tb[DCB_ATTR_APP], dcbnl_app_nest); if (ret) goto out; ret = -EINVAL; /* all must be non-null */ if ((!app_tb[DCB_APP_ATTR_IDTYPE]) || (!app_tb[DCB_APP_ATTR_ID])) goto out; /* either by eth type or by socket number */ idtype = nla_get_u8(app_tb[DCB_APP_ATTR_IDTYPE]); if ((idtype != DCB_APP_IDTYPE_ETHTYPE) && (idtype != DCB_APP_IDTYPE_PORTNUM)) goto out; id = nla_get_u16(app_tb[DCB_APP_ATTR_ID]); up = netdev->dcbnl_ops->getapp(netdev, idtype, id); /* send this back */ dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!dcbnl_skb) goto out; nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); dcb = NLMSG_DATA(nlh); dcb->dcb_family = AF_UNSPEC; dcb->cmd = DCB_CMD_GAPP; app_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_APP); ret = nla_put_u8(dcbnl_skb, DCB_APP_ATTR_IDTYPE, idtype); if (ret) goto out_cancel; ret = nla_put_u16(dcbnl_skb, DCB_APP_ATTR_ID, id); if (ret) goto out_cancel; ret = nla_put_u8(dcbnl_skb, DCB_APP_ATTR_PRIORITY, up); if (ret) goto out_cancel; nla_nest_end(dcbnl_skb, app_nest); nlmsg_end(dcbnl_skb, nlh); ret = rtnl_unicast(dcbnl_skb, &init_net, pid); if (ret) goto nlmsg_failure; goto out; out_cancel: nla_nest_cancel(dcbnl_skb, app_nest); nlmsg_failure: kfree_skb(dcbnl_skb); out: return ret; }
static int dcbnl_getnumtcs(struct net_device *netdev, struct nlattr **tb, u32 pid, u32 seq, u16 flags) { struct sk_buff *dcbnl_skb; struct nlmsghdr *nlh; struct dcbmsg *dcb; struct nlattr *data[DCB_NUMTCS_ATTR_MAX + 1], *nest; u8 value; int ret = -EINVAL; int i; int getall = 0; if (!tb[DCB_ATTR_NUMTCS] || !netdev->dcbnl_ops->getnumtcs) return ret; ret = nla_parse_nested(data, DCB_NUMTCS_ATTR_MAX, tb[DCB_ATTR_NUMTCS], dcbnl_numtcs_nest); if (ret) { ret = -EINVAL; goto err_out; } dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!dcbnl_skb) { ret = -EINVAL; goto err_out; } nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); dcb = NLMSG_DATA(nlh); dcb->dcb_family = AF_UNSPEC; dcb->cmd = DCB_CMD_GNUMTCS; nest = nla_nest_start(dcbnl_skb, DCB_ATTR_NUMTCS); if (!nest) { ret = -EINVAL; goto err; } if (data[DCB_NUMTCS_ATTR_ALL]) getall = 1; for (i = DCB_NUMTCS_ATTR_ALL+1; i <= DCB_NUMTCS_ATTR_MAX; i++) { if (!getall && !data[i]) continue; ret = netdev->dcbnl_ops->getnumtcs(netdev, i, &value); if (!ret) { ret = nla_put_u8(dcbnl_skb, i, value); if (ret) { nla_nest_cancel(dcbnl_skb, nest); ret = -EINVAL; goto err; } } else { goto err; } } nla_nest_end(dcbnl_skb, nest); nlmsg_end(dcbnl_skb, nlh); ret = rtnl_unicast(dcbnl_skb, &init_net, pid); if (ret) { ret = -EINVAL; goto err_out; } return 0; nlmsg_failure: err: kfree_skb(dcbnl_skb); err_out: return ret; }