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