diff options
Diffstat (limited to 'net/dcb')
-rw-r--r-- | net/dcb/dcbnl.c | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/net/dcb/dcbnl.c b/net/dcb/dcbnl.c index 19ac2b985485..2ff908498924 100644 --- a/net/dcb/dcbnl.c +++ b/net/dcb/dcbnl.c | |||
@@ -66,6 +66,7 @@ static const struct nla_policy dcbnl_rtnl_policy[DCB_ATTR_MAX + 1] = { | |||
66 | [DCB_ATTR_PFC_STATE] = {.type = NLA_U8}, | 66 | [DCB_ATTR_PFC_STATE] = {.type = NLA_U8}, |
67 | [DCB_ATTR_BCN] = {.type = NLA_NESTED}, | 67 | [DCB_ATTR_BCN] = {.type = NLA_NESTED}, |
68 | [DCB_ATTR_APP] = {.type = NLA_NESTED}, | 68 | [DCB_ATTR_APP] = {.type = NLA_NESTED}, |
69 | [DCB_ATTR_IEEE] = {.type = NLA_NESTED}, | ||
69 | }; | 70 | }; |
70 | 71 | ||
71 | /* DCB priority flow control to User Priority nested attributes */ | 72 | /* DCB priority flow control to User Priority nested attributes */ |
@@ -167,6 +168,17 @@ static const struct nla_policy dcbnl_app_nest[DCB_APP_ATTR_MAX + 1] = { | |||
167 | [DCB_APP_ATTR_PRIORITY] = {.type = NLA_U8}, | 168 | [DCB_APP_ATTR_PRIORITY] = {.type = NLA_U8}, |
168 | }; | 169 | }; |
169 | 170 | ||
171 | /* IEEE 802.1Qaz nested attributes. */ | ||
172 | static const struct nla_policy dcbnl_ieee_policy[DCB_ATTR_IEEE_MAX + 1] = { | ||
173 | [DCB_ATTR_IEEE_ETS] = {.len = sizeof(struct ieee_ets)}, | ||
174 | [DCB_ATTR_IEEE_PFC] = {.len = sizeof(struct ieee_pfc)}, | ||
175 | [DCB_ATTR_IEEE_APP_TABLE] = {.type = NLA_NESTED}, | ||
176 | }; | ||
177 | |||
178 | static const struct nla_policy dcbnl_ieee_app[DCB_ATTR_IEEE_APP_MAX + 1] = { | ||
179 | [DCB_ATTR_IEEE_APP] = {.len = sizeof(struct dcb_app)}, | ||
180 | }; | ||
181 | |||
170 | /* standard netlink reply call */ | 182 | /* standard netlink reply call */ |
171 | static int dcbnl_reply(u8 value, u8 event, u8 cmd, u8 attr, u32 pid, | 183 | static int dcbnl_reply(u8 value, u8 event, u8 cmd, u8 attr, u32 pid, |
172 | u32 seq, u16 flags) | 184 | u32 seq, u16 flags) |
@@ -1118,6 +1130,117 @@ err: | |||
1118 | return ret; | 1130 | return ret; |
1119 | } | 1131 | } |
1120 | 1132 | ||
1133 | /* Handle IEEE 802.1Qaz SET commands. If any requested operation can not | ||
1134 | * be completed the entire msg is aborted and error value is returned. | ||
1135 | * No attempt is made to reconcile the case where only part of the | ||
1136 | * cmd can be completed. | ||
1137 | */ | ||
1138 | static int dcbnl_ieee_set(struct net_device *netdev, struct nlattr **tb, | ||
1139 | u32 pid, u32 seq, u16 flags) | ||
1140 | { | ||
1141 | const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; | ||
1142 | struct nlattr *ieee[DCB_ATTR_IEEE_MAX + 1]; | ||
1143 | int err = -EOPNOTSUPP; | ||
1144 | |||
1145 | if (!ops) | ||
1146 | goto err; | ||
1147 | |||
1148 | err = nla_parse_nested(ieee, DCB_ATTR_IEEE_MAX, | ||
1149 | tb[DCB_ATTR_IEEE], dcbnl_ieee_policy); | ||
1150 | if (err) | ||
1151 | goto err; | ||
1152 | |||
1153 | if (ieee[DCB_ATTR_IEEE_ETS] && ops->ieee_setets) { | ||
1154 | struct ieee_ets *ets = nla_data(ieee[DCB_ATTR_IEEE_ETS]); | ||
1155 | err = ops->ieee_setets(netdev, ets); | ||
1156 | if (err) | ||
1157 | goto err; | ||
1158 | } | ||
1159 | |||
1160 | if (ieee[DCB_ATTR_IEEE_PFC] && ops->ieee_setets) { | ||
1161 | struct ieee_pfc *pfc = nla_data(ieee[DCB_ATTR_IEEE_PFC]); | ||
1162 | err = ops->ieee_setpfc(netdev, pfc); | ||
1163 | if (err) | ||
1164 | goto err; | ||
1165 | } | ||
1166 | |||
1167 | if (ieee[DCB_ATTR_IEEE_APP_TABLE] && ops->ieee_setapp) { | ||
1168 | struct nlattr *attr; | ||
1169 | int rem; | ||
1170 | |||
1171 | nla_for_each_nested(attr, ieee[DCB_ATTR_IEEE_APP_TABLE], rem) { | ||
1172 | struct dcb_app *app_data; | ||
1173 | if (nla_type(attr) != DCB_ATTR_IEEE_APP) | ||
1174 | continue; | ||
1175 | app_data = nla_data(attr); | ||
1176 | err = ops->ieee_setapp(netdev, app_data); | ||
1177 | if (err) | ||
1178 | goto err; | ||
1179 | } | ||
1180 | } | ||
1181 | |||
1182 | err: | ||
1183 | dcbnl_reply(err, RTM_SETDCB, DCB_CMD_IEEE_SET, DCB_ATTR_IEEE, | ||
1184 | pid, seq, flags); | ||
1185 | return err; | ||
1186 | } | ||
1187 | |||
1188 | |||
1189 | /* Handle IEEE 802.1Qaz GET commands. */ | ||
1190 | static int dcbnl_ieee_get(struct net_device *netdev, struct nlattr **tb, | ||
1191 | u32 pid, u32 seq, u16 flags) | ||
1192 | { | ||
1193 | struct sk_buff *skb; | ||
1194 | struct nlmsghdr *nlh; | ||
1195 | struct dcbmsg *dcb; | ||
1196 | struct nlattr *ieee; | ||
1197 | const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; | ||
1198 | int err; | ||
1199 | |||
1200 | if (!ops) | ||
1201 | return -EOPNOTSUPP; | ||
1202 | |||
1203 | skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
1204 | if (!skb) | ||
1205 | return -ENOBUFS; | ||
1206 | |||
1207 | nlh = NLMSG_NEW(skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); | ||
1208 | |||
1209 | dcb = NLMSG_DATA(nlh); | ||
1210 | dcb->dcb_family = AF_UNSPEC; | ||
1211 | dcb->cmd = DCB_CMD_IEEE_GET; | ||
1212 | |||
1213 | NLA_PUT_STRING(skb, DCB_ATTR_IFNAME, netdev->name); | ||
1214 | |||
1215 | ieee = nla_nest_start(skb, DCB_ATTR_IEEE); | ||
1216 | if (!ieee) | ||
1217 | goto nla_put_failure; | ||
1218 | |||
1219 | if (ops->ieee_getets) { | ||
1220 | struct ieee_ets ets; | ||
1221 | err = ops->ieee_getets(netdev, &ets); | ||
1222 | if (!err) | ||
1223 | NLA_PUT(skb, DCB_ATTR_IEEE_ETS, sizeof(ets), &ets); | ||
1224 | } | ||
1225 | |||
1226 | if (ops->ieee_getpfc) { | ||
1227 | struct ieee_pfc pfc; | ||
1228 | err = ops->ieee_getpfc(netdev, &pfc); | ||
1229 | if (!err) | ||
1230 | NLA_PUT(skb, DCB_ATTR_IEEE_PFC, sizeof(pfc), &pfc); | ||
1231 | } | ||
1232 | |||
1233 | nla_nest_end(skb, ieee); | ||
1234 | nlmsg_end(skb, nlh); | ||
1235 | |||
1236 | return rtnl_unicast(skb, &init_net, pid); | ||
1237 | nla_put_failure: | ||
1238 | nlmsg_cancel(skb, nlh); | ||
1239 | nlmsg_failure: | ||
1240 | kfree_skb(skb); | ||
1241 | return -1; | ||
1242 | } | ||
1243 | |||
1121 | static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | 1244 | static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) |
1122 | { | 1245 | { |
1123 | struct net *net = sock_net(skb->sk); | 1246 | struct net *net = sock_net(skb->sk); |
@@ -1223,6 +1346,14 @@ static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
1223 | ret = dcbnl_setapp(netdev, tb, pid, nlh->nlmsg_seq, | 1346 | ret = dcbnl_setapp(netdev, tb, pid, nlh->nlmsg_seq, |
1224 | nlh->nlmsg_flags); | 1347 | nlh->nlmsg_flags); |
1225 | goto out; | 1348 | goto out; |
1349 | case DCB_CMD_IEEE_SET: | ||
1350 | ret = dcbnl_ieee_set(netdev, tb, pid, nlh->nlmsg_seq, | ||
1351 | nlh->nlmsg_flags); | ||
1352 | goto out; | ||
1353 | case DCB_CMD_IEEE_GET: | ||
1354 | ret = dcbnl_ieee_get(netdev, tb, pid, nlh->nlmsg_seq, | ||
1355 | nlh->nlmsg_flags); | ||
1356 | goto out; | ||
1226 | default: | 1357 | default: |
1227 | goto errout; | 1358 | goto errout; |
1228 | } | 1359 | } |