diff options
Diffstat (limited to 'net/dcb/dcbnl.c')
| -rw-r--r-- | net/dcb/dcbnl.c | 677 | 
1 files changed, 547 insertions, 130 deletions
diff --git a/net/dcb/dcbnl.c b/net/dcb/dcbnl.c index 3609eacaf4c..3cb56af4e13 100644 --- a/net/dcb/dcbnl.c +++ b/net/dcb/dcbnl.c @@ -1166,64 +1166,6 @@ err:  	return ret;  } -/* Handle IEEE 802.1Qaz SET commands. If any requested operation can not - * be completed the entire msg is aborted and error value is returned. - * No attempt is made to reconcile the case where only part of the - * cmd can be completed. - */ -static int dcbnl_ieee_set(struct net_device *netdev, struct nlattr **tb, -			  u32 pid, u32 seq, u16 flags) -{ -	const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; -	struct nlattr *ieee[DCB_ATTR_IEEE_MAX + 1]; -	int err = -EOPNOTSUPP; - -	if (!ops) -		goto err; - -	err = nla_parse_nested(ieee, DCB_ATTR_IEEE_MAX, -			       tb[DCB_ATTR_IEEE], dcbnl_ieee_policy); -	if (err) -		goto err; - -	if (ieee[DCB_ATTR_IEEE_ETS] && ops->ieee_setets) { -		struct ieee_ets *ets = nla_data(ieee[DCB_ATTR_IEEE_ETS]); -		err = ops->ieee_setets(netdev, ets); -		if (err) -			goto err; -	} - -	if (ieee[DCB_ATTR_IEEE_PFC] && ops->ieee_setpfc) { -		struct ieee_pfc *pfc = nla_data(ieee[DCB_ATTR_IEEE_PFC]); -		err = ops->ieee_setpfc(netdev, pfc); -		if (err) -			goto err; -	} - -	if (ieee[DCB_ATTR_IEEE_APP_TABLE]) { -		struct nlattr *attr; -		int rem; - -		nla_for_each_nested(attr, ieee[DCB_ATTR_IEEE_APP_TABLE], rem) { -			struct dcb_app *app_data; -			if (nla_type(attr) != DCB_ATTR_IEEE_APP) -				continue; -			app_data = nla_data(attr); -			if (ops->ieee_setapp) -				err = ops->ieee_setapp(netdev, app_data); -			else -				err = dcb_setapp(netdev, app_data); -			if (err) -				goto err; -		} -	} - -err: -	dcbnl_reply(err, RTM_SETDCB, DCB_CMD_IEEE_SET, DCB_ATTR_IEEE, -		    pid, seq, flags); -	return err; -} -  static int dcbnl_build_peer_app(struct net_device *netdev, struct sk_buff* skb,  				int app_nested_type, int app_info_type,  				int app_entry_type) @@ -1279,29 +1221,13 @@ nla_put_failure:  }  /* Handle IEEE 802.1Qaz GET commands. */ -static int dcbnl_ieee_get(struct net_device *netdev, struct nlattr **tb, -			  u32 pid, u32 seq, u16 flags) +static int dcbnl_ieee_fill(struct sk_buff *skb, struct net_device *netdev)  { -	struct sk_buff *skb; -	struct nlmsghdr *nlh; -	struct dcbmsg *dcb;  	struct nlattr *ieee, *app;  	struct dcb_app_type *itr;  	const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; -	int err; - -	if (!ops) -		return -EOPNOTSUPP; - -	skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); -	if (!skb) -		return -ENOBUFS; - -	nlh = NLMSG_NEW(skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); - -	dcb = NLMSG_DATA(nlh); -	dcb->dcb_family = AF_UNSPEC; -	dcb->cmd = DCB_CMD_IEEE_GET; +	int dcbx; +	int err = -EMSGSIZE;  	NLA_PUT_STRING(skb, DCB_ATTR_IFNAME, netdev->name); @@ -1338,6 +1264,12 @@ static int dcbnl_ieee_get(struct net_device *netdev, struct nlattr **tb,  			}  		}  	} + +	if (netdev->dcbnl_ops->getdcbx) +		dcbx = netdev->dcbnl_ops->getdcbx(netdev); +	else +		dcbx = -EOPNOTSUPP; +  	spin_unlock(&dcb_lock);  	nla_nest_end(skb, app); @@ -1366,16 +1298,413 @@ static int dcbnl_ieee_get(struct net_device *netdev, struct nlattr **tb,  	}  	nla_nest_end(skb, ieee); -	nlmsg_end(skb, nlh); +	if (dcbx >= 0) { +		err = nla_put_u8(skb, DCB_ATTR_DCBX, dcbx); +		if (err) +			goto nla_put_failure; +	} + +	return 0; -	return rtnl_unicast(skb, &init_net, pid);  nla_put_failure: -	nlmsg_cancel(skb, nlh); -nlmsg_failure: -	kfree_skb(skb); -	return -1; +	return err; +} + +static int dcbnl_cee_pg_fill(struct sk_buff *skb, struct net_device *dev, +			     int dir) +{ +	u8 pgid, up_map, prio, tc_pct; +	const struct dcbnl_rtnl_ops *ops = dev->dcbnl_ops; +	int i = dir ? DCB_ATTR_CEE_TX_PG : DCB_ATTR_CEE_RX_PG; +	struct nlattr *pg = nla_nest_start(skb, i); + +	if (!pg) +		goto nla_put_failure; + +	for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) { +		struct nlattr *tc_nest = nla_nest_start(skb, i); + +		if (!tc_nest) +			goto nla_put_failure; + +		pgid = DCB_ATTR_VALUE_UNDEFINED; +		prio = DCB_ATTR_VALUE_UNDEFINED; +		tc_pct = DCB_ATTR_VALUE_UNDEFINED; +		up_map = DCB_ATTR_VALUE_UNDEFINED; + +		if (!dir) +			ops->getpgtccfgrx(dev, i - DCB_PG_ATTR_TC_0, +					  &prio, &pgid, &tc_pct, &up_map); +		else +			ops->getpgtccfgtx(dev, i - DCB_PG_ATTR_TC_0, +					  &prio, &pgid, &tc_pct, &up_map); + +		NLA_PUT_U8(skb, DCB_TC_ATTR_PARAM_PGID, pgid); +		NLA_PUT_U8(skb, DCB_TC_ATTR_PARAM_UP_MAPPING, up_map); +		NLA_PUT_U8(skb, DCB_TC_ATTR_PARAM_STRICT_PRIO, prio); +		NLA_PUT_U8(skb, DCB_TC_ATTR_PARAM_BW_PCT, tc_pct); +		nla_nest_end(skb, tc_nest); +	} + +	for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) { +		tc_pct = DCB_ATTR_VALUE_UNDEFINED; + +		if (!dir) +			ops->getpgbwgcfgrx(dev, i - DCB_PG_ATTR_BW_ID_0, +					   &tc_pct); +		else +			ops->getpgbwgcfgtx(dev, i - DCB_PG_ATTR_BW_ID_0, +					   &tc_pct); +		NLA_PUT_U8(skb, i, tc_pct); +	} +	nla_nest_end(skb, pg); +	return 0; + +nla_put_failure: +	return -EMSGSIZE; +} + +static int dcbnl_cee_fill(struct sk_buff *skb, struct net_device *netdev) +{ +	struct nlattr *cee, *app; +	struct dcb_app_type *itr; +	const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; +	int dcbx, i, err = -EMSGSIZE; +	u8 value; + +	NLA_PUT_STRING(skb, DCB_ATTR_IFNAME, netdev->name); + +	cee = nla_nest_start(skb, DCB_ATTR_CEE); +	if (!cee) +		goto nla_put_failure; + +	/* local pg */ +	if (ops->getpgtccfgtx && ops->getpgbwgcfgtx) { +		err = dcbnl_cee_pg_fill(skb, netdev, 1); +		if (err) +			goto nla_put_failure; +	} + +	if (ops->getpgtccfgrx && ops->getpgbwgcfgrx) { +		err = dcbnl_cee_pg_fill(skb, netdev, 0); +		if (err) +			goto nla_put_failure; +	} + +	/* local pfc */ +	if (ops->getpfccfg) { +		struct nlattr *pfc_nest = nla_nest_start(skb, DCB_ATTR_CEE_PFC); + +		if (!pfc_nest) +			goto nla_put_failure; + +		for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) { +			ops->getpfccfg(netdev, i - DCB_PFC_UP_ATTR_0, &value); +			NLA_PUT_U8(skb, i, value); +		} +		nla_nest_end(skb, pfc_nest); +	} + +	/* local app */ +	spin_lock(&dcb_lock); +	app = nla_nest_start(skb, DCB_ATTR_CEE_APP_TABLE); +	if (!app) +		goto dcb_unlock; + +	list_for_each_entry(itr, &dcb_app_list, list) { +		if (strncmp(itr->name, netdev->name, IFNAMSIZ) == 0) { +			struct nlattr *app_nest = nla_nest_start(skb, +								 DCB_ATTR_APP); +			if (!app_nest) +				goto dcb_unlock; + +			err = nla_put_u8(skb, DCB_APP_ATTR_IDTYPE, +					 itr->app.selector); +			if (err) +				goto dcb_unlock; + +			err = nla_put_u16(skb, DCB_APP_ATTR_ID, +					  itr->app.protocol); +			if (err) +				goto dcb_unlock; + +			err = nla_put_u8(skb, DCB_APP_ATTR_PRIORITY, +					 itr->app.priority); +			if (err) +				goto dcb_unlock; + +			nla_nest_end(skb, app_nest); +		} +	} +	nla_nest_end(skb, app); + +	if (netdev->dcbnl_ops->getdcbx) +		dcbx = netdev->dcbnl_ops->getdcbx(netdev); +	else +		dcbx = -EOPNOTSUPP; + +	spin_unlock(&dcb_lock); + +	/* features flags */ +	if (ops->getfeatcfg) { +		struct nlattr *feat = nla_nest_start(skb, DCB_ATTR_CEE_FEAT); +		if (!feat) +			goto nla_put_failure; + +		for (i = DCB_FEATCFG_ATTR_ALL + 1; i <= DCB_FEATCFG_ATTR_MAX; +		     i++) +			if (!ops->getfeatcfg(netdev, i, &value)) +				NLA_PUT_U8(skb, i, value); + +		nla_nest_end(skb, feat); +	} + +	/* peer info if available */ +	if (ops->cee_peer_getpg) { +		struct cee_pg pg; +		err = ops->cee_peer_getpg(netdev, &pg); +		if (!err) +			NLA_PUT(skb, DCB_ATTR_CEE_PEER_PG, sizeof(pg), &pg); +	} + +	if (ops->cee_peer_getpfc) { +		struct cee_pfc pfc; +		err = ops->cee_peer_getpfc(netdev, &pfc); +		if (!err) +			NLA_PUT(skb, DCB_ATTR_CEE_PEER_PFC, sizeof(pfc), &pfc); +	} + +	if (ops->peer_getappinfo && ops->peer_getapptable) { +		err = dcbnl_build_peer_app(netdev, skb, +					   DCB_ATTR_CEE_PEER_APP_TABLE, +					   DCB_ATTR_CEE_PEER_APP_INFO, +					   DCB_ATTR_CEE_PEER_APP); +		if (err) +			goto nla_put_failure; +	} +	nla_nest_end(skb, cee); + +	/* DCBX state */ +	if (dcbx >= 0) { +		err = nla_put_u8(skb, DCB_ATTR_DCBX, dcbx); +		if (err) +			goto nla_put_failure; +	} +	return 0; + +dcb_unlock: +	spin_unlock(&dcb_lock); +nla_put_failure: +	return err; +} + +static int dcbnl_notify(struct net_device *dev, int event, int cmd, +			u32 seq, u32 pid, int dcbx_ver) +{ +	struct net *net = dev_net(dev); +	struct sk_buff *skb; +	struct nlmsghdr *nlh; +	struct dcbmsg *dcb; +	const struct dcbnl_rtnl_ops *ops = dev->dcbnl_ops; +	int err; + +	if (!ops) +		return -EOPNOTSUPP; + +	skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); +	if (!skb) +		return -ENOBUFS; + +	nlh = nlmsg_put(skb, pid, 0, event, sizeof(*dcb), 0); +	if (nlh == NULL) { +		nlmsg_free(skb); +		return -EMSGSIZE; +	} + +	dcb = NLMSG_DATA(nlh); +	dcb->dcb_family = AF_UNSPEC; +	dcb->cmd = cmd; + +	if (dcbx_ver == DCB_CAP_DCBX_VER_IEEE) +		err = dcbnl_ieee_fill(skb, dev); +	else +		err = dcbnl_cee_fill(skb, dev); + +	if (err < 0) { +		/* Report error to broadcast listeners */ +		nlmsg_cancel(skb, nlh); +		kfree_skb(skb); +		rtnl_set_sk_err(net, RTNLGRP_DCB, err); +	} else { +		/* End nlmsg and notify broadcast listeners */ +		nlmsg_end(skb, nlh); +		rtnl_notify(skb, net, 0, RTNLGRP_DCB, NULL, GFP_KERNEL); +	} + +	return err; +} + +int dcbnl_ieee_notify(struct net_device *dev, int event, int cmd, +		      u32 seq, u32 pid) +{ +	return dcbnl_notify(dev, event, cmd, seq, pid, DCB_CAP_DCBX_VER_IEEE); +} +EXPORT_SYMBOL(dcbnl_ieee_notify); + +int dcbnl_cee_notify(struct net_device *dev, int event, int cmd, +		     u32 seq, u32 pid) +{ +	return dcbnl_notify(dev, event, cmd, seq, pid, DCB_CAP_DCBX_VER_CEE); +} +EXPORT_SYMBOL(dcbnl_cee_notify); + +/* Handle IEEE 802.1Qaz SET commands. If any requested operation can not + * be completed the entire msg is aborted and error value is returned. + * No attempt is made to reconcile the case where only part of the + * cmd can be completed. + */ +static int dcbnl_ieee_set(struct net_device *netdev, struct nlattr **tb, +			  u32 pid, u32 seq, u16 flags) +{ +	const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; +	struct nlattr *ieee[DCB_ATTR_IEEE_MAX + 1]; +	int err = -EOPNOTSUPP; + +	if (!ops) +		return err; + +	if (!tb[DCB_ATTR_IEEE]) +		return -EINVAL; + +	err = nla_parse_nested(ieee, DCB_ATTR_IEEE_MAX, +			       tb[DCB_ATTR_IEEE], dcbnl_ieee_policy); +	if (err) +		return err; + +	if (ieee[DCB_ATTR_IEEE_ETS] && ops->ieee_setets) { +		struct ieee_ets *ets = nla_data(ieee[DCB_ATTR_IEEE_ETS]); +		err = ops->ieee_setets(netdev, ets); +		if (err) +			goto err; +	} + +	if (ieee[DCB_ATTR_IEEE_PFC] && ops->ieee_setpfc) { +		struct ieee_pfc *pfc = nla_data(ieee[DCB_ATTR_IEEE_PFC]); +		err = ops->ieee_setpfc(netdev, pfc); +		if (err) +			goto err; +	} + +	if (ieee[DCB_ATTR_IEEE_APP_TABLE]) { +		struct nlattr *attr; +		int rem; + +		nla_for_each_nested(attr, ieee[DCB_ATTR_IEEE_APP_TABLE], rem) { +			struct dcb_app *app_data; +			if (nla_type(attr) != DCB_ATTR_IEEE_APP) +				continue; +			app_data = nla_data(attr); +			if (ops->ieee_setapp) +				err = ops->ieee_setapp(netdev, app_data); +			else +				err = dcb_ieee_setapp(netdev, app_data); +			if (err) +				goto err; +		} +	} + +err: +	dcbnl_reply(err, RTM_SETDCB, DCB_CMD_IEEE_SET, DCB_ATTR_IEEE, +		    pid, seq, flags); +	dcbnl_ieee_notify(netdev, RTM_SETDCB, DCB_CMD_IEEE_SET, seq, 0); +	return err;  } +static int dcbnl_ieee_get(struct net_device *netdev, struct nlattr **tb, +			  u32 pid, u32 seq, u16 flags) +{ +	struct net *net = dev_net(netdev); +	struct sk_buff *skb; +	struct nlmsghdr *nlh; +	struct dcbmsg *dcb; +	const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; +	int err; + +	if (!ops) +		return -EOPNOTSUPP; + +	skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); +	if (!skb) +		return -ENOBUFS; + +	nlh = nlmsg_put(skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); +	if (nlh == NULL) { +		nlmsg_free(skb); +		return -EMSGSIZE; +	} + +	dcb = NLMSG_DATA(nlh); +	dcb->dcb_family = AF_UNSPEC; +	dcb->cmd = DCB_CMD_IEEE_GET; + +	err = dcbnl_ieee_fill(skb, netdev); + +	if (err < 0) { +		nlmsg_cancel(skb, nlh); +		kfree_skb(skb); +	} else { +		nlmsg_end(skb, nlh); +		err = rtnl_unicast(skb, net, pid); +	} + +	return err; +} + +static int dcbnl_ieee_del(struct net_device *netdev, struct nlattr **tb, +			  u32 pid, u32 seq, u16 flags) +{ +	const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; +	struct nlattr *ieee[DCB_ATTR_IEEE_MAX + 1]; +	int err = -EOPNOTSUPP; + +	if (!ops) +		return -EOPNOTSUPP; + +	if (!tb[DCB_ATTR_IEEE]) +		return -EINVAL; + +	err = nla_parse_nested(ieee, DCB_ATTR_IEEE_MAX, +			       tb[DCB_ATTR_IEEE], dcbnl_ieee_policy); +	if (err) +		return err; + +	if (ieee[DCB_ATTR_IEEE_APP_TABLE]) { +		struct nlattr *attr; +		int rem; + +		nla_for_each_nested(attr, ieee[DCB_ATTR_IEEE_APP_TABLE], rem) { +			struct dcb_app *app_data; + +			if (nla_type(attr) != DCB_ATTR_IEEE_APP) +				continue; +			app_data = nla_data(attr); +			if (ops->ieee_delapp) +				err = ops->ieee_delapp(netdev, app_data); +			else +				err = dcb_ieee_delapp(netdev, app_data); +			if (err) +				goto err; +		} +	} + +err: +	dcbnl_reply(err, RTM_SETDCB, DCB_CMD_IEEE_DEL, DCB_ATTR_IEEE, +		    pid, seq, flags); +	dcbnl_ieee_notify(netdev, RTM_SETDCB, DCB_CMD_IEEE_DEL, seq, 0); +	return err; +} + +  /* DCBX configuration */  static int dcbnl_getdcbx(struct net_device *netdev, struct nlattr **tb,  			 u32 pid, u32 seq, u16 flags) @@ -1522,10 +1851,10 @@ err:  static int dcbnl_cee_get(struct net_device *netdev, struct nlattr **tb,  			 u32 pid, u32 seq, u16 flags)  { +	struct net *net = dev_net(netdev);  	struct sk_buff *skb;  	struct nlmsghdr *nlh;  	struct dcbmsg *dcb; -	struct nlattr *cee;  	const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;  	int err; @@ -1536,51 +1865,26 @@ static int dcbnl_cee_get(struct net_device *netdev, struct nlattr **tb,  	if (!skb)  		return -ENOBUFS; -	nlh = NLMSG_NEW(skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); +	nlh = nlmsg_put(skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); +	if (nlh == NULL) { +		nlmsg_free(skb); +		return -EMSGSIZE; +	}  	dcb = NLMSG_DATA(nlh);  	dcb->dcb_family = AF_UNSPEC;  	dcb->cmd = DCB_CMD_CEE_GET; -	NLA_PUT_STRING(skb, DCB_ATTR_IFNAME, netdev->name); +	err = dcbnl_cee_fill(skb, netdev); -	cee = nla_nest_start(skb, DCB_ATTR_CEE); -	if (!cee) -		goto nla_put_failure; - -	/* get peer info if available */ -	if (ops->cee_peer_getpg) { -		struct cee_pg pg; -		err = ops->cee_peer_getpg(netdev, &pg); -		if (!err) -			NLA_PUT(skb, DCB_ATTR_CEE_PEER_PG, sizeof(pg), &pg); -	} - -	if (ops->cee_peer_getpfc) { -		struct cee_pfc pfc; -		err = ops->cee_peer_getpfc(netdev, &pfc); -		if (!err) -			NLA_PUT(skb, DCB_ATTR_CEE_PEER_PFC, sizeof(pfc), &pfc); -	} - -	if (ops->peer_getappinfo && ops->peer_getapptable) { -		err = dcbnl_build_peer_app(netdev, skb, -					   DCB_ATTR_CEE_PEER_APP_TABLE, -					   DCB_ATTR_CEE_PEER_APP_INFO, -					   DCB_ATTR_CEE_PEER_APP); -		if (err) -			goto nla_put_failure; +	if (err < 0) { +		nlmsg_cancel(skb, nlh); +		nlmsg_free(skb); +	} else { +		nlmsg_end(skb, nlh); +		err = rtnl_unicast(skb, net, pid);  	} - -	nla_nest_end(skb, cee); -	nlmsg_end(skb, nlh); - -	return rtnl_unicast(skb, &init_net, pid); -nla_put_failure: -	nlmsg_cancel(skb, nlh); -nlmsg_failure: -	kfree_skb(skb); -	return -1; +	return err;  }  static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) @@ -1690,11 +1994,15 @@ static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)  		goto out;  	case DCB_CMD_IEEE_SET:  		ret = dcbnl_ieee_set(netdev, tb, pid, nlh->nlmsg_seq, -				 nlh->nlmsg_flags); +				     nlh->nlmsg_flags);  		goto out;  	case DCB_CMD_IEEE_GET:  		ret = dcbnl_ieee_get(netdev, tb, pid, nlh->nlmsg_seq, -				 nlh->nlmsg_flags); +				     nlh->nlmsg_flags); +		goto out; +	case DCB_CMD_IEEE_DEL: +		ret = dcbnl_ieee_del(netdev, tb, pid, nlh->nlmsg_seq, +				     nlh->nlmsg_flags);  		goto out;  	case DCB_CMD_GDCBX:  		ret = dcbnl_getdcbx(netdev, tb, pid, nlh->nlmsg_seq, @@ -1754,12 +2062,13 @@ u8 dcb_getapp(struct net_device *dev, struct dcb_app *app)  EXPORT_SYMBOL(dcb_getapp);  /** - * ixgbe_dcbnl_setapp - add dcb application data to app list + * dcb_setapp - add CEE dcb application data to app list   * - * Priority 0 is the default priority this removes applications - * from the app list if the priority is set to zero. + * Priority 0 is an invalid priority in CEE spec. This routine + * removes applications from the app list if the priority is + * set to zero.   */ -u8 dcb_setapp(struct net_device *dev, struct dcb_app *new) +int dcb_setapp(struct net_device *dev, struct dcb_app *new)  {  	struct dcb_app_type *itr;  	struct dcb_app_type event; @@ -1802,6 +2111,114 @@ out:  }  EXPORT_SYMBOL(dcb_setapp); +/** + * dcb_ieee_getapp_mask - retrieve the IEEE DCB application priority + * + * Helper routine which on success returns a non-zero 802.1Qaz user + * priority bitmap otherwise returns 0 to indicate the dcb_app was + * not found in APP list. + */ +u8 dcb_ieee_getapp_mask(struct net_device *dev, struct dcb_app *app) +{ +	struct dcb_app_type *itr; +	u8 prio = 0; + +	spin_lock(&dcb_lock); +	list_for_each_entry(itr, &dcb_app_list, list) { +		if (itr->app.selector == app->selector && +		    itr->app.protocol == app->protocol && +		    (strncmp(itr->name, dev->name, IFNAMSIZ) == 0)) { +			prio |= 1 << itr->app.priority; +		} +	} +	spin_unlock(&dcb_lock); + +	return prio; +} +EXPORT_SYMBOL(dcb_ieee_getapp_mask); + +/** + * dcb_ieee_setapp - add IEEE dcb application data to app list + * + * This adds Application data to the list. Multiple application + * entries may exists for the same selector and protocol as long + * as the priorities are different. + */ +int dcb_ieee_setapp(struct net_device *dev, struct dcb_app *new) +{ +	struct dcb_app_type *itr, *entry; +	struct dcb_app_type event; +	int err = 0; + +	memcpy(&event.name, dev->name, sizeof(event.name)); +	memcpy(&event.app, new, sizeof(event.app)); + +	spin_lock(&dcb_lock); +	/* Search for existing match and abort if found */ +	list_for_each_entry(itr, &dcb_app_list, list) { +		if (itr->app.selector == new->selector && +		    itr->app.protocol == new->protocol && +		    itr->app.priority == new->priority && +		    (strncmp(itr->name, dev->name, IFNAMSIZ) == 0)) { +			err = -EEXIST; +			goto out; +		} +	} + +	/* App entry does not exist add new entry */ +	entry = kmalloc(sizeof(struct dcb_app_type), GFP_ATOMIC); +	if (!entry) { +		err = -ENOMEM; +		goto out; +	} + +	memcpy(&entry->app, new, sizeof(*new)); +	strncpy(entry->name, dev->name, IFNAMSIZ); +	list_add(&entry->list, &dcb_app_list); +out: +	spin_unlock(&dcb_lock); +	if (!err) +		call_dcbevent_notifiers(DCB_APP_EVENT, &event); +	return err; +} +EXPORT_SYMBOL(dcb_ieee_setapp); + +/** + * dcb_ieee_delapp - delete IEEE dcb application data from list + * + * This removes a matching APP data from the APP list + */ +int dcb_ieee_delapp(struct net_device *dev, struct dcb_app *del) +{ +	struct dcb_app_type *itr; +	struct dcb_app_type event; +	int err = -ENOENT; + +	memcpy(&event.name, dev->name, sizeof(event.name)); +	memcpy(&event.app, del, sizeof(event.app)); + +	spin_lock(&dcb_lock); +	/* Search for existing match and remove it. */ +	list_for_each_entry(itr, &dcb_app_list, list) { +		if (itr->app.selector == del->selector && +		    itr->app.protocol == del->protocol && +		    itr->app.priority == del->priority && +		    (strncmp(itr->name, dev->name, IFNAMSIZ) == 0)) { +			list_del(&itr->list); +			kfree(itr); +			err = 0; +			goto out; +		} +	} + +out: +	spin_unlock(&dcb_lock); +	if (!err) +		call_dcbevent_notifiers(DCB_APP_EVENT, &event); +	return err; +} +EXPORT_SYMBOL(dcb_ieee_delapp); +  static void dcb_flushapp(void)  {  	struct dcb_app_type *app; @@ -1819,8 +2236,8 @@ static int __init dcbnl_init(void)  {  	INIT_LIST_HEAD(&dcb_app_list); -	rtnl_register(PF_UNSPEC, RTM_GETDCB, dcb_doit, NULL); -	rtnl_register(PF_UNSPEC, RTM_SETDCB, dcb_doit, NULL); +	rtnl_register(PF_UNSPEC, RTM_GETDCB, dcb_doit, NULL, NULL); +	rtnl_register(PF_UNSPEC, RTM_SETDCB, dcb_doit, NULL, NULL);  	return 0;  }  |