0013-net-add-swconfig-support.patch 43 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837
  1. diff -Nur linux-4.1.6.orig/drivers/net/phy/Kconfig linux-4.1.6/drivers/net/phy/Kconfig
  2. --- linux-4.1.6.orig/drivers/net/phy/Kconfig 2015-08-17 05:52:51.000000000 +0200
  3. +++ linux-4.1.6/drivers/net/phy/Kconfig 2015-09-13 20:15:06.381308993 +0200
  4. @@ -12,6 +12,16 @@
  5. if PHYLIB
  6. +config SWCONFIG
  7. + tristate "Switch configuration API"
  8. + ---help---
  9. + Switch configuration API using netlink. This allows
  10. + you to configure the VLAN features of certain switches.
  11. +
  12. +config SWCONFIG_LEDS
  13. + bool "Switch LED trigger support"
  14. + depends on (SWCONFIG && LEDS_TRIGGERS)
  15. +
  16. comment "MII PHY device drivers"
  17. config AT803X_PHY
  18. diff -Nur linux-4.1.6.orig/drivers/net/phy/Makefile linux-4.1.6/drivers/net/phy/Makefile
  19. --- linux-4.1.6.orig/drivers/net/phy/Makefile 2015-08-17 05:52:51.000000000 +0200
  20. +++ linux-4.1.6/drivers/net/phy/Makefile 2015-09-13 20:15:06.381308993 +0200
  21. @@ -3,6 +3,7 @@
  22. libphy-objs := phy.o phy_device.o mdio_bus.o
  23. obj-$(CONFIG_PHYLIB) += libphy.o
  24. +obj-$(CONFIG_SWCONFIG) += swconfig.o
  25. obj-$(CONFIG_MARVELL_PHY) += marvell.o
  26. obj-$(CONFIG_DAVICOM_PHY) += davicom.o
  27. obj-$(CONFIG_CICADA_PHY) += cicada.o
  28. diff -Nur linux-4.1.6.orig/drivers/net/phy/swconfig.c linux-4.1.6/drivers/net/phy/swconfig.c
  29. --- linux-4.1.6.orig/drivers/net/phy/swconfig.c 1970-01-01 01:00:00.000000000 +0100
  30. +++ linux-4.1.6/drivers/net/phy/swconfig.c 2015-09-13 20:14:58.973675262 +0200
  31. @@ -0,0 +1,1153 @@
  32. +/*
  33. + * swconfig.c: Switch configuration API
  34. + *
  35. + * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
  36. + *
  37. + * This program is free software; you can redistribute it and/or
  38. + * modify it under the terms of the GNU General Public License
  39. + * as published by the Free Software Foundation; either version 2
  40. + * of the License, or (at your option) any later version.
  41. + *
  42. + * This program is distributed in the hope that it will be useful,
  43. + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  44. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  45. + * GNU General Public License for more details.
  46. + */
  47. +
  48. +#include <linux/types.h>
  49. +#include <linux/module.h>
  50. +#include <linux/init.h>
  51. +#include <linux/list.h>
  52. +#include <linux/if.h>
  53. +#include <linux/if_ether.h>
  54. +#include <linux/capability.h>
  55. +#include <linux/skbuff.h>
  56. +#include <linux/switch.h>
  57. +#include <linux/of.h>
  58. +#include <linux/version.h>
  59. +
  60. +#define SWCONFIG_DEVNAME "switch%d"
  61. +
  62. +#include "swconfig_leds.c"
  63. +
  64. +MODULE_AUTHOR("Felix Fietkau <nbd@openwrt.org>");
  65. +MODULE_LICENSE("GPL");
  66. +
  67. +static int swdev_id;
  68. +static struct list_head swdevs;
  69. +static DEFINE_SPINLOCK(swdevs_lock);
  70. +struct swconfig_callback;
  71. +
  72. +struct swconfig_callback {
  73. + struct sk_buff *msg;
  74. + struct genlmsghdr *hdr;
  75. + struct genl_info *info;
  76. + int cmd;
  77. +
  78. + /* callback for filling in the message data */
  79. + int (*fill)(struct swconfig_callback *cb, void *arg);
  80. +
  81. + /* callback for closing the message before sending it */
  82. + int (*close)(struct swconfig_callback *cb, void *arg);
  83. +
  84. + struct nlattr *nest[4];
  85. + int args[4];
  86. +};
  87. +
  88. +/* defaults */
  89. +
  90. +static int
  91. +swconfig_get_vlan_ports(struct switch_dev *dev, const struct switch_attr *attr,
  92. + struct switch_val *val)
  93. +{
  94. + int ret;
  95. + if (val->port_vlan >= dev->vlans)
  96. + return -EINVAL;
  97. +
  98. + if (!dev->ops->get_vlan_ports)
  99. + return -EOPNOTSUPP;
  100. +
  101. + ret = dev->ops->get_vlan_ports(dev, val);
  102. + return ret;
  103. +}
  104. +
  105. +static int
  106. +swconfig_set_vlan_ports(struct switch_dev *dev, const struct switch_attr *attr,
  107. + struct switch_val *val)
  108. +{
  109. + struct switch_port *ports = val->value.ports;
  110. + const struct switch_dev_ops *ops = dev->ops;
  111. + int i;
  112. +
  113. + if (val->port_vlan >= dev->vlans)
  114. + return -EINVAL;
  115. +
  116. + /* validate ports */
  117. + if (val->len > dev->ports)
  118. + return -EINVAL;
  119. +
  120. + if (!ops->set_vlan_ports)
  121. + return -EOPNOTSUPP;
  122. +
  123. + for (i = 0; i < val->len; i++) {
  124. + if (ports[i].id >= dev->ports)
  125. + return -EINVAL;
  126. +
  127. + if (ops->set_port_pvid &&
  128. + !(ports[i].flags & (1 << SWITCH_PORT_FLAG_TAGGED)))
  129. + ops->set_port_pvid(dev, ports[i].id, val->port_vlan);
  130. + }
  131. +
  132. + return ops->set_vlan_ports(dev, val);
  133. +}
  134. +
  135. +static int
  136. +swconfig_set_pvid(struct switch_dev *dev, const struct switch_attr *attr,
  137. + struct switch_val *val)
  138. +{
  139. + if (val->port_vlan >= dev->ports)
  140. + return -EINVAL;
  141. +
  142. + if (!dev->ops->set_port_pvid)
  143. + return -EOPNOTSUPP;
  144. +
  145. + return dev->ops->set_port_pvid(dev, val->port_vlan, val->value.i);
  146. +}
  147. +
  148. +static int
  149. +swconfig_get_pvid(struct switch_dev *dev, const struct switch_attr *attr,
  150. + struct switch_val *val)
  151. +{
  152. + if (val->port_vlan >= dev->ports)
  153. + return -EINVAL;
  154. +
  155. + if (!dev->ops->get_port_pvid)
  156. + return -EOPNOTSUPP;
  157. +
  158. + return dev->ops->get_port_pvid(dev, val->port_vlan, &val->value.i);
  159. +}
  160. +
  161. +static const char *
  162. +swconfig_speed_str(enum switch_port_speed speed)
  163. +{
  164. + switch (speed) {
  165. + case SWITCH_PORT_SPEED_10:
  166. + return "10baseT";
  167. + case SWITCH_PORT_SPEED_100:
  168. + return "100baseT";
  169. + case SWITCH_PORT_SPEED_1000:
  170. + return "1000baseT";
  171. + default:
  172. + break;
  173. + }
  174. +
  175. + return "unknown";
  176. +}
  177. +
  178. +static int
  179. +swconfig_get_link(struct switch_dev *dev, const struct switch_attr *attr,
  180. + struct switch_val *val)
  181. +{
  182. + struct switch_port_link link;
  183. + int len;
  184. + int ret;
  185. +
  186. + if (val->port_vlan >= dev->ports)
  187. + return -EINVAL;
  188. +
  189. + if (!dev->ops->get_port_link)
  190. + return -EOPNOTSUPP;
  191. +
  192. + memset(&link, 0, sizeof(link));
  193. + ret = dev->ops->get_port_link(dev, val->port_vlan, &link);
  194. + if (ret)
  195. + return ret;
  196. +
  197. + memset(dev->buf, 0, sizeof(dev->buf));
  198. +
  199. + if (link.link)
  200. + len = snprintf(dev->buf, sizeof(dev->buf),
  201. + "port:%d link:up speed:%s %s-duplex %s%s%s%s%s",
  202. + val->port_vlan,
  203. + swconfig_speed_str(link.speed),
  204. + link.duplex ? "full" : "half",
  205. + link.tx_flow ? "txflow " : "",
  206. + link.rx_flow ? "rxflow " : "",
  207. + link.eee & ADVERTISED_100baseT_Full ? "eee100 " : "",
  208. + link.eee & ADVERTISED_1000baseT_Full ? "eee1000 " : "",
  209. + link.aneg ? "auto" : "");
  210. + else
  211. + len = snprintf(dev->buf, sizeof(dev->buf), "port:%d link:down",
  212. + val->port_vlan);
  213. +
  214. + val->value.s = dev->buf;
  215. + val->len = len;
  216. +
  217. + return 0;
  218. +}
  219. +
  220. +static int
  221. +swconfig_apply_config(struct switch_dev *dev, const struct switch_attr *attr,
  222. + struct switch_val *val)
  223. +{
  224. + /* don't complain if not supported by the switch driver */
  225. + if (!dev->ops->apply_config)
  226. + return 0;
  227. +
  228. + return dev->ops->apply_config(dev);
  229. +}
  230. +
  231. +static int
  232. +swconfig_reset_switch(struct switch_dev *dev, const struct switch_attr *attr,
  233. + struct switch_val *val)
  234. +{
  235. + /* don't complain if not supported by the switch driver */
  236. + if (!dev->ops->reset_switch)
  237. + return 0;
  238. +
  239. + return dev->ops->reset_switch(dev);
  240. +}
  241. +
  242. +enum global_defaults {
  243. + GLOBAL_APPLY,
  244. + GLOBAL_RESET,
  245. +};
  246. +
  247. +enum vlan_defaults {
  248. + VLAN_PORTS,
  249. +};
  250. +
  251. +enum port_defaults {
  252. + PORT_PVID,
  253. + PORT_LINK,
  254. +};
  255. +
  256. +static struct switch_attr default_global[] = {
  257. + [GLOBAL_APPLY] = {
  258. + .type = SWITCH_TYPE_NOVAL,
  259. + .name = "apply",
  260. + .description = "Activate changes in the hardware",
  261. + .set = swconfig_apply_config,
  262. + },
  263. + [GLOBAL_RESET] = {
  264. + .type = SWITCH_TYPE_NOVAL,
  265. + .name = "reset",
  266. + .description = "Reset the switch",
  267. + .set = swconfig_reset_switch,
  268. + }
  269. +};
  270. +
  271. +static struct switch_attr default_port[] = {
  272. + [PORT_PVID] = {
  273. + .type = SWITCH_TYPE_INT,
  274. + .name = "pvid",
  275. + .description = "Primary VLAN ID",
  276. + .set = swconfig_set_pvid,
  277. + .get = swconfig_get_pvid,
  278. + },
  279. + [PORT_LINK] = {
  280. + .type = SWITCH_TYPE_STRING,
  281. + .name = "link",
  282. + .description = "Get port link information",
  283. + .set = NULL,
  284. + .get = swconfig_get_link,
  285. + }
  286. +};
  287. +
  288. +static struct switch_attr default_vlan[] = {
  289. + [VLAN_PORTS] = {
  290. + .type = SWITCH_TYPE_PORTS,
  291. + .name = "ports",
  292. + .description = "VLAN port mapping",
  293. + .set = swconfig_set_vlan_ports,
  294. + .get = swconfig_get_vlan_ports,
  295. + },
  296. +};
  297. +
  298. +static const struct switch_attr *
  299. +swconfig_find_attr_by_name(const struct switch_attrlist *alist,
  300. + const char *name)
  301. +{
  302. + int i;
  303. +
  304. + for (i = 0; i < alist->n_attr; i++)
  305. + if (strcmp(name, alist->attr[i].name) == 0)
  306. + return &alist->attr[i];
  307. +
  308. + return NULL;
  309. +}
  310. +
  311. +static void swconfig_defaults_init(struct switch_dev *dev)
  312. +{
  313. + const struct switch_dev_ops *ops = dev->ops;
  314. +
  315. + dev->def_global = 0;
  316. + dev->def_vlan = 0;
  317. + dev->def_port = 0;
  318. +
  319. + if (ops->get_vlan_ports || ops->set_vlan_ports)
  320. + set_bit(VLAN_PORTS, &dev->def_vlan);
  321. +
  322. + if (ops->get_port_pvid || ops->set_port_pvid)
  323. + set_bit(PORT_PVID, &dev->def_port);
  324. +
  325. + if (ops->get_port_link &&
  326. + !swconfig_find_attr_by_name(&ops->attr_port, "link"))
  327. + set_bit(PORT_LINK, &dev->def_port);
  328. +
  329. + /* always present, can be no-op */
  330. + set_bit(GLOBAL_APPLY, &dev->def_global);
  331. + set_bit(GLOBAL_RESET, &dev->def_global);
  332. +}
  333. +
  334. +
  335. +static struct genl_family switch_fam = {
  336. + .id = GENL_ID_GENERATE,
  337. + .name = "switch",
  338. + .hdrsize = 0,
  339. + .version = 1,
  340. + .maxattr = SWITCH_ATTR_MAX,
  341. +};
  342. +
  343. +static const struct nla_policy switch_policy[SWITCH_ATTR_MAX+1] = {
  344. + [SWITCH_ATTR_ID] = { .type = NLA_U32 },
  345. + [SWITCH_ATTR_OP_ID] = { .type = NLA_U32 },
  346. + [SWITCH_ATTR_OP_PORT] = { .type = NLA_U32 },
  347. + [SWITCH_ATTR_OP_VLAN] = { .type = NLA_U32 },
  348. + [SWITCH_ATTR_OP_VALUE_INT] = { .type = NLA_U32 },
  349. + [SWITCH_ATTR_OP_VALUE_STR] = { .type = NLA_NUL_STRING },
  350. + [SWITCH_ATTR_OP_VALUE_PORTS] = { .type = NLA_NESTED },
  351. + [SWITCH_ATTR_TYPE] = { .type = NLA_U32 },
  352. +};
  353. +
  354. +static const struct nla_policy port_policy[SWITCH_PORT_ATTR_MAX+1] = {
  355. + [SWITCH_PORT_ID] = { .type = NLA_U32 },
  356. + [SWITCH_PORT_FLAG_TAGGED] = { .type = NLA_FLAG },
  357. +};
  358. +
  359. +static inline void
  360. +swconfig_lock(void)
  361. +{
  362. + spin_lock(&swdevs_lock);
  363. +}
  364. +
  365. +static inline void
  366. +swconfig_unlock(void)
  367. +{
  368. + spin_unlock(&swdevs_lock);
  369. +}
  370. +
  371. +static struct switch_dev *
  372. +swconfig_get_dev(struct genl_info *info)
  373. +{
  374. + struct switch_dev *dev = NULL;
  375. + struct switch_dev *p;
  376. + int id;
  377. +
  378. + if (!info->attrs[SWITCH_ATTR_ID])
  379. + goto done;
  380. +
  381. + id = nla_get_u32(info->attrs[SWITCH_ATTR_ID]);
  382. + swconfig_lock();
  383. + list_for_each_entry(p, &swdevs, dev_list) {
  384. + if (id != p->id)
  385. + continue;
  386. +
  387. + dev = p;
  388. + break;
  389. + }
  390. + if (dev)
  391. + mutex_lock(&dev->sw_mutex);
  392. + else
  393. + pr_debug("device %d not found\n", id);
  394. + swconfig_unlock();
  395. +done:
  396. + return dev;
  397. +}
  398. +
  399. +static inline void
  400. +swconfig_put_dev(struct switch_dev *dev)
  401. +{
  402. + mutex_unlock(&dev->sw_mutex);
  403. +}
  404. +
  405. +static int
  406. +swconfig_dump_attr(struct swconfig_callback *cb, void *arg)
  407. +{
  408. + struct switch_attr *op = arg;
  409. + struct genl_info *info = cb->info;
  410. + struct sk_buff *msg = cb->msg;
  411. + int id = cb->args[0];
  412. + void *hdr;
  413. +
  414. + hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq, &switch_fam,
  415. + NLM_F_MULTI, SWITCH_CMD_NEW_ATTR);
  416. + if (IS_ERR(hdr))
  417. + return -1;
  418. +
  419. + if (nla_put_u32(msg, SWITCH_ATTR_OP_ID, id))
  420. + goto nla_put_failure;
  421. + if (nla_put_u32(msg, SWITCH_ATTR_OP_TYPE, op->type))
  422. + goto nla_put_failure;
  423. + if (nla_put_string(msg, SWITCH_ATTR_OP_NAME, op->name))
  424. + goto nla_put_failure;
  425. + if (op->description)
  426. + if (nla_put_string(msg, SWITCH_ATTR_OP_DESCRIPTION,
  427. + op->description))
  428. + goto nla_put_failure;
  429. +
  430. + genlmsg_end(msg, hdr);
  431. + return msg->len;
  432. +nla_put_failure:
  433. + genlmsg_cancel(msg, hdr);
  434. + return -EMSGSIZE;
  435. +}
  436. +
  437. +/* spread multipart messages across multiple message buffers */
  438. +static int
  439. +swconfig_send_multipart(struct swconfig_callback *cb, void *arg)
  440. +{
  441. + struct genl_info *info = cb->info;
  442. + int restart = 0;
  443. + int err;
  444. +
  445. + do {
  446. + if (!cb->msg) {
  447. + cb->msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
  448. + if (cb->msg == NULL)
  449. + goto error;
  450. + }
  451. +
  452. + if (!(cb->fill(cb, arg) < 0))
  453. + break;
  454. +
  455. + /* fill failed, check if this was already the second attempt */
  456. + if (restart)
  457. + goto error;
  458. +
  459. + /* try again in a new message, send the current one */
  460. + restart = 1;
  461. + if (cb->close) {
  462. + if (cb->close(cb, arg) < 0)
  463. + goto error;
  464. + }
  465. + err = genlmsg_reply(cb->msg, info);
  466. + cb->msg = NULL;
  467. + if (err < 0)
  468. + goto error;
  469. +
  470. + } while (restart);
  471. +
  472. + return 0;
  473. +
  474. +error:
  475. + if (cb->msg)
  476. + nlmsg_free(cb->msg);
  477. + return -1;
  478. +}
  479. +
  480. +static int
  481. +swconfig_list_attrs(struct sk_buff *skb, struct genl_info *info)
  482. +{
  483. + struct genlmsghdr *hdr = nlmsg_data(info->nlhdr);
  484. + const struct switch_attrlist *alist;
  485. + struct switch_dev *dev;
  486. + struct swconfig_callback cb;
  487. + int err = -EINVAL;
  488. + int i;
  489. +
  490. + /* defaults */
  491. + struct switch_attr *def_list;
  492. + unsigned long *def_active;
  493. + int n_def;
  494. +
  495. + dev = swconfig_get_dev(info);
  496. + if (!dev)
  497. + return -EINVAL;
  498. +
  499. + switch (hdr->cmd) {
  500. + case SWITCH_CMD_LIST_GLOBAL:
  501. + alist = &dev->ops->attr_global;
  502. + def_list = default_global;
  503. + def_active = &dev->def_global;
  504. + n_def = ARRAY_SIZE(default_global);
  505. + break;
  506. + case SWITCH_CMD_LIST_VLAN:
  507. + alist = &dev->ops->attr_vlan;
  508. + def_list = default_vlan;
  509. + def_active = &dev->def_vlan;
  510. + n_def = ARRAY_SIZE(default_vlan);
  511. + break;
  512. + case SWITCH_CMD_LIST_PORT:
  513. + alist = &dev->ops->attr_port;
  514. + def_list = default_port;
  515. + def_active = &dev->def_port;
  516. + n_def = ARRAY_SIZE(default_port);
  517. + break;
  518. + default:
  519. + WARN_ON(1);
  520. + goto out;
  521. + }
  522. +
  523. + memset(&cb, 0, sizeof(cb));
  524. + cb.info = info;
  525. + cb.fill = swconfig_dump_attr;
  526. + for (i = 0; i < alist->n_attr; i++) {
  527. + if (alist->attr[i].disabled)
  528. + continue;
  529. + cb.args[0] = i;
  530. + err = swconfig_send_multipart(&cb, (void *) &alist->attr[i]);
  531. + if (err < 0)
  532. + goto error;
  533. + }
  534. +
  535. + /* defaults */
  536. + for (i = 0; i < n_def; i++) {
  537. + if (!test_bit(i, def_active))
  538. + continue;
  539. + cb.args[0] = SWITCH_ATTR_DEFAULTS_OFFSET + i;
  540. + err = swconfig_send_multipart(&cb, (void *) &def_list[i]);
  541. + if (err < 0)
  542. + goto error;
  543. + }
  544. + swconfig_put_dev(dev);
  545. +
  546. + if (!cb.msg)
  547. + return 0;
  548. +
  549. + return genlmsg_reply(cb.msg, info);
  550. +
  551. +error:
  552. + if (cb.msg)
  553. + nlmsg_free(cb.msg);
  554. +out:
  555. + swconfig_put_dev(dev);
  556. + return err;
  557. +}
  558. +
  559. +static const struct switch_attr *
  560. +swconfig_lookup_attr(struct switch_dev *dev, struct genl_info *info,
  561. + struct switch_val *val)
  562. +{
  563. + struct genlmsghdr *hdr = nlmsg_data(info->nlhdr);
  564. + const struct switch_attrlist *alist;
  565. + const struct switch_attr *attr = NULL;
  566. + int attr_id;
  567. +
  568. + /* defaults */
  569. + struct switch_attr *def_list;
  570. + unsigned long *def_active;
  571. + int n_def;
  572. +
  573. + if (!info->attrs[SWITCH_ATTR_OP_ID])
  574. + goto done;
  575. +
  576. + switch (hdr->cmd) {
  577. + case SWITCH_CMD_SET_GLOBAL:
  578. + case SWITCH_CMD_GET_GLOBAL:
  579. + alist = &dev->ops->attr_global;
  580. + def_list = default_global;
  581. + def_active = &dev->def_global;
  582. + n_def = ARRAY_SIZE(default_global);
  583. + break;
  584. + case SWITCH_CMD_SET_VLAN:
  585. + case SWITCH_CMD_GET_VLAN:
  586. + alist = &dev->ops->attr_vlan;
  587. + def_list = default_vlan;
  588. + def_active = &dev->def_vlan;
  589. + n_def = ARRAY_SIZE(default_vlan);
  590. + if (!info->attrs[SWITCH_ATTR_OP_VLAN])
  591. + goto done;
  592. + val->port_vlan = nla_get_u32(info->attrs[SWITCH_ATTR_OP_VLAN]);
  593. + if (val->port_vlan >= dev->vlans)
  594. + goto done;
  595. + break;
  596. + case SWITCH_CMD_SET_PORT:
  597. + case SWITCH_CMD_GET_PORT:
  598. + alist = &dev->ops->attr_port;
  599. + def_list = default_port;
  600. + def_active = &dev->def_port;
  601. + n_def = ARRAY_SIZE(default_port);
  602. + if (!info->attrs[SWITCH_ATTR_OP_PORT])
  603. + goto done;
  604. + val->port_vlan = nla_get_u32(info->attrs[SWITCH_ATTR_OP_PORT]);
  605. + if (val->port_vlan >= dev->ports)
  606. + goto done;
  607. + break;
  608. + default:
  609. + WARN_ON(1);
  610. + goto done;
  611. + }
  612. +
  613. + if (!alist)
  614. + goto done;
  615. +
  616. + attr_id = nla_get_u32(info->attrs[SWITCH_ATTR_OP_ID]);
  617. + if (attr_id >= SWITCH_ATTR_DEFAULTS_OFFSET) {
  618. + attr_id -= SWITCH_ATTR_DEFAULTS_OFFSET;
  619. + if (attr_id >= n_def)
  620. + goto done;
  621. + if (!test_bit(attr_id, def_active))
  622. + goto done;
  623. + attr = &def_list[attr_id];
  624. + } else {
  625. + if (attr_id >= alist->n_attr)
  626. + goto done;
  627. + attr = &alist->attr[attr_id];
  628. + }
  629. +
  630. + if (attr->disabled)
  631. + attr = NULL;
  632. +
  633. +done:
  634. + if (!attr)
  635. + pr_debug("attribute lookup failed\n");
  636. + val->attr = attr;
  637. + return attr;
  638. +}
  639. +
  640. +static int
  641. +swconfig_parse_ports(struct sk_buff *msg, struct nlattr *head,
  642. + struct switch_val *val, int max)
  643. +{
  644. + struct nlattr *nla;
  645. + int rem;
  646. +
  647. + val->len = 0;
  648. + nla_for_each_nested(nla, head, rem) {
  649. + struct nlattr *tb[SWITCH_PORT_ATTR_MAX+1];
  650. + struct switch_port *port = &val->value.ports[val->len];
  651. +
  652. + if (val->len >= max)
  653. + return -EINVAL;
  654. +
  655. + if (nla_parse_nested(tb, SWITCH_PORT_ATTR_MAX, nla,
  656. + port_policy))
  657. + return -EINVAL;
  658. +
  659. + if (!tb[SWITCH_PORT_ID])
  660. + return -EINVAL;
  661. +
  662. + port->id = nla_get_u32(tb[SWITCH_PORT_ID]);
  663. + if (tb[SWITCH_PORT_FLAG_TAGGED])
  664. + port->flags |= (1 << SWITCH_PORT_FLAG_TAGGED);
  665. + val->len++;
  666. + }
  667. +
  668. + return 0;
  669. +}
  670. +
  671. +static int
  672. +swconfig_set_attr(struct sk_buff *skb, struct genl_info *info)
  673. +{
  674. + const struct switch_attr *attr;
  675. + struct switch_dev *dev;
  676. + struct switch_val val;
  677. + int err = -EINVAL;
  678. +
  679. + dev = swconfig_get_dev(info);
  680. + if (!dev)
  681. + return -EINVAL;
  682. +
  683. + memset(&val, 0, sizeof(val));
  684. + attr = swconfig_lookup_attr(dev, info, &val);
  685. + if (!attr || !attr->set)
  686. + goto error;
  687. +
  688. + val.attr = attr;
  689. + switch (attr->type) {
  690. + case SWITCH_TYPE_NOVAL:
  691. + break;
  692. + case SWITCH_TYPE_INT:
  693. + if (!info->attrs[SWITCH_ATTR_OP_VALUE_INT])
  694. + goto error;
  695. + val.value.i =
  696. + nla_get_u32(info->attrs[SWITCH_ATTR_OP_VALUE_INT]);
  697. + break;
  698. + case SWITCH_TYPE_STRING:
  699. + if (!info->attrs[SWITCH_ATTR_OP_VALUE_STR])
  700. + goto error;
  701. + val.value.s =
  702. + nla_data(info->attrs[SWITCH_ATTR_OP_VALUE_STR]);
  703. + break;
  704. + case SWITCH_TYPE_PORTS:
  705. + val.value.ports = dev->portbuf;
  706. + memset(dev->portbuf, 0,
  707. + sizeof(struct switch_port) * dev->ports);
  708. +
  709. + /* TODO: implement multipart? */
  710. + if (info->attrs[SWITCH_ATTR_OP_VALUE_PORTS]) {
  711. + err = swconfig_parse_ports(skb,
  712. + info->attrs[SWITCH_ATTR_OP_VALUE_PORTS],
  713. + &val, dev->ports);
  714. + if (err < 0)
  715. + goto error;
  716. + } else {
  717. + val.len = 0;
  718. + err = 0;
  719. + }
  720. + break;
  721. + default:
  722. + goto error;
  723. + }
  724. +
  725. + err = attr->set(dev, attr, &val);
  726. +error:
  727. + swconfig_put_dev(dev);
  728. + return err;
  729. +}
  730. +
  731. +static int
  732. +swconfig_close_portlist(struct swconfig_callback *cb, void *arg)
  733. +{
  734. + if (cb->nest[0])
  735. + nla_nest_end(cb->msg, cb->nest[0]);
  736. + return 0;
  737. +}
  738. +
  739. +static int
  740. +swconfig_send_port(struct swconfig_callback *cb, void *arg)
  741. +{
  742. + const struct switch_port *port = arg;
  743. + struct nlattr *p = NULL;
  744. +
  745. + if (!cb->nest[0]) {
  746. + cb->nest[0] = nla_nest_start(cb->msg, cb->cmd);
  747. + if (!cb->nest[0])
  748. + return -1;
  749. + }
  750. +
  751. + p = nla_nest_start(cb->msg, SWITCH_ATTR_PORT);
  752. + if (!p)
  753. + goto error;
  754. +
  755. + if (nla_put_u32(cb->msg, SWITCH_PORT_ID, port->id))
  756. + goto nla_put_failure;
  757. + if (port->flags & (1 << SWITCH_PORT_FLAG_TAGGED)) {
  758. + if (nla_put_flag(cb->msg, SWITCH_PORT_FLAG_TAGGED))
  759. + goto nla_put_failure;
  760. + }
  761. +
  762. + nla_nest_end(cb->msg, p);
  763. + return 0;
  764. +
  765. +nla_put_failure:
  766. + nla_nest_cancel(cb->msg, p);
  767. +error:
  768. + nla_nest_cancel(cb->msg, cb->nest[0]);
  769. + return -1;
  770. +}
  771. +
  772. +static int
  773. +swconfig_send_ports(struct sk_buff **msg, struct genl_info *info, int attr,
  774. + const struct switch_val *val)
  775. +{
  776. + struct swconfig_callback cb;
  777. + int err = 0;
  778. + int i;
  779. +
  780. + if (!val->value.ports)
  781. + return -EINVAL;
  782. +
  783. + memset(&cb, 0, sizeof(cb));
  784. + cb.cmd = attr;
  785. + cb.msg = *msg;
  786. + cb.info = info;
  787. + cb.fill = swconfig_send_port;
  788. + cb.close = swconfig_close_portlist;
  789. +
  790. + cb.nest[0] = nla_nest_start(cb.msg, cb.cmd);
  791. + for (i = 0; i < val->len; i++) {
  792. + err = swconfig_send_multipart(&cb, &val->value.ports[i]);
  793. + if (err)
  794. + goto done;
  795. + }
  796. + err = val->len;
  797. + swconfig_close_portlist(&cb, NULL);
  798. + *msg = cb.msg;
  799. +
  800. +done:
  801. + return err;
  802. +}
  803. +
  804. +static int
  805. +swconfig_get_attr(struct sk_buff *skb, struct genl_info *info)
  806. +{
  807. + struct genlmsghdr *hdr = nlmsg_data(info->nlhdr);
  808. + const struct switch_attr *attr;
  809. + struct switch_dev *dev;
  810. + struct sk_buff *msg = NULL;
  811. + struct switch_val val;
  812. + int err = -EINVAL;
  813. + int cmd = hdr->cmd;
  814. +
  815. + dev = swconfig_get_dev(info);
  816. + if (!dev)
  817. + return -EINVAL;
  818. +
  819. + memset(&val, 0, sizeof(val));
  820. + attr = swconfig_lookup_attr(dev, info, &val);
  821. + if (!attr || !attr->get)
  822. + goto error;
  823. +
  824. + if (attr->type == SWITCH_TYPE_PORTS) {
  825. + val.value.ports = dev->portbuf;
  826. + memset(dev->portbuf, 0,
  827. + sizeof(struct switch_port) * dev->ports);
  828. + }
  829. +
  830. + err = attr->get(dev, attr, &val);
  831. + if (err)
  832. + goto error;
  833. +
  834. + msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
  835. + if (!msg)
  836. + goto error;
  837. +
  838. + hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq, &switch_fam,
  839. + 0, cmd);
  840. + if (IS_ERR(hdr))
  841. + goto nla_put_failure;
  842. +
  843. + switch (attr->type) {
  844. + case SWITCH_TYPE_INT:
  845. + if (nla_put_u32(msg, SWITCH_ATTR_OP_VALUE_INT, val.value.i))
  846. + goto nla_put_failure;
  847. + break;
  848. + case SWITCH_TYPE_STRING:
  849. + if (nla_put_string(msg, SWITCH_ATTR_OP_VALUE_STR, val.value.s))
  850. + goto nla_put_failure;
  851. + break;
  852. + case SWITCH_TYPE_PORTS:
  853. + err = swconfig_send_ports(&msg, info,
  854. + SWITCH_ATTR_OP_VALUE_PORTS, &val);
  855. + if (err < 0)
  856. + goto nla_put_failure;
  857. + break;
  858. + default:
  859. + pr_debug("invalid type in attribute\n");
  860. + err = -EINVAL;
  861. + goto error;
  862. + }
  863. + genlmsg_end(msg, hdr);
  864. + err = msg->len;
  865. + if (err < 0)
  866. + goto nla_put_failure;
  867. +
  868. + swconfig_put_dev(dev);
  869. + return genlmsg_reply(msg, info);
  870. +
  871. +nla_put_failure:
  872. + if (msg)
  873. + nlmsg_free(msg);
  874. +error:
  875. + swconfig_put_dev(dev);
  876. + if (!err)
  877. + err = -ENOMEM;
  878. + return err;
  879. +}
  880. +
  881. +static int
  882. +swconfig_send_switch(struct sk_buff *msg, u32 pid, u32 seq, int flags,
  883. + const struct switch_dev *dev)
  884. +{
  885. + struct nlattr *p = NULL, *m = NULL;
  886. + void *hdr;
  887. + int i;
  888. +
  889. + hdr = genlmsg_put(msg, pid, seq, &switch_fam, flags,
  890. + SWITCH_CMD_NEW_ATTR);
  891. + if (IS_ERR(hdr))
  892. + return -1;
  893. +
  894. + if (nla_put_u32(msg, SWITCH_ATTR_ID, dev->id))
  895. + goto nla_put_failure;
  896. + if (nla_put_string(msg, SWITCH_ATTR_DEV_NAME, dev->devname))
  897. + goto nla_put_failure;
  898. + if (nla_put_string(msg, SWITCH_ATTR_ALIAS, dev->alias))
  899. + goto nla_put_failure;
  900. + if (nla_put_string(msg, SWITCH_ATTR_NAME, dev->name))
  901. + goto nla_put_failure;
  902. + if (nla_put_u32(msg, SWITCH_ATTR_VLANS, dev->vlans))
  903. + goto nla_put_failure;
  904. + if (nla_put_u32(msg, SWITCH_ATTR_PORTS, dev->ports))
  905. + goto nla_put_failure;
  906. + if (nla_put_u32(msg, SWITCH_ATTR_CPU_PORT, dev->cpu_port))
  907. + goto nla_put_failure;
  908. +
  909. + m = nla_nest_start(msg, SWITCH_ATTR_PORTMAP);
  910. + if (!m)
  911. + goto nla_put_failure;
  912. + for (i = 0; i < dev->ports; i++) {
  913. + p = nla_nest_start(msg, SWITCH_ATTR_PORTS);
  914. + if (!p)
  915. + continue;
  916. + if (dev->portmap[i].s) {
  917. + if (nla_put_string(msg, SWITCH_PORTMAP_SEGMENT,
  918. + dev->portmap[i].s))
  919. + goto nla_put_failure;
  920. + if (nla_put_u32(msg, SWITCH_PORTMAP_VIRT,
  921. + dev->portmap[i].virt))
  922. + goto nla_put_failure;
  923. + }
  924. + nla_nest_end(msg, p);
  925. + }
  926. + nla_nest_end(msg, m);
  927. + genlmsg_end(msg, hdr);
  928. + return msg->len;
  929. +nla_put_failure:
  930. + genlmsg_cancel(msg, hdr);
  931. + return -EMSGSIZE;
  932. +}
  933. +
  934. +static int swconfig_dump_switches(struct sk_buff *skb,
  935. + struct netlink_callback *cb)
  936. +{
  937. + struct switch_dev *dev;
  938. + int start = cb->args[0];
  939. + int idx = 0;
  940. +
  941. + swconfig_lock();
  942. + list_for_each_entry(dev, &swdevs, dev_list) {
  943. + if (++idx <= start)
  944. + continue;
  945. + if (swconfig_send_switch(skb, NETLINK_CB(cb->skb).portid,
  946. + cb->nlh->nlmsg_seq, NLM_F_MULTI,
  947. + dev) < 0)
  948. + break;
  949. + }
  950. + swconfig_unlock();
  951. + cb->args[0] = idx;
  952. +
  953. + return skb->len;
  954. +}
  955. +
  956. +static int
  957. +swconfig_done(struct netlink_callback *cb)
  958. +{
  959. + return 0;
  960. +}
  961. +
  962. +static struct genl_ops swconfig_ops[] = {
  963. + {
  964. + .cmd = SWITCH_CMD_LIST_GLOBAL,
  965. + .doit = swconfig_list_attrs,
  966. + .policy = switch_policy,
  967. + },
  968. + {
  969. + .cmd = SWITCH_CMD_LIST_VLAN,
  970. + .doit = swconfig_list_attrs,
  971. + .policy = switch_policy,
  972. + },
  973. + {
  974. + .cmd = SWITCH_CMD_LIST_PORT,
  975. + .doit = swconfig_list_attrs,
  976. + .policy = switch_policy,
  977. + },
  978. + {
  979. + .cmd = SWITCH_CMD_GET_GLOBAL,
  980. + .doit = swconfig_get_attr,
  981. + .policy = switch_policy,
  982. + },
  983. + {
  984. + .cmd = SWITCH_CMD_GET_VLAN,
  985. + .doit = swconfig_get_attr,
  986. + .policy = switch_policy,
  987. + },
  988. + {
  989. + .cmd = SWITCH_CMD_GET_PORT,
  990. + .doit = swconfig_get_attr,
  991. + .policy = switch_policy,
  992. + },
  993. + {
  994. + .cmd = SWITCH_CMD_SET_GLOBAL,
  995. + .doit = swconfig_set_attr,
  996. + .policy = switch_policy,
  997. + },
  998. + {
  999. + .cmd = SWITCH_CMD_SET_VLAN,
  1000. + .doit = swconfig_set_attr,
  1001. + .policy = switch_policy,
  1002. + },
  1003. + {
  1004. + .cmd = SWITCH_CMD_SET_PORT,
  1005. + .doit = swconfig_set_attr,
  1006. + .policy = switch_policy,
  1007. + },
  1008. + {
  1009. + .cmd = SWITCH_CMD_GET_SWITCH,
  1010. + .dumpit = swconfig_dump_switches,
  1011. + .policy = switch_policy,
  1012. + .done = swconfig_done,
  1013. + }
  1014. +};
  1015. +
  1016. +#ifdef CONFIG_OF
  1017. +void
  1018. +of_switch_load_portmap(struct switch_dev *dev)
  1019. +{
  1020. + struct device_node *port;
  1021. +
  1022. + if (!dev->of_node)
  1023. + return;
  1024. +
  1025. + for_each_child_of_node(dev->of_node, port) {
  1026. + const __be32 *prop;
  1027. + const char *segment;
  1028. + int size, phys;
  1029. +
  1030. + if (!of_device_is_compatible(port, "swconfig,port"))
  1031. + continue;
  1032. +
  1033. + if (of_property_read_string(port, "swconfig,segment", &segment))
  1034. + continue;
  1035. +
  1036. + prop = of_get_property(port, "swconfig,portmap", &size);
  1037. + if (!prop)
  1038. + continue;
  1039. +
  1040. + if (size != (2 * sizeof(*prop))) {
  1041. + pr_err("%s: failed to parse port mapping\n",
  1042. + port->name);
  1043. + continue;
  1044. + }
  1045. +
  1046. + phys = be32_to_cpup(prop++);
  1047. + if ((phys < 0) | (phys >= dev->ports)) {
  1048. + pr_err("%s: physical port index out of range\n",
  1049. + port->name);
  1050. + continue;
  1051. + }
  1052. +
  1053. + dev->portmap[phys].s = kstrdup(segment, GFP_KERNEL);
  1054. + dev->portmap[phys].virt = be32_to_cpup(prop);
  1055. + pr_debug("Found port: %s, physical: %d, virtual: %d\n",
  1056. + segment, phys, dev->portmap[phys].virt);
  1057. + }
  1058. +}
  1059. +#endif
  1060. +
  1061. +int
  1062. +register_switch(struct switch_dev *dev, struct net_device *netdev)
  1063. +{
  1064. + struct switch_dev *sdev;
  1065. + const int max_switches = 8 * sizeof(unsigned long);
  1066. + unsigned long in_use = 0;
  1067. + int err;
  1068. + int i;
  1069. +
  1070. + INIT_LIST_HEAD(&dev->dev_list);
  1071. + if (netdev) {
  1072. + dev->netdev = netdev;
  1073. + if (!dev->alias)
  1074. + dev->alias = netdev->name;
  1075. + }
  1076. + BUG_ON(!dev->alias);
  1077. +
  1078. + if (dev->ports > 0) {
  1079. + dev->portbuf = kzalloc(sizeof(struct switch_port) *
  1080. + dev->ports, GFP_KERNEL);
  1081. + if (!dev->portbuf)
  1082. + return -ENOMEM;
  1083. + dev->portmap = kzalloc(sizeof(struct switch_portmap) *
  1084. + dev->ports, GFP_KERNEL);
  1085. + if (!dev->portmap) {
  1086. + kfree(dev->portbuf);
  1087. + return -ENOMEM;
  1088. + }
  1089. + }
  1090. + swconfig_defaults_init(dev);
  1091. + mutex_init(&dev->sw_mutex);
  1092. + swconfig_lock();
  1093. + dev->id = ++swdev_id;
  1094. +
  1095. + list_for_each_entry(sdev, &swdevs, dev_list) {
  1096. + if (!sscanf(sdev->devname, SWCONFIG_DEVNAME, &i))
  1097. + continue;
  1098. + if (i < 0 || i > max_switches)
  1099. + continue;
  1100. +
  1101. + set_bit(i, &in_use);
  1102. + }
  1103. + i = find_first_zero_bit(&in_use, max_switches);
  1104. +
  1105. + if (i == max_switches) {
  1106. + swconfig_unlock();
  1107. + return -ENFILE;
  1108. + }
  1109. +
  1110. +#ifdef CONFIG_OF
  1111. + if (dev->ports)
  1112. + of_switch_load_portmap(dev);
  1113. +#endif
  1114. +
  1115. + /* fill device name */
  1116. + snprintf(dev->devname, IFNAMSIZ, SWCONFIG_DEVNAME, i);
  1117. +
  1118. + list_add_tail(&dev->dev_list, &swdevs);
  1119. + swconfig_unlock();
  1120. +
  1121. + err = swconfig_create_led_trigger(dev);
  1122. + if (err)
  1123. + return err;
  1124. +
  1125. + return 0;
  1126. +}
  1127. +EXPORT_SYMBOL_GPL(register_switch);
  1128. +
  1129. +void
  1130. +unregister_switch(struct switch_dev *dev)
  1131. +{
  1132. + swconfig_destroy_led_trigger(dev);
  1133. + kfree(dev->portbuf);
  1134. + mutex_lock(&dev->sw_mutex);
  1135. + swconfig_lock();
  1136. + list_del(&dev->dev_list);
  1137. + swconfig_unlock();
  1138. + mutex_unlock(&dev->sw_mutex);
  1139. +}
  1140. +EXPORT_SYMBOL_GPL(unregister_switch);
  1141. +
  1142. +
  1143. +static int __init
  1144. +swconfig_init(void)
  1145. +{
  1146. + int err;
  1147. +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0))
  1148. + int i;
  1149. +#endif
  1150. +
  1151. + INIT_LIST_HEAD(&swdevs);
  1152. +
  1153. +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0))
  1154. + err = genl_register_family(&switch_fam);
  1155. + if (err)
  1156. + return err;
  1157. +
  1158. + for (i = 0; i < ARRAY_SIZE(swconfig_ops); i++) {
  1159. + err = genl_register_ops(&switch_fam, &swconfig_ops[i]);
  1160. + if (err)
  1161. + goto unregister;
  1162. + }
  1163. + return 0;
  1164. +
  1165. +unregister:
  1166. + genl_unregister_family(&switch_fam);
  1167. + return err;
  1168. +#else
  1169. + err = genl_register_family_with_ops(&switch_fam, swconfig_ops);
  1170. + if (err)
  1171. + return err;
  1172. + return 0;
  1173. +#endif
  1174. +}
  1175. +
  1176. +static void __exit
  1177. +swconfig_exit(void)
  1178. +{
  1179. + genl_unregister_family(&switch_fam);
  1180. +}
  1181. +
  1182. +module_init(swconfig_init);
  1183. +module_exit(swconfig_exit);
  1184. +
  1185. diff -Nur linux-4.1.6.orig/drivers/net/phy/swconfig_leds.c linux-4.1.6/drivers/net/phy/swconfig_leds.c
  1186. --- linux-4.1.6.orig/drivers/net/phy/swconfig_leds.c 1970-01-01 01:00:00.000000000 +0100
  1187. +++ linux-4.1.6/drivers/net/phy/swconfig_leds.c 2015-09-13 20:14:58.973675262 +0200
  1188. @@ -0,0 +1,354 @@
  1189. +/*
  1190. + * swconfig_led.c: LED trigger support for the switch configuration API
  1191. + *
  1192. + * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
  1193. + *
  1194. + * This program is free software; you can redistribute it and/or
  1195. + * modify it under the terms of the GNU General Public License
  1196. + * as published by the Free Software Foundation; either version 2
  1197. + * of the License, or (at your option) any later version.
  1198. + *
  1199. + */
  1200. +
  1201. +#ifdef CONFIG_SWCONFIG_LEDS
  1202. +
  1203. +#include <linux/leds.h>
  1204. +#include <linux/ctype.h>
  1205. +#include <linux/device.h>
  1206. +#include <linux/workqueue.h>
  1207. +
  1208. +#define SWCONFIG_LED_TIMER_INTERVAL (HZ / 10)
  1209. +#define SWCONFIG_LED_NUM_PORTS 32
  1210. +
  1211. +struct switch_led_trigger {
  1212. + struct led_trigger trig;
  1213. + struct switch_dev *swdev;
  1214. +
  1215. + struct delayed_work sw_led_work;
  1216. + u32 port_mask;
  1217. + u32 port_link;
  1218. + unsigned long port_traffic[SWCONFIG_LED_NUM_PORTS];
  1219. +};
  1220. +
  1221. +struct swconfig_trig_data {
  1222. + struct led_classdev *led_cdev;
  1223. + struct switch_dev *swdev;
  1224. +
  1225. + rwlock_t lock;
  1226. + u32 port_mask;
  1227. +
  1228. + bool prev_link;
  1229. + unsigned long prev_traffic;
  1230. + enum led_brightness prev_brightness;
  1231. +};
  1232. +
  1233. +static void
  1234. +swconfig_trig_set_brightness(struct swconfig_trig_data *trig_data,
  1235. + enum led_brightness brightness)
  1236. +{
  1237. + led_set_brightness(trig_data->led_cdev, brightness);
  1238. + trig_data->prev_brightness = brightness;
  1239. +}
  1240. +
  1241. +static void
  1242. +swconfig_trig_update_port_mask(struct led_trigger *trigger)
  1243. +{
  1244. + struct list_head *entry;
  1245. + struct switch_led_trigger *sw_trig;
  1246. + u32 port_mask;
  1247. +
  1248. + if (!trigger)
  1249. + return;
  1250. +
  1251. + sw_trig = (void *) trigger;
  1252. +
  1253. + port_mask = 0;
  1254. + read_lock(&trigger->leddev_list_lock);
  1255. + list_for_each(entry, &trigger->led_cdevs) {
  1256. + struct led_classdev *led_cdev;
  1257. + struct swconfig_trig_data *trig_data;
  1258. +
  1259. + led_cdev = list_entry(entry, struct led_classdev, trig_list);
  1260. + trig_data = led_cdev->trigger_data;
  1261. + if (trig_data) {
  1262. + read_lock(&trig_data->lock);
  1263. + port_mask |= trig_data->port_mask;
  1264. + read_unlock(&trig_data->lock);
  1265. + }
  1266. + }
  1267. + read_unlock(&trigger->leddev_list_lock);
  1268. +
  1269. + sw_trig->port_mask = port_mask;
  1270. +
  1271. + if (port_mask)
  1272. + schedule_delayed_work(&sw_trig->sw_led_work,
  1273. + SWCONFIG_LED_TIMER_INTERVAL);
  1274. + else
  1275. + cancel_delayed_work_sync(&sw_trig->sw_led_work);
  1276. +}
  1277. +
  1278. +static ssize_t
  1279. +swconfig_trig_port_mask_store(struct device *dev, struct device_attribute *attr,
  1280. + const char *buf, size_t size)
  1281. +{
  1282. + struct led_classdev *led_cdev = dev_get_drvdata(dev);
  1283. + struct swconfig_trig_data *trig_data = led_cdev->trigger_data;
  1284. + unsigned long port_mask;
  1285. + ssize_t ret = -EINVAL;
  1286. + char *after;
  1287. + size_t count;
  1288. +
  1289. + port_mask = simple_strtoul(buf, &after, 16);
  1290. + count = after - buf;
  1291. +
  1292. + if (*after && isspace(*after))
  1293. + count++;
  1294. +
  1295. + if (count == size) {
  1296. + bool changed;
  1297. +
  1298. + write_lock(&trig_data->lock);
  1299. +
  1300. + changed = (trig_data->port_mask != port_mask);
  1301. + if (changed) {
  1302. + trig_data->port_mask = port_mask;
  1303. + if (port_mask == 0)
  1304. + swconfig_trig_set_brightness(trig_data, LED_OFF);
  1305. + }
  1306. +
  1307. + write_unlock(&trig_data->lock);
  1308. +
  1309. + if (changed)
  1310. + swconfig_trig_update_port_mask(led_cdev->trigger);
  1311. +
  1312. + ret = count;
  1313. + }
  1314. +
  1315. + return ret;
  1316. +}
  1317. +
  1318. +static ssize_t
  1319. +swconfig_trig_port_mask_show(struct device *dev, struct device_attribute *attr,
  1320. + char *buf)
  1321. +{
  1322. + struct led_classdev *led_cdev = dev_get_drvdata(dev);
  1323. + struct swconfig_trig_data *trig_data = led_cdev->trigger_data;
  1324. +
  1325. + read_lock(&trig_data->lock);
  1326. + sprintf(buf, "%#x\n", trig_data->port_mask);
  1327. + read_unlock(&trig_data->lock);
  1328. +
  1329. + return strlen(buf) + 1;
  1330. +}
  1331. +
  1332. +static DEVICE_ATTR(port_mask, 0644, swconfig_trig_port_mask_show,
  1333. + swconfig_trig_port_mask_store);
  1334. +
  1335. +static void
  1336. +swconfig_trig_activate(struct led_classdev *led_cdev)
  1337. +{
  1338. + struct switch_led_trigger *sw_trig;
  1339. + struct swconfig_trig_data *trig_data;
  1340. + int err;
  1341. +
  1342. + if (led_cdev->trigger->activate != swconfig_trig_activate)
  1343. + return;
  1344. +
  1345. + trig_data = kzalloc(sizeof(struct swconfig_trig_data), GFP_KERNEL);
  1346. + if (!trig_data)
  1347. + return;
  1348. +
  1349. + sw_trig = (void *) led_cdev->trigger;
  1350. +
  1351. + rwlock_init(&trig_data->lock);
  1352. + trig_data->led_cdev = led_cdev;
  1353. + trig_data->swdev = sw_trig->swdev;
  1354. + led_cdev->trigger_data = trig_data;
  1355. +
  1356. + err = device_create_file(led_cdev->dev, &dev_attr_port_mask);
  1357. + if (err)
  1358. + goto err_free;
  1359. +
  1360. + return;
  1361. +
  1362. +err_free:
  1363. + led_cdev->trigger_data = NULL;
  1364. + kfree(trig_data);
  1365. +}
  1366. +
  1367. +static void
  1368. +swconfig_trig_deactivate(struct led_classdev *led_cdev)
  1369. +{
  1370. + struct swconfig_trig_data *trig_data;
  1371. +
  1372. + swconfig_trig_update_port_mask(led_cdev->trigger);
  1373. +
  1374. + trig_data = (void *) led_cdev->trigger_data;
  1375. + if (trig_data) {
  1376. + device_remove_file(led_cdev->dev, &dev_attr_port_mask);
  1377. + kfree(trig_data);
  1378. + }
  1379. +}
  1380. +
  1381. +static void
  1382. +swconfig_trig_led_event(struct switch_led_trigger *sw_trig,
  1383. + struct led_classdev *led_cdev)
  1384. +{
  1385. + struct swconfig_trig_data *trig_data;
  1386. + u32 port_mask;
  1387. + bool link;
  1388. +
  1389. + trig_data = led_cdev->trigger_data;
  1390. + if (!trig_data)
  1391. + return;
  1392. +
  1393. + read_lock(&trig_data->lock);
  1394. + port_mask = trig_data->port_mask;
  1395. + read_unlock(&trig_data->lock);
  1396. +
  1397. + link = !!(sw_trig->port_link & port_mask);
  1398. + if (!link) {
  1399. + if (link != trig_data->prev_link)
  1400. + swconfig_trig_set_brightness(trig_data, LED_OFF);
  1401. + } else {
  1402. + unsigned long traffic;
  1403. + int i;
  1404. +
  1405. + traffic = 0;
  1406. + for (i = 0; i < SWCONFIG_LED_NUM_PORTS; i++) {
  1407. + if (port_mask & (1 << i))
  1408. + traffic += sw_trig->port_traffic[i];
  1409. + }
  1410. +
  1411. + if (trig_data->prev_brightness != LED_FULL)
  1412. + swconfig_trig_set_brightness(trig_data, LED_FULL);
  1413. + else if (traffic != trig_data->prev_traffic)
  1414. + swconfig_trig_set_brightness(trig_data, LED_OFF);
  1415. +
  1416. + trig_data->prev_traffic = traffic;
  1417. + }
  1418. +
  1419. + trig_data->prev_link = link;
  1420. +}
  1421. +
  1422. +static void
  1423. +swconfig_trig_update_leds(struct switch_led_trigger *sw_trig)
  1424. +{
  1425. + struct list_head *entry;
  1426. + struct led_trigger *trigger;
  1427. +
  1428. + trigger = &sw_trig->trig;
  1429. + read_lock(&trigger->leddev_list_lock);
  1430. + list_for_each(entry, &trigger->led_cdevs) {
  1431. + struct led_classdev *led_cdev;
  1432. +
  1433. + led_cdev = list_entry(entry, struct led_classdev, trig_list);
  1434. + swconfig_trig_led_event(sw_trig, led_cdev);
  1435. + }
  1436. + read_unlock(&trigger->leddev_list_lock);
  1437. +}
  1438. +
  1439. +static void
  1440. +swconfig_led_work_func(struct work_struct *work)
  1441. +{
  1442. + struct switch_led_trigger *sw_trig;
  1443. + struct switch_dev *swdev;
  1444. + u32 port_mask;
  1445. + u32 link;
  1446. + int i;
  1447. +
  1448. + sw_trig = container_of(work, struct switch_led_trigger,
  1449. + sw_led_work.work);
  1450. +
  1451. + port_mask = sw_trig->port_mask;
  1452. + swdev = sw_trig->swdev;
  1453. +
  1454. + link = 0;
  1455. + for (i = 0; i < SWCONFIG_LED_NUM_PORTS; i++) {
  1456. + u32 port_bit;
  1457. +
  1458. + port_bit = BIT(i);
  1459. + if ((port_mask & port_bit) == 0)
  1460. + continue;
  1461. +
  1462. + if (swdev->ops->get_port_link) {
  1463. + struct switch_port_link port_link;
  1464. +
  1465. + memset(&port_link, '\0', sizeof(port_link));
  1466. + swdev->ops->get_port_link(swdev, i, &port_link);
  1467. +
  1468. + if (port_link.link)
  1469. + link |= port_bit;
  1470. + }
  1471. +
  1472. + if (swdev->ops->get_port_stats) {
  1473. + struct switch_port_stats port_stats;
  1474. +
  1475. + memset(&port_stats, '\0', sizeof(port_stats));
  1476. + swdev->ops->get_port_stats(swdev, i, &port_stats);
  1477. + sw_trig->port_traffic[i] = port_stats.tx_bytes +
  1478. + port_stats.rx_bytes;
  1479. + }
  1480. + }
  1481. +
  1482. + sw_trig->port_link = link;
  1483. +
  1484. + swconfig_trig_update_leds(sw_trig);
  1485. +
  1486. + schedule_delayed_work(&sw_trig->sw_led_work,
  1487. + SWCONFIG_LED_TIMER_INTERVAL);
  1488. +}
  1489. +
  1490. +static int
  1491. +swconfig_create_led_trigger(struct switch_dev *swdev)
  1492. +{
  1493. + struct switch_led_trigger *sw_trig;
  1494. + int err;
  1495. +
  1496. + if (!swdev->ops->get_port_link)
  1497. + return 0;
  1498. +
  1499. + sw_trig = kzalloc(sizeof(struct switch_led_trigger), GFP_KERNEL);
  1500. + if (!sw_trig)
  1501. + return -ENOMEM;
  1502. +
  1503. + sw_trig->swdev = swdev;
  1504. + sw_trig->trig.name = swdev->devname;
  1505. + sw_trig->trig.activate = swconfig_trig_activate;
  1506. + sw_trig->trig.deactivate = swconfig_trig_deactivate;
  1507. +
  1508. + INIT_DELAYED_WORK(&sw_trig->sw_led_work, swconfig_led_work_func);
  1509. +
  1510. + err = led_trigger_register(&sw_trig->trig);
  1511. + if (err)
  1512. + goto err_free;
  1513. +
  1514. + swdev->led_trigger = sw_trig;
  1515. +
  1516. + return 0;
  1517. +
  1518. +err_free:
  1519. + kfree(sw_trig);
  1520. + return err;
  1521. +}
  1522. +
  1523. +static void
  1524. +swconfig_destroy_led_trigger(struct switch_dev *swdev)
  1525. +{
  1526. + struct switch_led_trigger *sw_trig;
  1527. +
  1528. + sw_trig = swdev->led_trigger;
  1529. + if (sw_trig) {
  1530. + cancel_delayed_work_sync(&sw_trig->sw_led_work);
  1531. + led_trigger_unregister(&sw_trig->trig);
  1532. + kfree(sw_trig);
  1533. + }
  1534. +}
  1535. +
  1536. +#else /* SWCONFIG_LEDS */
  1537. +static inline int
  1538. +swconfig_create_led_trigger(struct switch_dev *swdev) { return 0; }
  1539. +
  1540. +static inline void
  1541. +swconfig_destroy_led_trigger(struct switch_dev *swdev) { }
  1542. +#endif /* CONFIG_SWCONFIG_LEDS */
  1543. diff -Nur linux-4.1.6.orig/include/linux/switch.h linux-4.1.6/include/linux/switch.h
  1544. --- linux-4.1.6.orig/include/linux/switch.h 1970-01-01 01:00:00.000000000 +0100
  1545. +++ linux-4.1.6/include/linux/switch.h 2015-09-13 20:20:39.168854401 +0200
  1546. @@ -0,0 +1,169 @@
  1547. +/*
  1548. + * switch.h: Switch configuration API
  1549. + *
  1550. + * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
  1551. + *
  1552. + * This program is free software; you can redistribute it and/or
  1553. + * modify it under the terms of the GNU General Public License
  1554. + * as published by the Free Software Foundation; either version 2
  1555. + * of the License, or (at your option) any later version.
  1556. + *
  1557. + * This program is distributed in the hope that it will be useful,
  1558. + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  1559. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  1560. + * GNU General Public License for more details.
  1561. + */
  1562. +#ifndef _LINUX_SWITCH_H
  1563. +#define _LINUX_SWITCH_H
  1564. +
  1565. +#include <net/genetlink.h>
  1566. +#include <uapi/linux/switch.h>
  1567. +
  1568. +struct switch_dev;
  1569. +struct switch_op;
  1570. +struct switch_val;
  1571. +struct switch_attr;
  1572. +struct switch_attrlist;
  1573. +struct switch_led_trigger;
  1574. +
  1575. +int register_switch(struct switch_dev *dev, struct net_device *netdev);
  1576. +void unregister_switch(struct switch_dev *dev);
  1577. +
  1578. +/**
  1579. + * struct switch_attrlist - attribute list
  1580. + *
  1581. + * @n_attr: number of attributes
  1582. + * @attr: pointer to the attributes array
  1583. + */
  1584. +struct switch_attrlist {
  1585. + int n_attr;
  1586. + const struct switch_attr *attr;
  1587. +};
  1588. +
  1589. +enum switch_port_speed {
  1590. + SWITCH_PORT_SPEED_UNKNOWN = 0,
  1591. + SWITCH_PORT_SPEED_10 = 10,
  1592. + SWITCH_PORT_SPEED_100 = 100,
  1593. + SWITCH_PORT_SPEED_1000 = 1000,
  1594. +};
  1595. +
  1596. +struct switch_port_link {
  1597. + bool link;
  1598. + bool duplex;
  1599. + bool aneg;
  1600. + bool tx_flow;
  1601. + bool rx_flow;
  1602. + enum switch_port_speed speed;
  1603. + /* in ethtool adv_t format */
  1604. + u32 eee;
  1605. +};
  1606. +
  1607. +struct switch_port_stats {
  1608. + unsigned long tx_bytes;
  1609. + unsigned long rx_bytes;
  1610. +};
  1611. +
  1612. +/**
  1613. + * struct switch_dev_ops - switch driver operations
  1614. + *
  1615. + * @attr_global: global switch attribute list
  1616. + * @attr_port: port attribute list
  1617. + * @attr_vlan: vlan attribute list
  1618. + *
  1619. + * Callbacks:
  1620. + *
  1621. + * @get_vlan_ports: read the port list of a VLAN
  1622. + * @set_vlan_ports: set the port list of a VLAN
  1623. + *
  1624. + * @get_port_pvid: get the primary VLAN ID of a port
  1625. + * @set_port_pvid: set the primary VLAN ID of a port
  1626. + *
  1627. + * @apply_config: apply all changed settings to the switch
  1628. + * @reset_switch: resetting the switch
  1629. + */
  1630. +struct switch_dev_ops {
  1631. + struct switch_attrlist attr_global, attr_port, attr_vlan;
  1632. +
  1633. + int (*get_vlan_ports)(struct switch_dev *dev, struct switch_val *val);
  1634. + int (*set_vlan_ports)(struct switch_dev *dev, struct switch_val *val);
  1635. +
  1636. + int (*get_port_pvid)(struct switch_dev *dev, int port, int *val);
  1637. + int (*set_port_pvid)(struct switch_dev *dev, int port, int val);
  1638. +
  1639. + int (*apply_config)(struct switch_dev *dev);
  1640. + int (*reset_switch)(struct switch_dev *dev);
  1641. +
  1642. + int (*get_port_link)(struct switch_dev *dev, int port,
  1643. + struct switch_port_link *link);
  1644. + int (*get_port_stats)(struct switch_dev *dev, int port,
  1645. + struct switch_port_stats *stats);
  1646. +};
  1647. +
  1648. +struct switch_dev {
  1649. + struct device_node *of_node;
  1650. + const struct switch_dev_ops *ops;
  1651. + /* will be automatically filled */
  1652. + char devname[IFNAMSIZ];
  1653. +
  1654. + const char *name;
  1655. + /* NB: either alias or netdev must be set */
  1656. + const char *alias;
  1657. + struct net_device *netdev;
  1658. +
  1659. + int ports;
  1660. + int vlans;
  1661. + int cpu_port;
  1662. +
  1663. + /* the following fields are internal for swconfig */
  1664. + int id;
  1665. + struct list_head dev_list;
  1666. + unsigned long def_global, def_port, def_vlan;
  1667. +
  1668. + struct mutex sw_mutex;
  1669. + struct switch_port *portbuf;
  1670. + struct switch_portmap *portmap;
  1671. +
  1672. + char buf[128];
  1673. +
  1674. +#ifdef CONFIG_SWCONFIG_LEDS
  1675. + struct switch_led_trigger *led_trigger;
  1676. +#endif
  1677. +};
  1678. +
  1679. +struct switch_port {
  1680. + u32 id;
  1681. + u32 flags;
  1682. +};
  1683. +
  1684. +struct switch_portmap {
  1685. + u32 virt;
  1686. + const char *s;
  1687. +};
  1688. +
  1689. +struct switch_val {
  1690. + const struct switch_attr *attr;
  1691. + int port_vlan;
  1692. + int len;
  1693. + union {
  1694. + const char *s;
  1695. + u32 i;
  1696. + struct switch_port *ports;
  1697. + } value;
  1698. +};
  1699. +
  1700. +struct switch_attr {
  1701. + int disabled;
  1702. + int type;
  1703. + const char *name;
  1704. + const char *description;
  1705. +
  1706. + int (*set)(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val);
  1707. + int (*get)(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val);
  1708. +
  1709. + /* for driver internal use */
  1710. + int id;
  1711. + int ofs;
  1712. + int max;
  1713. +};
  1714. +
  1715. +#endif /* _LINUX_SWITCH_H */
  1716. diff -Nur linux-4.1.6.orig/include/uapi/linux/Kbuild linux-4.1.6/include/uapi/linux/Kbuild
  1717. --- linux-4.1.6.orig/include/uapi/linux/Kbuild 2015-08-17 05:52:51.000000000 +0200
  1718. +++ linux-4.1.6/include/uapi/linux/Kbuild 2015-09-13 20:15:06.385308796 +0200
  1719. @@ -380,6 +380,7 @@
  1720. header-y += string.h
  1721. header-y += suspend_ioctls.h
  1722. header-y += swab.h
  1723. +header-y += switch.h
  1724. header-y += synclink.h
  1725. header-y += sysctl.h
  1726. header-y += sysinfo.h
  1727. diff -Nur linux-4.1.6.orig/include/uapi/linux/switch.h linux-4.1.6/include/uapi/linux/switch.h
  1728. --- linux-4.1.6.orig/include/uapi/linux/switch.h 1970-01-01 01:00:00.000000000 +0100
  1729. +++ linux-4.1.6/include/uapi/linux/switch.h 2015-09-13 20:20:56.895977889 +0200
  1730. @@ -0,0 +1,103 @@
  1731. +/*
  1732. + * switch.h: Switch configuration API
  1733. + *
  1734. + * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
  1735. + *
  1736. + * This program is free software; you can redistribute it and/or
  1737. + * modify it under the terms of the GNU General Public License
  1738. + * as published by the Free Software Foundation; either version 2
  1739. + * of the License, or (at your option) any later version.
  1740. + *
  1741. + * This program is distributed in the hope that it will be useful,
  1742. + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  1743. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  1744. + * GNU General Public License for more details.
  1745. + */
  1746. +
  1747. +#ifndef _UAPI_LINUX_SWITCH_H
  1748. +#define _UAPI_LINUX_SWITCH_H
  1749. +
  1750. +#include <linux/types.h>
  1751. +#include <linux/netdevice.h>
  1752. +#include <linux/netlink.h>
  1753. +#include <linux/genetlink.h>
  1754. +#ifndef __KERNEL__
  1755. +#include <netlink/netlink.h>
  1756. +#include <netlink/genl/genl.h>
  1757. +#include <netlink/genl/ctrl.h>
  1758. +#endif
  1759. +
  1760. +/* main attributes */
  1761. +enum {
  1762. + SWITCH_ATTR_UNSPEC,
  1763. + /* global */
  1764. + SWITCH_ATTR_TYPE,
  1765. + /* device */
  1766. + SWITCH_ATTR_ID,
  1767. + SWITCH_ATTR_DEV_NAME,
  1768. + SWITCH_ATTR_ALIAS,
  1769. + SWITCH_ATTR_NAME,
  1770. + SWITCH_ATTR_VLANS,
  1771. + SWITCH_ATTR_PORTS,
  1772. + SWITCH_ATTR_PORTMAP,
  1773. + SWITCH_ATTR_CPU_PORT,
  1774. + /* attributes */
  1775. + SWITCH_ATTR_OP_ID,
  1776. + SWITCH_ATTR_OP_TYPE,
  1777. + SWITCH_ATTR_OP_NAME,
  1778. + SWITCH_ATTR_OP_PORT,
  1779. + SWITCH_ATTR_OP_VLAN,
  1780. + SWITCH_ATTR_OP_VALUE_INT,
  1781. + SWITCH_ATTR_OP_VALUE_STR,
  1782. + SWITCH_ATTR_OP_VALUE_PORTS,
  1783. + SWITCH_ATTR_OP_DESCRIPTION,
  1784. + /* port lists */
  1785. + SWITCH_ATTR_PORT,
  1786. + SWITCH_ATTR_MAX
  1787. +};
  1788. +
  1789. +enum {
  1790. + /* port map */
  1791. + SWITCH_PORTMAP_PORTS,
  1792. + SWITCH_PORTMAP_SEGMENT,
  1793. + SWITCH_PORTMAP_VIRT,
  1794. + SWITCH_PORTMAP_MAX
  1795. +};
  1796. +
  1797. +/* commands */
  1798. +enum {
  1799. + SWITCH_CMD_UNSPEC,
  1800. + SWITCH_CMD_GET_SWITCH,
  1801. + SWITCH_CMD_NEW_ATTR,
  1802. + SWITCH_CMD_LIST_GLOBAL,
  1803. + SWITCH_CMD_GET_GLOBAL,
  1804. + SWITCH_CMD_SET_GLOBAL,
  1805. + SWITCH_CMD_LIST_PORT,
  1806. + SWITCH_CMD_GET_PORT,
  1807. + SWITCH_CMD_SET_PORT,
  1808. + SWITCH_CMD_LIST_VLAN,
  1809. + SWITCH_CMD_GET_VLAN,
  1810. + SWITCH_CMD_SET_VLAN
  1811. +};
  1812. +
  1813. +/* data types */
  1814. +enum switch_val_type {
  1815. + SWITCH_TYPE_UNSPEC,
  1816. + SWITCH_TYPE_INT,
  1817. + SWITCH_TYPE_STRING,
  1818. + SWITCH_TYPE_PORTS,
  1819. + SWITCH_TYPE_NOVAL,
  1820. +};
  1821. +
  1822. +/* port nested attributes */
  1823. +enum {
  1824. + SWITCH_PORT_UNSPEC,
  1825. + SWITCH_PORT_ID,
  1826. + SWITCH_PORT_FLAG_TAGGED,
  1827. + SWITCH_PORT_ATTR_MAX
  1828. +};
  1829. +
  1830. +#define SWITCH_ATTR_DEFAULTS_OFFSET 0x1000
  1831. +
  1832. +
  1833. +#endif /* _UAPI_LINUX_SWITCH_H */