2
0

swconfig.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929
  1. /*
  2. * swconfig.c: Switch configuration API
  3. *
  4. * Copyright (C) 2008 Felix Fietkau <[email protected]>
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version 2
  9. * of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. */
  16. #include <linux/types.h>
  17. #include <linux/module.h>
  18. #include <linux/init.h>
  19. #include <linux/list.h>
  20. #include <linux/if.h>
  21. #include <linux/if_ether.h>
  22. #include <linux/capability.h>
  23. #include <linux/skbuff.h>
  24. #include <linux/switch.h>
  25. //#define DEBUG 1
  26. #ifdef DEBUG
  27. #define DPRINTF(format, ...) printk("%s: " format, __func__, ##__VA_ARGS__)
  28. #else
  29. #define DPRINTF(...) do {} while(0)
  30. #endif
  31. MODULE_AUTHOR("Felix Fietkau <[email protected]>");
  32. MODULE_LICENSE("GPL");
  33. static int swdev_id = 0;
  34. static struct list_head swdevs;
  35. static spinlock_t swdevs_lock = SPIN_LOCK_UNLOCKED;
  36. struct swconfig_callback;
  37. struct swconfig_callback
  38. {
  39. struct sk_buff *msg;
  40. struct genlmsghdr *hdr;
  41. struct genl_info *info;
  42. int cmd;
  43. /* callback for filling in the message data */
  44. int (*fill)(struct swconfig_callback *cb, void *arg);
  45. /* callback for closing the message before sending it */
  46. int (*close)(struct swconfig_callback *cb, void *arg);
  47. struct nlattr *nest[4];
  48. int args[4];
  49. };
  50. /* defaults */
  51. static int
  52. swconfig_get_vlan_ports(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
  53. {
  54. int ret;
  55. if (val->port_vlan >= dev->vlans)
  56. return -EINVAL;
  57. if (!dev->ops->get_vlan_ports)
  58. return -EOPNOTSUPP;
  59. ret = dev->ops->get_vlan_ports(dev, val);
  60. return ret;
  61. }
  62. static int
  63. swconfig_set_vlan_ports(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
  64. {
  65. struct switch_port *ports = val->value.ports;
  66. const struct switch_dev_ops *ops = dev->ops;
  67. int i;
  68. if (val->port_vlan >= dev->vlans)
  69. return -EINVAL;
  70. /* validate ports */
  71. if (val->len > dev->ports)
  72. return -EINVAL;
  73. if (!ops->set_vlan_ports)
  74. return -EOPNOTSUPP;
  75. for (i = 0; i < val->len; i++) {
  76. if (ports[i].id >= dev->ports)
  77. return -EINVAL;
  78. if (ops->set_port_pvid &&
  79. !(ports[i].flags & (1 << SWITCH_PORT_FLAG_TAGGED)))
  80. ops->set_port_pvid(dev, ports[i].id, val->port_vlan);
  81. }
  82. return ops->set_vlan_ports(dev, val);
  83. }
  84. static int
  85. swconfig_set_pvid(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
  86. {
  87. if (val->port_vlan >= dev->ports)
  88. return -EINVAL;
  89. if (!dev->ops->set_port_pvid)
  90. return -EOPNOTSUPP;
  91. return dev->ops->set_port_pvid(dev, val->port_vlan, val->value.i);
  92. }
  93. static int
  94. swconfig_get_pvid(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
  95. {
  96. if (val->port_vlan >= dev->ports)
  97. return -EINVAL;
  98. if (!dev->ops->get_port_pvid)
  99. return -EOPNOTSUPP;
  100. return dev->ops->get_port_pvid(dev, val->port_vlan, &val->value.i);
  101. }
  102. static int
  103. swconfig_apply_config(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
  104. {
  105. /* don't complain if not supported by the switch driver */
  106. if (!dev->ops->apply_config)
  107. return 0;
  108. return dev->ops->apply_config(dev);
  109. }
  110. static int
  111. swconfig_reset_switch(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
  112. {
  113. /* don't complain if not supported by the switch driver */
  114. if (!dev->ops->reset_switch)
  115. return 0;
  116. return dev->ops->reset_switch(dev);
  117. }
  118. enum global_defaults {
  119. GLOBAL_APPLY,
  120. GLOBAL_RESET,
  121. };
  122. enum vlan_defaults {
  123. VLAN_PORTS,
  124. };
  125. enum port_defaults {
  126. PORT_PVID,
  127. };
  128. static struct switch_attr default_global[] = {
  129. [GLOBAL_APPLY] = {
  130. .type = SWITCH_TYPE_NOVAL,
  131. .name = "apply",
  132. .description = "Activate changes in the hardware",
  133. .set = swconfig_apply_config,
  134. },
  135. [GLOBAL_RESET] = {
  136. .type = SWITCH_TYPE_NOVAL,
  137. .name = "reset",
  138. .description = "Reset the switch",
  139. .set = swconfig_reset_switch,
  140. }
  141. };
  142. static struct switch_attr default_port[] = {
  143. [PORT_PVID] = {
  144. .type = SWITCH_TYPE_INT,
  145. .name = "pvid",
  146. .description = "Primary VLAN ID",
  147. .set = swconfig_set_pvid,
  148. .get = swconfig_get_pvid,
  149. }
  150. };
  151. static struct switch_attr default_vlan[] = {
  152. [VLAN_PORTS] = {
  153. .type = SWITCH_TYPE_PORTS,
  154. .name = "ports",
  155. .description = "VLAN port mapping",
  156. .set = swconfig_set_vlan_ports,
  157. .get = swconfig_get_vlan_ports,
  158. },
  159. };
  160. static void swconfig_defaults_init(struct switch_dev *dev)
  161. {
  162. const struct switch_dev_ops *ops = dev->ops;
  163. dev->def_global = 0;
  164. dev->def_vlan = 0;
  165. dev->def_port = 0;
  166. if (ops->get_vlan_ports || ops->set_vlan_ports)
  167. set_bit(VLAN_PORTS, &dev->def_vlan);
  168. if (ops->get_port_pvid || ops->set_port_pvid)
  169. set_bit(PORT_PVID, &dev->def_port);
  170. /* always present, can be no-op */
  171. set_bit(GLOBAL_APPLY, &dev->def_global);
  172. set_bit(GLOBAL_RESET, &dev->def_global);
  173. }
  174. static struct genl_family switch_fam = {
  175. .id = GENL_ID_GENERATE,
  176. .name = "switch",
  177. .hdrsize = 0,
  178. .version = 1,
  179. .maxattr = SWITCH_ATTR_MAX,
  180. };
  181. static const struct nla_policy switch_policy[SWITCH_ATTR_MAX+1] = {
  182. [SWITCH_ATTR_ID] = { .type = NLA_U32 },
  183. [SWITCH_ATTR_OP_ID] = { .type = NLA_U32 },
  184. [SWITCH_ATTR_OP_PORT] = { .type = NLA_U32 },
  185. [SWITCH_ATTR_OP_VLAN] = { .type = NLA_U32 },
  186. [SWITCH_ATTR_OP_VALUE_INT] = { .type = NLA_U32 },
  187. [SWITCH_ATTR_OP_VALUE_STR] = { .type = NLA_NUL_STRING },
  188. [SWITCH_ATTR_OP_VALUE_PORTS] = { .type = NLA_NESTED },
  189. [SWITCH_ATTR_TYPE] = { .type = NLA_U32 },
  190. };
  191. static const struct nla_policy port_policy[SWITCH_PORT_ATTR_MAX+1] = {
  192. [SWITCH_PORT_ID] = { .type = NLA_U32 },
  193. [SWITCH_PORT_FLAG_TAGGED] = { .type = NLA_FLAG },
  194. };
  195. static inline void
  196. swconfig_lock(void)
  197. {
  198. spin_lock(&swdevs_lock);
  199. }
  200. static inline void
  201. swconfig_unlock(void)
  202. {
  203. spin_unlock(&swdevs_lock);
  204. }
  205. static struct switch_dev *
  206. swconfig_get_dev(struct genl_info *info)
  207. {
  208. struct switch_dev *dev = NULL;
  209. struct switch_dev *p;
  210. int id;
  211. if (!info->attrs[SWITCH_ATTR_ID])
  212. goto done;
  213. id = nla_get_u32(info->attrs[SWITCH_ATTR_ID]);
  214. swconfig_lock();
  215. list_for_each_entry(p, &swdevs, dev_list) {
  216. if (id != p->id)
  217. continue;
  218. dev = p;
  219. break;
  220. }
  221. if (dev)
  222. spin_lock(&dev->lock);
  223. else
  224. DPRINTF("device %d not found\n", id);
  225. swconfig_unlock();
  226. done:
  227. return dev;
  228. }
  229. static inline void
  230. swconfig_put_dev(struct switch_dev *dev)
  231. {
  232. spin_unlock(&dev->lock);
  233. }
  234. static int
  235. swconfig_dump_attr(struct swconfig_callback *cb, void *arg)
  236. {
  237. struct switch_attr *op = arg;
  238. struct genl_info *info = cb->info;
  239. struct sk_buff *msg = cb->msg;
  240. int id = cb->args[0];
  241. void *hdr;
  242. hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq, &switch_fam,
  243. NLM_F_MULTI, SWITCH_CMD_NEW_ATTR);
  244. if (IS_ERR(hdr))
  245. return -1;
  246. NLA_PUT_U32(msg, SWITCH_ATTR_OP_ID, id);
  247. NLA_PUT_U32(msg, SWITCH_ATTR_OP_TYPE, op->type);
  248. NLA_PUT_STRING(msg, SWITCH_ATTR_OP_NAME, op->name);
  249. if (op->description)
  250. NLA_PUT_STRING(msg, SWITCH_ATTR_OP_DESCRIPTION,
  251. op->description);
  252. return genlmsg_end(msg, hdr);
  253. nla_put_failure:
  254. genlmsg_cancel(msg, hdr);
  255. return -EMSGSIZE;
  256. }
  257. /* spread multipart messages across multiple message buffers */
  258. static int
  259. swconfig_send_multipart(struct swconfig_callback *cb, void *arg)
  260. {
  261. struct genl_info *info = cb->info;
  262. int restart = 0;
  263. int err;
  264. do {
  265. if (!cb->msg) {
  266. cb->msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
  267. if (cb->msg == NULL)
  268. goto error;
  269. }
  270. if (!(cb->fill(cb, arg) < 0))
  271. break;
  272. /* fill failed, check if this was already the second attempt */
  273. if (restart)
  274. goto error;
  275. /* try again in a new message, send the current one */
  276. restart = 1;
  277. if (cb->close) {
  278. if (cb->close(cb, arg) < 0)
  279. goto error;
  280. }
  281. err = genlmsg_reply(cb->msg, info);
  282. cb->msg = NULL;
  283. if (err < 0)
  284. goto error;
  285. } while (restart);
  286. return 0;
  287. error:
  288. if (cb->msg)
  289. nlmsg_free(cb->msg);
  290. return -1;
  291. }
  292. static int
  293. swconfig_list_attrs(struct sk_buff *skb, struct genl_info *info)
  294. {
  295. struct genlmsghdr *hdr = nlmsg_data(info->nlhdr);
  296. const struct switch_attrlist *alist;
  297. struct switch_dev *dev;
  298. struct swconfig_callback cb;
  299. int err = -EINVAL;
  300. int i;
  301. /* defaults */
  302. struct switch_attr *def_list;
  303. unsigned long *def_active;
  304. int n_def;
  305. dev = swconfig_get_dev(info);
  306. if (!dev)
  307. return -EINVAL;
  308. switch(hdr->cmd) {
  309. case SWITCH_CMD_LIST_GLOBAL:
  310. alist = &dev->ops->attr_global;
  311. def_list = default_global;
  312. def_active = &dev->def_global;
  313. n_def = ARRAY_SIZE(default_global);
  314. break;
  315. case SWITCH_CMD_LIST_VLAN:
  316. alist = &dev->ops->attr_vlan;
  317. def_list = default_vlan;
  318. def_active = &dev->def_vlan;
  319. n_def = ARRAY_SIZE(default_vlan);
  320. break;
  321. case SWITCH_CMD_LIST_PORT:
  322. alist = &dev->ops->attr_port;
  323. def_list = default_port;
  324. def_active = &dev->def_port;
  325. n_def = ARRAY_SIZE(default_port);
  326. break;
  327. default:
  328. WARN_ON(1);
  329. goto out;
  330. }
  331. memset(&cb, 0, sizeof(cb));
  332. cb.info = info;
  333. cb.fill = swconfig_dump_attr;
  334. for (i = 0; i < alist->n_attr; i++) {
  335. if (alist->attr[i].disabled)
  336. continue;
  337. cb.args[0] = i;
  338. err = swconfig_send_multipart(&cb, (void *) &alist->attr[i]);
  339. if (err < 0)
  340. goto error;
  341. }
  342. /* defaults */
  343. for (i = 0; i < n_def; i++) {
  344. if (!test_bit(i, def_active))
  345. continue;
  346. cb.args[0] = SWITCH_ATTR_DEFAULTS_OFFSET + i;
  347. err = swconfig_send_multipart(&cb, (void *) &def_list[i]);
  348. if (err < 0)
  349. goto error;
  350. }
  351. swconfig_put_dev(dev);
  352. if (!cb.msg)
  353. return 0;
  354. return genlmsg_reply(cb.msg, info);
  355. error:
  356. if (cb.msg)
  357. nlmsg_free(cb.msg);
  358. out:
  359. swconfig_put_dev(dev);
  360. return err;
  361. }
  362. static const struct switch_attr *
  363. swconfig_lookup_attr(struct switch_dev *dev, struct genl_info *info,
  364. struct switch_val *val)
  365. {
  366. struct genlmsghdr *hdr = nlmsg_data(info->nlhdr);
  367. const struct switch_attrlist *alist;
  368. const struct switch_attr *attr = NULL;
  369. int attr_id;
  370. /* defaults */
  371. struct switch_attr *def_list;
  372. unsigned long *def_active;
  373. int n_def;
  374. if (!info->attrs[SWITCH_ATTR_OP_ID])
  375. goto done;
  376. switch(hdr->cmd) {
  377. case SWITCH_CMD_SET_GLOBAL:
  378. case SWITCH_CMD_GET_GLOBAL:
  379. alist = &dev->ops->attr_global;
  380. def_list = default_global;
  381. def_active = &dev->def_global;
  382. n_def = ARRAY_SIZE(default_global);
  383. break;
  384. case SWITCH_CMD_SET_VLAN:
  385. case SWITCH_CMD_GET_VLAN:
  386. alist = &dev->ops->attr_vlan;
  387. def_list = default_vlan;
  388. def_active = &dev->def_vlan;
  389. n_def = ARRAY_SIZE(default_vlan);
  390. if (!info->attrs[SWITCH_ATTR_OP_VLAN])
  391. goto done;
  392. val->port_vlan = nla_get_u32(info->attrs[SWITCH_ATTR_OP_VLAN]);
  393. if (val->port_vlan >= dev->vlans)
  394. goto done;
  395. break;
  396. case SWITCH_CMD_SET_PORT:
  397. case SWITCH_CMD_GET_PORT:
  398. alist = &dev->ops->attr_port;
  399. def_list = default_port;
  400. def_active = &dev->def_port;
  401. n_def = ARRAY_SIZE(default_port);
  402. if (!info->attrs[SWITCH_ATTR_OP_PORT])
  403. goto done;
  404. val->port_vlan = nla_get_u32(info->attrs[SWITCH_ATTR_OP_PORT]);
  405. if (val->port_vlan >= dev->ports)
  406. goto done;
  407. break;
  408. default:
  409. WARN_ON(1);
  410. goto done;
  411. }
  412. if (!alist)
  413. goto done;
  414. attr_id = nla_get_u32(info->attrs[SWITCH_ATTR_OP_ID]);
  415. if (attr_id >= SWITCH_ATTR_DEFAULTS_OFFSET) {
  416. attr_id -= SWITCH_ATTR_DEFAULTS_OFFSET;
  417. if (attr_id >= n_def)
  418. goto done;
  419. if (!test_bit(attr_id, def_active))
  420. goto done;
  421. attr = &def_list[attr_id];
  422. } else {
  423. if (attr_id >= alist->n_attr)
  424. goto done;
  425. attr = &alist->attr[attr_id];
  426. }
  427. if (attr->disabled)
  428. attr = NULL;
  429. done:
  430. if (!attr)
  431. DPRINTF("attribute lookup failed\n");
  432. val->attr = attr;
  433. return attr;
  434. }
  435. static int
  436. swconfig_parse_ports(struct sk_buff *msg, struct nlattr *head,
  437. struct switch_val *val, int max)
  438. {
  439. struct nlattr *nla;
  440. int rem;
  441. val->len = 0;
  442. nla_for_each_nested(nla, head, rem) {
  443. struct nlattr *tb[SWITCH_PORT_ATTR_MAX+1];
  444. struct switch_port *port = &val->value.ports[val->len];
  445. if (val->len >= max)
  446. return -EINVAL;
  447. if (nla_parse_nested(tb, SWITCH_PORT_ATTR_MAX, nla,
  448. port_policy))
  449. return -EINVAL;
  450. if (!tb[SWITCH_PORT_ID])
  451. return -EINVAL;
  452. port->id = nla_get_u32(tb[SWITCH_PORT_ID]);
  453. if (tb[SWITCH_PORT_FLAG_TAGGED])
  454. port->flags |= (1 << SWITCH_PORT_FLAG_TAGGED);
  455. val->len++;
  456. }
  457. return 0;
  458. }
  459. static int
  460. swconfig_set_attr(struct sk_buff *skb, struct genl_info *info)
  461. {
  462. const struct switch_attr *attr;
  463. struct switch_dev *dev;
  464. struct switch_val val;
  465. int err = -EINVAL;
  466. dev = swconfig_get_dev(info);
  467. if (!dev)
  468. return -EINVAL;
  469. memset(&val, 0, sizeof(val));
  470. attr = swconfig_lookup_attr(dev, info, &val);
  471. if (!attr || !attr->set)
  472. goto error;
  473. val.attr = attr;
  474. switch(attr->type) {
  475. case SWITCH_TYPE_NOVAL:
  476. break;
  477. case SWITCH_TYPE_INT:
  478. if (!info->attrs[SWITCH_ATTR_OP_VALUE_INT])
  479. goto error;
  480. val.value.i =
  481. nla_get_u32(info->attrs[SWITCH_ATTR_OP_VALUE_INT]);
  482. break;
  483. case SWITCH_TYPE_STRING:
  484. if (!info->attrs[SWITCH_ATTR_OP_VALUE_STR])
  485. goto error;
  486. val.value.s =
  487. nla_data(info->attrs[SWITCH_ATTR_OP_VALUE_STR]);
  488. break;
  489. case SWITCH_TYPE_PORTS:
  490. val.value.ports = dev->portbuf;
  491. memset(dev->portbuf, 0,
  492. sizeof(struct switch_port) * dev->ports);
  493. /* TODO: implement multipart? */
  494. if (info->attrs[SWITCH_ATTR_OP_VALUE_PORTS]) {
  495. err = swconfig_parse_ports(skb,
  496. info->attrs[SWITCH_ATTR_OP_VALUE_PORTS], &val, dev->ports);
  497. if (err < 0)
  498. goto error;
  499. } else {
  500. val.len = 0;
  501. err = 0;
  502. }
  503. break;
  504. default:
  505. goto error;
  506. }
  507. err = attr->set(dev, attr, &val);
  508. error:
  509. swconfig_put_dev(dev);
  510. return err;
  511. }
  512. static int
  513. swconfig_close_portlist(struct swconfig_callback *cb, void *arg)
  514. {
  515. if (cb->nest[0])
  516. nla_nest_end(cb->msg, cb->nest[0]);
  517. return 0;
  518. }
  519. static int
  520. swconfig_send_port(struct swconfig_callback *cb, void *arg)
  521. {
  522. const struct switch_port *port = arg;
  523. struct nlattr *p = NULL;
  524. if (!cb->nest[0]) {
  525. cb->nest[0] = nla_nest_start(cb->msg, cb->cmd);
  526. if (!cb->nest[0])
  527. return -1;
  528. }
  529. p = nla_nest_start(cb->msg, SWITCH_ATTR_PORT);
  530. if (!p)
  531. goto error;
  532. NLA_PUT_U32(cb->msg, SWITCH_PORT_ID, port->id);
  533. if (port->flags & (1 << SWITCH_PORT_FLAG_TAGGED))
  534. NLA_PUT_FLAG(cb->msg, SWITCH_PORT_FLAG_TAGGED);
  535. nla_nest_end(cb->msg, p);
  536. return 0;
  537. nla_put_failure:
  538. nla_nest_cancel(cb->msg, p);
  539. error:
  540. nla_nest_cancel(cb->msg, cb->nest[0]);
  541. return -1;
  542. }
  543. static int
  544. swconfig_send_ports(struct sk_buff **msg, struct genl_info *info, int attr,
  545. const struct switch_val *val)
  546. {
  547. struct swconfig_callback cb;
  548. int err = 0;
  549. int i;
  550. if (!val->value.ports)
  551. return -EINVAL;
  552. memset(&cb, 0, sizeof(cb));
  553. cb.cmd = attr;
  554. cb.msg = *msg;
  555. cb.info = info;
  556. cb.fill = swconfig_send_port;
  557. cb.close = swconfig_close_portlist;
  558. cb.nest[0] = nla_nest_start(cb.msg, cb.cmd);
  559. for (i = 0; i < val->len; i++) {
  560. err = swconfig_send_multipart(&cb, &val->value.ports[i]);
  561. if (err)
  562. goto done;
  563. }
  564. err = val->len;
  565. swconfig_close_portlist(&cb, NULL);
  566. *msg = cb.msg;
  567. done:
  568. return err;
  569. }
  570. static int
  571. swconfig_get_attr(struct sk_buff *skb, struct genl_info *info)
  572. {
  573. struct genlmsghdr *hdr = nlmsg_data(info->nlhdr);
  574. const struct switch_attr *attr;
  575. struct switch_dev *dev;
  576. struct sk_buff *msg = NULL;
  577. struct switch_val val;
  578. int err = -EINVAL;
  579. int cmd = hdr->cmd;
  580. dev = swconfig_get_dev(info);
  581. if (!dev)
  582. return -EINVAL;
  583. memset(&val, 0, sizeof(val));
  584. attr = swconfig_lookup_attr(dev, info, &val);
  585. if (!attr || !attr->get)
  586. goto error;
  587. if (attr->type == SWITCH_TYPE_PORTS) {
  588. val.value.ports = dev->portbuf;
  589. memset(dev->portbuf, 0,
  590. sizeof(struct switch_port) * dev->ports);
  591. }
  592. err = attr->get(dev, attr, &val);
  593. if (err)
  594. goto error;
  595. msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
  596. if (!msg)
  597. goto error;
  598. hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq, &switch_fam,
  599. 0, cmd);
  600. if (IS_ERR(hdr))
  601. goto nla_put_failure;
  602. switch(attr->type) {
  603. case SWITCH_TYPE_INT:
  604. NLA_PUT_U32(msg, SWITCH_ATTR_OP_VALUE_INT, val.value.i);
  605. break;
  606. case SWITCH_TYPE_STRING:
  607. NLA_PUT_STRING(msg, SWITCH_ATTR_OP_VALUE_STR, val.value.s);
  608. break;
  609. case SWITCH_TYPE_PORTS:
  610. err = swconfig_send_ports(&msg, info,
  611. SWITCH_ATTR_OP_VALUE_PORTS, &val);
  612. if (err < 0)
  613. goto nla_put_failure;
  614. break;
  615. default:
  616. DPRINTF("invalid type in attribute\n");
  617. err = -EINVAL;
  618. goto error;
  619. }
  620. err = genlmsg_end(msg, hdr);
  621. if (err < 0)
  622. goto nla_put_failure;
  623. swconfig_put_dev(dev);
  624. return genlmsg_reply(msg, info);
  625. nla_put_failure:
  626. if (msg)
  627. nlmsg_free(msg);
  628. error:
  629. swconfig_put_dev(dev);
  630. if (!err)
  631. err = -ENOMEM;
  632. return err;
  633. }
  634. static int
  635. swconfig_send_switch(struct sk_buff *msg, u32 pid, u32 seq, int flags,
  636. const struct switch_dev *dev)
  637. {
  638. void *hdr;
  639. hdr = genlmsg_put(msg, pid, seq, &switch_fam, flags,
  640. SWITCH_CMD_NEW_ATTR);
  641. if (IS_ERR(hdr))
  642. return -1;
  643. NLA_PUT_U32(msg, SWITCH_ATTR_ID, dev->id);
  644. NLA_PUT_STRING(msg, SWITCH_ATTR_NAME, dev->name);
  645. NLA_PUT_STRING(msg, SWITCH_ATTR_DEV_NAME, dev->devname);
  646. NLA_PUT_U32(msg, SWITCH_ATTR_VLANS, dev->vlans);
  647. NLA_PUT_U32(msg, SWITCH_ATTR_PORTS, dev->ports);
  648. NLA_PUT_U32(msg, SWITCH_ATTR_CPU_PORT, dev->cpu_port);
  649. return genlmsg_end(msg, hdr);
  650. nla_put_failure:
  651. genlmsg_cancel(msg, hdr);
  652. return -EMSGSIZE;
  653. }
  654. static int swconfig_dump_switches(struct sk_buff *skb,
  655. struct netlink_callback *cb)
  656. {
  657. struct switch_dev *dev;
  658. int start = cb->args[0];
  659. int idx = 0;
  660. swconfig_lock();
  661. list_for_each_entry(dev, &swdevs, dev_list) {
  662. if (++idx <= start)
  663. continue;
  664. if (swconfig_send_switch(skb, NETLINK_CB(cb->skb).pid,
  665. cb->nlh->nlmsg_seq, NLM_F_MULTI,
  666. dev) < 0)
  667. break;
  668. }
  669. swconfig_unlock();
  670. cb->args[0] = idx;
  671. return skb->len;
  672. }
  673. static int
  674. swconfig_done(struct netlink_callback *cb)
  675. {
  676. return 0;
  677. }
  678. static struct genl_ops swconfig_ops[] = {
  679. {
  680. .cmd = SWITCH_CMD_LIST_GLOBAL,
  681. .doit = swconfig_list_attrs,
  682. .policy = switch_policy,
  683. },
  684. {
  685. .cmd = SWITCH_CMD_LIST_VLAN,
  686. .doit = swconfig_list_attrs,
  687. .policy = switch_policy,
  688. },
  689. {
  690. .cmd = SWITCH_CMD_LIST_PORT,
  691. .doit = swconfig_list_attrs,
  692. .policy = switch_policy,
  693. },
  694. {
  695. .cmd = SWITCH_CMD_GET_GLOBAL,
  696. .doit = swconfig_get_attr,
  697. .policy = switch_policy,
  698. },
  699. {
  700. .cmd = SWITCH_CMD_GET_VLAN,
  701. .doit = swconfig_get_attr,
  702. .policy = switch_policy,
  703. },
  704. {
  705. .cmd = SWITCH_CMD_GET_PORT,
  706. .doit = swconfig_get_attr,
  707. .policy = switch_policy,
  708. },
  709. {
  710. .cmd = SWITCH_CMD_SET_GLOBAL,
  711. .doit = swconfig_set_attr,
  712. .policy = switch_policy,
  713. },
  714. {
  715. .cmd = SWITCH_CMD_SET_VLAN,
  716. .doit = swconfig_set_attr,
  717. .policy = switch_policy,
  718. },
  719. {
  720. .cmd = SWITCH_CMD_SET_PORT,
  721. .doit = swconfig_set_attr,
  722. .policy = switch_policy,
  723. },
  724. {
  725. .cmd = SWITCH_CMD_GET_SWITCH,
  726. .dumpit = swconfig_dump_switches,
  727. .policy = switch_policy,
  728. .done = swconfig_done,
  729. }
  730. };
  731. int
  732. register_switch(struct switch_dev *dev, struct net_device *netdev)
  733. {
  734. INIT_LIST_HEAD(&dev->dev_list);
  735. if (netdev) {
  736. dev->netdev = netdev;
  737. if (!dev->devname)
  738. dev->devname = netdev->name;
  739. }
  740. BUG_ON(!dev->devname);
  741. if (dev->ports > 0) {
  742. dev->portbuf = kzalloc(sizeof(struct switch_port) * dev->ports,
  743. GFP_KERNEL);
  744. if (!dev->portbuf)
  745. return -ENOMEM;
  746. }
  747. dev->id = ++swdev_id;
  748. swconfig_defaults_init(dev);
  749. spin_lock_init(&dev->lock);
  750. swconfig_lock();
  751. list_add(&dev->dev_list, &swdevs);
  752. swconfig_unlock();
  753. return 0;
  754. }
  755. EXPORT_SYMBOL_GPL(register_switch);
  756. void
  757. unregister_switch(struct switch_dev *dev)
  758. {
  759. kfree(dev->portbuf);
  760. spin_lock(&dev->lock);
  761. swconfig_lock();
  762. list_del(&dev->dev_list);
  763. swconfig_unlock();
  764. spin_unlock(&dev->lock);
  765. }
  766. EXPORT_SYMBOL_GPL(unregister_switch);
  767. static int __init
  768. swconfig_init(void)
  769. {
  770. int i, err;
  771. INIT_LIST_HEAD(&swdevs);
  772. err = genl_register_family(&switch_fam);
  773. if (err)
  774. return err;
  775. for (i = 0; i < ARRAY_SIZE(swconfig_ops); i++) {
  776. err = genl_register_ops(&switch_fam, &swconfig_ops[i]);
  777. if (err)
  778. goto unregister;
  779. }
  780. return 0;
  781. unregister:
  782. genl_unregister_family(&switch_fam);
  783. return err;
  784. }
  785. static void __exit
  786. swconfig_exit(void)
  787. {
  788. genl_unregister_family(&switch_fam);
  789. }
  790. module_init(swconfig_init);
  791. module_exit(swconfig_exit);