1 /* 2 * Copyright Samuel Mendoza-Jonas, IBM Corporation 2018. 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 */ 9 10 #include <linux/module.h> 11 #include <linux/kernel.h> 12 #include <linux/if_arp.h> 13 #include <linux/rtnetlink.h> 14 #include <linux/etherdevice.h> 15 #include <net/genetlink.h> 16 #include <net/ncsi.h> 17 #include <linux/skbuff.h> 18 #include <net/sock.h> 19 #include <uapi/linux/ncsi.h> 20 21 #include "internal.h" 22 #include "ncsi-netlink.h" 23 24 static struct genl_family ncsi_genl_family; 25 26 static const struct nla_policy ncsi_genl_policy[NCSI_ATTR_MAX + 1] = { 27 [NCSI_ATTR_IFINDEX] = { .type = NLA_U32 }, 28 [NCSI_ATTR_PACKAGE_LIST] = { .type = NLA_NESTED }, 29 [NCSI_ATTR_PACKAGE_ID] = { .type = NLA_U32 }, 30 [NCSI_ATTR_CHANNEL_ID] = { .type = NLA_U32 }, 31 }; 32 33 static struct ncsi_dev_priv *ndp_from_ifindex(struct net *net, u32 ifindex) 34 { 35 struct ncsi_dev_priv *ndp; 36 struct net_device *dev; 37 struct ncsi_dev *nd; 38 struct ncsi_dev; 39 40 if (!net) 41 return NULL; 42 43 dev = dev_get_by_index(net, ifindex); 44 if (!dev) { 45 pr_err("NCSI netlink: No device for ifindex %u\n", ifindex); 46 return NULL; 47 } 48 49 nd = ncsi_find_dev(dev); 50 ndp = nd ? TO_NCSI_DEV_PRIV(nd) : NULL; 51 52 dev_put(dev); 53 return ndp; 54 } 55 56 static int ncsi_write_channel_info(struct sk_buff *skb, 57 struct ncsi_dev_priv *ndp, 58 struct ncsi_channel *nc) 59 { 60 struct ncsi_channel_vlan_filter *ncf; 61 struct ncsi_channel_mode *m; 62 struct nlattr *vid_nest; 63 int i; 64 65 nla_put_u32(skb, NCSI_CHANNEL_ATTR_ID, nc->id); 66 m = &nc->modes[NCSI_MODE_LINK]; 67 nla_put_u32(skb, NCSI_CHANNEL_ATTR_LINK_STATE, m->data[2]); 68 if (nc->state == NCSI_CHANNEL_ACTIVE) 69 nla_put_flag(skb, NCSI_CHANNEL_ATTR_ACTIVE); 70 if (ndp->force_channel == nc) 71 nla_put_flag(skb, NCSI_CHANNEL_ATTR_FORCED); 72 73 nla_put_u32(skb, NCSI_CHANNEL_ATTR_VERSION_MAJOR, nc->version.version); 74 nla_put_u32(skb, NCSI_CHANNEL_ATTR_VERSION_MINOR, nc->version.alpha2); 75 nla_put_string(skb, NCSI_CHANNEL_ATTR_VERSION_STR, nc->version.fw_name); 76 77 vid_nest = nla_nest_start(skb, NCSI_CHANNEL_ATTR_VLAN_LIST); 78 if (!vid_nest) 79 return -ENOMEM; 80 ncf = &nc->vlan_filter; 81 i = -1; 82 while ((i = find_next_bit((void *)&ncf->bitmap, ncf->n_vids, 83 i + 1)) < ncf->n_vids) { 84 if (ncf->vids[i]) 85 nla_put_u16(skb, NCSI_CHANNEL_ATTR_VLAN_ID, 86 ncf->vids[i]); 87 } 88 nla_nest_end(skb, vid_nest); 89 90 return 0; 91 } 92 93 static int ncsi_write_package_info(struct sk_buff *skb, 94 struct ncsi_dev_priv *ndp, unsigned int id) 95 { 96 struct nlattr *pnest, *cnest, *nest; 97 struct ncsi_package *np; 98 struct ncsi_channel *nc; 99 bool found; 100 int rc; 101 102 if (id > ndp->package_num - 1) { 103 netdev_info(ndp->ndev.dev, "NCSI: No package with id %u\n", id); 104 return -ENODEV; 105 } 106 107 found = false; 108 NCSI_FOR_EACH_PACKAGE(ndp, np) { 109 if (np->id != id) 110 continue; 111 pnest = nla_nest_start(skb, NCSI_PKG_ATTR); 112 if (!pnest) 113 return -ENOMEM; 114 nla_put_u32(skb, NCSI_PKG_ATTR_ID, np->id); 115 if (ndp->force_package == np) 116 nla_put_flag(skb, NCSI_PKG_ATTR_FORCED); 117 cnest = nla_nest_start(skb, NCSI_PKG_ATTR_CHANNEL_LIST); 118 if (!cnest) { 119 nla_nest_cancel(skb, pnest); 120 return -ENOMEM; 121 } 122 NCSI_FOR_EACH_CHANNEL(np, nc) { 123 nest = nla_nest_start(skb, NCSI_CHANNEL_ATTR); 124 if (!nest) { 125 nla_nest_cancel(skb, cnest); 126 nla_nest_cancel(skb, pnest); 127 return -ENOMEM; 128 } 129 rc = ncsi_write_channel_info(skb, ndp, nc); 130 if (rc) { 131 nla_nest_cancel(skb, nest); 132 nla_nest_cancel(skb, cnest); 133 nla_nest_cancel(skb, pnest); 134 return rc; 135 } 136 nla_nest_end(skb, nest); 137 } 138 nla_nest_end(skb, cnest); 139 nla_nest_end(skb, pnest); 140 found = true; 141 } 142 143 if (!found) 144 return -ENODEV; 145 146 return 0; 147 } 148 149 static int ncsi_pkg_info_nl(struct sk_buff *msg, struct genl_info *info) 150 { 151 struct ncsi_dev_priv *ndp; 152 unsigned int package_id; 153 struct sk_buff *skb; 154 struct nlattr *attr; 155 void *hdr; 156 int rc; 157 158 if (!info || !info->attrs) 159 return -EINVAL; 160 161 if (!info->attrs[NCSI_ATTR_IFINDEX]) 162 return -EINVAL; 163 164 if (!info->attrs[NCSI_ATTR_PACKAGE_ID]) 165 return -EINVAL; 166 167 ndp = ndp_from_ifindex(genl_info_net(info), 168 nla_get_u32(info->attrs[NCSI_ATTR_IFINDEX])); 169 if (!ndp) 170 return -ENODEV; 171 172 skb = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 173 if (!skb) 174 return -ENOMEM; 175 176 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq, 177 &ncsi_genl_family, 0, NCSI_CMD_PKG_INFO); 178 if (!hdr) { 179 kfree_skb(skb); 180 return -EMSGSIZE; 181 } 182 183 package_id = nla_get_u32(info->attrs[NCSI_ATTR_PACKAGE_ID]); 184 185 attr = nla_nest_start(skb, NCSI_ATTR_PACKAGE_LIST); 186 if (!attr) { 187 kfree_skb(skb); 188 return -EMSGSIZE; 189 } 190 rc = ncsi_write_package_info(skb, ndp, package_id); 191 192 if (rc) { 193 nla_nest_cancel(skb, attr); 194 goto err; 195 } 196 197 nla_nest_end(skb, attr); 198 199 genlmsg_end(skb, hdr); 200 return genlmsg_reply(skb, info); 201 202 err: 203 kfree_skb(skb); 204 return rc; 205 } 206 207 static int ncsi_pkg_info_all_nl(struct sk_buff *skb, 208 struct netlink_callback *cb) 209 { 210 struct nlattr *attrs[NCSI_ATTR_MAX + 1]; 211 struct ncsi_package *np, *package; 212 struct ncsi_dev_priv *ndp; 213 unsigned int package_id; 214 struct nlattr *attr; 215 void *hdr; 216 int rc; 217 218 rc = genlmsg_parse(cb->nlh, &ncsi_genl_family, attrs, NCSI_ATTR_MAX, 219 ncsi_genl_policy, NULL); 220 if (rc) 221 return rc; 222 223 if (!attrs[NCSI_ATTR_IFINDEX]) 224 return -EINVAL; 225 226 ndp = ndp_from_ifindex(get_net(sock_net(skb->sk)), 227 nla_get_u32(attrs[NCSI_ATTR_IFINDEX])); 228 229 if (!ndp) 230 return -ENODEV; 231 232 package_id = cb->args[0]; 233 package = NULL; 234 NCSI_FOR_EACH_PACKAGE(ndp, np) 235 if (np->id == package_id) 236 package = np; 237 238 if (!package) 239 return 0; /* done */ 240 241 hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, 242 &ncsi_genl_family, NLM_F_MULTI, NCSI_CMD_PKG_INFO); 243 if (!hdr) { 244 rc = -EMSGSIZE; 245 goto err; 246 } 247 248 attr = nla_nest_start(skb, NCSI_ATTR_PACKAGE_LIST); 249 rc = ncsi_write_package_info(skb, ndp, package->id); 250 if (rc) { 251 nla_nest_cancel(skb, attr); 252 goto err; 253 } 254 255 nla_nest_end(skb, attr); 256 genlmsg_end(skb, hdr); 257 258 cb->args[0] = package_id + 1; 259 260 return skb->len; 261 err: 262 genlmsg_cancel(skb, hdr); 263 return rc; 264 } 265 266 static int ncsi_set_interface_nl(struct sk_buff *msg, struct genl_info *info) 267 { 268 struct ncsi_package *np, *package; 269 struct ncsi_channel *nc, *channel; 270 u32 package_id, channel_id; 271 struct ncsi_dev_priv *ndp; 272 unsigned long flags; 273 274 if (!info || !info->attrs) 275 return -EINVAL; 276 277 if (!info->attrs[NCSI_ATTR_IFINDEX]) 278 return -EINVAL; 279 280 if (!info->attrs[NCSI_ATTR_PACKAGE_ID]) 281 return -EINVAL; 282 283 ndp = ndp_from_ifindex(get_net(sock_net(msg->sk)), 284 nla_get_u32(info->attrs[NCSI_ATTR_IFINDEX])); 285 if (!ndp) 286 return -ENODEV; 287 288 package_id = nla_get_u32(info->attrs[NCSI_ATTR_PACKAGE_ID]); 289 package = NULL; 290 291 spin_lock_irqsave(&ndp->lock, flags); 292 293 NCSI_FOR_EACH_PACKAGE(ndp, np) 294 if (np->id == package_id) 295 package = np; 296 if (!package) { 297 /* The user has set a package that does not exist */ 298 spin_unlock_irqrestore(&ndp->lock, flags); 299 return -ERANGE; 300 } 301 302 channel = NULL; 303 if (!info->attrs[NCSI_ATTR_CHANNEL_ID]) { 304 /* Allow any channel */ 305 channel_id = NCSI_RESERVED_CHANNEL; 306 } else { 307 channel_id = nla_get_u32(info->attrs[NCSI_ATTR_CHANNEL_ID]); 308 NCSI_FOR_EACH_CHANNEL(package, nc) 309 if (nc->id == channel_id) 310 channel = nc; 311 } 312 313 if (channel_id != NCSI_RESERVED_CHANNEL && !channel) { 314 /* The user has set a channel that does not exist on this 315 * package 316 */ 317 spin_unlock_irqrestore(&ndp->lock, flags); 318 netdev_info(ndp->ndev.dev, "NCSI: Channel %u does not exist!\n", 319 channel_id); 320 return -ERANGE; 321 } 322 323 ndp->force_package = package; 324 ndp->force_channel = channel; 325 spin_unlock_irqrestore(&ndp->lock, flags); 326 327 netdev_info(ndp->ndev.dev, "Set package 0x%x, channel 0x%x%s as preferred\n", 328 package_id, channel_id, 329 channel_id == NCSI_RESERVED_CHANNEL ? " (any)" : ""); 330 331 /* Bounce the NCSI channel to set changes */ 332 ncsi_stop_dev(&ndp->ndev); 333 ncsi_start_dev(&ndp->ndev); 334 335 return 0; 336 } 337 338 static int ncsi_clear_interface_nl(struct sk_buff *msg, struct genl_info *info) 339 { 340 struct ncsi_dev_priv *ndp; 341 unsigned long flags; 342 343 if (!info || !info->attrs) 344 return -EINVAL; 345 346 if (!info->attrs[NCSI_ATTR_IFINDEX]) 347 return -EINVAL; 348 349 ndp = ndp_from_ifindex(get_net(sock_net(msg->sk)), 350 nla_get_u32(info->attrs[NCSI_ATTR_IFINDEX])); 351 if (!ndp) 352 return -ENODEV; 353 354 /* Clear any override */ 355 spin_lock_irqsave(&ndp->lock, flags); 356 ndp->force_package = NULL; 357 ndp->force_channel = NULL; 358 spin_unlock_irqrestore(&ndp->lock, flags); 359 netdev_info(ndp->ndev.dev, "NCSI: Cleared preferred package/channel\n"); 360 361 /* Bounce the NCSI channel to set changes */ 362 ncsi_stop_dev(&ndp->ndev); 363 ncsi_start_dev(&ndp->ndev); 364 365 return 0; 366 } 367 368 static const struct genl_ops ncsi_ops[] = { 369 { 370 .cmd = NCSI_CMD_PKG_INFO, 371 .policy = ncsi_genl_policy, 372 .doit = ncsi_pkg_info_nl, 373 .dumpit = ncsi_pkg_info_all_nl, 374 .flags = 0, 375 }, 376 { 377 .cmd = NCSI_CMD_SET_INTERFACE, 378 .policy = ncsi_genl_policy, 379 .doit = ncsi_set_interface_nl, 380 .flags = GENL_ADMIN_PERM, 381 }, 382 { 383 .cmd = NCSI_CMD_CLEAR_INTERFACE, 384 .policy = ncsi_genl_policy, 385 .doit = ncsi_clear_interface_nl, 386 .flags = GENL_ADMIN_PERM, 387 }, 388 }; 389 390 static struct genl_family ncsi_genl_family __ro_after_init = { 391 .name = "NCSI", 392 .version = 0, 393 .maxattr = NCSI_ATTR_MAX, 394 .module = THIS_MODULE, 395 .ops = ncsi_ops, 396 .n_ops = ARRAY_SIZE(ncsi_ops), 397 }; 398 399 int ncsi_init_netlink(struct net_device *dev) 400 { 401 int rc; 402 403 rc = genl_register_family(&ncsi_genl_family); 404 if (rc) 405 netdev_err(dev, "ncsi: failed to register netlink family\n"); 406 407 return rc; 408 } 409 410 int ncsi_unregister_netlink(struct net_device *dev) 411 { 412 int rc; 413 414 rc = genl_unregister_family(&ncsi_genl_family); 415 if (rc) 416 netdev_err(dev, "ncsi: failed to unregister netlink family\n"); 417 418 return rc; 419 } 420