]>
Commit | Line | Data |
---|---|---|
94c98157 AA |
1 | /* -*- mode: c; c-file-style: "openbsd" -*- */ |
2 | /* | |
3 | * Copyright (c) 2015 Vincent Bernat <vincent@bernat.im> | |
4 | * | |
5 | * Permission to use, copy, modify, and/or distribute this software for any | |
6 | * purpose with or without fee is hereby granted, provided that the above | |
7 | * copyright notice and this permission notice appear in all copies. | |
8 | * | |
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
16 | */ | |
17 | ||
18 | #include <stdio.h> | |
19 | #include <stdarg.h> | |
20 | #include <string.h> | |
21 | #include <arpa/inet.h> | |
22 | ||
23 | #include "lldpctl.h" | |
94c98157 | 24 | #include "../log.h" |
a5f98717 | 25 | #include "atom.h" |
94c98157 AA |
26 | #include "helpers.h" |
27 | ||
28 | static struct atom_map lldpd_protocol_map = { | |
29 | .key = lldpctl_k_port_protocol, | |
30 | .map = { | |
31 | { LLDPD_MODE_LLDP, "LLDP" }, | |
32 | { LLDPD_MODE_CDPV1, "CDPv1"}, | |
33 | { LLDPD_MODE_CDPV2, "CDPv2"}, | |
34 | { LLDPD_MODE_EDP, "EDP" }, | |
35 | { LLDPD_MODE_FDP, "FDP"}, | |
36 | { LLDPD_MODE_SONMP, "SONMP"}, | |
37 | { 0, NULL }, | |
38 | } | |
39 | }; | |
40 | ||
41 | ATOM_MAP_REGISTER(lldpd_protocol_map, 3); | |
42 | ||
43 | static lldpctl_map_t port_id_subtype_map[] = { | |
44 | { LLDP_PORTID_SUBTYPE_IFNAME, "ifname"}, | |
45 | { LLDP_PORTID_SUBTYPE_IFALIAS, "ifalias" }, | |
46 | { LLDP_PORTID_SUBTYPE_LOCAL, "local" }, | |
47 | { LLDP_PORTID_SUBTYPE_LLADDR, "mac" }, | |
48 | { LLDP_PORTID_SUBTYPE_ADDR, "ip" }, | |
49 | { LLDP_PORTID_SUBTYPE_PORT, "unhandled" }, | |
50 | { LLDP_PORTID_SUBTYPE_AGENTCID, "unhandled" }, | |
51 | { 0, NULL}, | |
52 | }; | |
53 | ||
e7331ce9 VB |
54 | static struct atom_map port_status_map = { |
55 | .key = lldpctl_k_port_status, | |
56 | .map = { | |
57 | { LLDPD_RXTX_TXONLY, "TX only" }, | |
58 | { LLDPD_RXTX_RXONLY, "RX only" }, | |
59 | { LLDPD_RXTX_DISABLED, "disabled" }, | |
60 | { LLDPD_RXTX_BOTH, "RX and TX" }, | |
61 | { 0, NULL }, | |
62 | } | |
63 | }; | |
64 | ||
65 | ATOM_MAP_REGISTER(port_status_map, 3); | |
66 | ||
5458f879 | 67 | #ifdef ENABLE_DOT3 |
94c98157 | 68 | static lldpctl_map_t operational_mau_type_values[] = { |
9bf35ec4 VB |
69 | { LLDP_DOT3_MAU_AUI, "AUI - No internal MAU, view from AUI" }, |
70 | { LLDP_DOT3_MAU_10BASE5, "10Base5 - Thick coax MAU" }, | |
71 | { LLDP_DOT3_MAU_FOIRL, "Foirl - FOIRL MAU" }, | |
72 | { LLDP_DOT3_MAU_10BASE2, "10Base2 - Thin coax MAU" }, | |
73 | { LLDP_DOT3_MAU_10BASET, "10BaseT - UTP MAU" }, | |
74 | { LLDP_DOT3_MAU_10BASEFP, "10BaseFP - Passive fiber MAU" }, | |
75 | { LLDP_DOT3_MAU_10BASEFB, "10BaseFB - Sync fiber MAU" }, | |
76 | { LLDP_DOT3_MAU_10BASEFL, "10BaseFL - Async fiber MAU" }, | |
77 | { LLDP_DOT3_MAU_10BROAD36, "10Broad36 - Broadband DTE MAU" }, | |
78 | { LLDP_DOT3_MAU_10BASETHD, "10BaseTHD - UTP MAU, half duplex mode" }, | |
79 | { LLDP_DOT3_MAU_10BASETFD, "10BaseTFD - UTP MAU, full duplex mode" }, | |
80 | { LLDP_DOT3_MAU_10BASEFLHD, "10BaseFLHD - Async fiber MAU, half duplex mode" }, | |
81 | { LLDP_DOT3_MAU_10BASEFLFD, "10BaseFLDF - Async fiber MAU, full duplex mode" }, | |
82 | { LLDP_DOT3_MAU_100BASET4, "100BaseT4 - 4 pair category 3 UTP" }, | |
83 | { LLDP_DOT3_MAU_100BASETXHD, "100BaseTXHD - 2 pair category 5 UTP, half duplex mode" }, | |
84 | { LLDP_DOT3_MAU_100BASETXFD, "100BaseTXFD - 2 pair category 5 UTP, full duplex mode" }, | |
85 | { LLDP_DOT3_MAU_100BASEFXHD, "100BaseFXHD - X fiber over PMT, half duplex mode" }, | |
86 | { LLDP_DOT3_MAU_100BASEFXFD, "100BaseFXFD - X fiber over PMT, full duplex mode" }, | |
87 | { LLDP_DOT3_MAU_100BASET2HD, "100BaseT2HD - 2 pair category 3 UTP, half duplex mode" }, | |
88 | { LLDP_DOT3_MAU_100BASET2FD, "100BaseT2FD - 2 pair category 3 UTP, full duplex mode" }, | |
89 | { LLDP_DOT3_MAU_1000BASEXHD, "1000BaseXHD - PCS/PMA, unknown PMD, half duplex mode" }, | |
90 | { LLDP_DOT3_MAU_1000BASEXFD, "1000BaseXFD - PCS/PMA, unknown PMD, full duplex mode" }, | |
91 | { LLDP_DOT3_MAU_1000BASELXHD, "1000BaseLXHD - Fiber over long-wavelength laser, half duplex mode" }, | |
92 | { LLDP_DOT3_MAU_1000BASELXFD, "1000BaseLXFD - Fiber over long-wavelength laser, full duplex mode" }, | |
93 | { LLDP_DOT3_MAU_1000BASESXHD, "1000BaseSXHD - Fiber over short-wavelength laser, half duplex mode" }, | |
94 | { LLDP_DOT3_MAU_1000BASESXFD, "1000BaseSXFD - Fiber over short-wavelength laser, full duplex mode" }, | |
95 | { LLDP_DOT3_MAU_1000BASECXHD, "1000BaseCXHD - Copper over 150-Ohm balanced cable, half duplex mode" }, | |
96 | { LLDP_DOT3_MAU_1000BASECXFD, "1000BaseCXFD - Copper over 150-Ohm balanced cable, full duplex mode" }, | |
97 | { LLDP_DOT3_MAU_1000BASETHD, "1000BaseTHD - Four-pair Category 5 UTP, half duplex mode" }, | |
98 | { LLDP_DOT3_MAU_1000BASETFD, "1000BaseTFD - Four-pair Category 5 UTP, full duplex mode" }, | |
99 | { LLDP_DOT3_MAU_10GIGBASEX, "10GigBaseX - X PCS/PMA, unknown PMD." }, | |
100 | { LLDP_DOT3_MAU_10GIGBASELX4, "10GigBaseLX4 - X fiber over WWDM optics" }, | |
101 | { LLDP_DOT3_MAU_10GIGBASER, "10GigBaseR - R PCS/PMA, unknown PMD." }, | |
102 | { LLDP_DOT3_MAU_10GIGBASEER, "10GigBaseER - R fiber over 1550 nm optics" }, | |
103 | { LLDP_DOT3_MAU_10GIGBASELR, "10GigBaseLR - R fiber over 1310 nm optics" }, | |
104 | { LLDP_DOT3_MAU_10GIGBASESR, "10GigBaseSR - R fiber over 850 nm optics" }, | |
105 | { LLDP_DOT3_MAU_10GIGBASEW, "10GigBaseW - W PCS/PMA, unknown PMD." }, | |
106 | { LLDP_DOT3_MAU_10GIGBASEEW, "10GigBaseEW - W fiber over 1550 nm optics" }, | |
107 | { LLDP_DOT3_MAU_10GIGBASELW, "10GigBaseLW - W fiber over 1310 nm optics" }, | |
108 | { LLDP_DOT3_MAU_10GIGBASESW, "10GigBaseSW - W fiber over 850 nm optics" }, | |
109 | { LLDP_DOT3_MAU_10GIGBASECX4, "10GigBaseCX4 - X copper over 8 pair 100-Ohm balanced cable" }, | |
110 | { LLDP_DOT3_MAU_2BASETL, "2BaseTL - Voice grade UTP copper, up to 2700m, optional PAF" }, | |
111 | { LLDP_DOT3_MAU_10PASSTS, "10PassTS - Voice grade UTP copper, up to 750m, optional PAF" }, | |
112 | { LLDP_DOT3_MAU_100BASEBX10D, "100BaseBX10D - One single-mode fiber OLT, long wavelength, 10km" }, | |
113 | { LLDP_DOT3_MAU_100BASEBX10U, "100BaseBX10U - One single-mode fiber ONU, long wavelength, 10km" }, | |
114 | { LLDP_DOT3_MAU_100BASELX10, "100BaseLX10 - Two single-mode fibers, long wavelength, 10km" }, | |
115 | { LLDP_DOT3_MAU_1000BASEBX10D, "1000BaseBX10D - One single-mode fiber OLT, long wavelength, 10km" }, | |
116 | { LLDP_DOT3_MAU_1000BASEBX10U, "1000BaseBX10U - One single-mode fiber ONU, long wavelength, 10km" }, | |
117 | { LLDP_DOT3_MAU_1000BASELX10, "1000BaseLX10 - Two sigle-mode fiber, long wavelength, 10km" }, | |
118 | { LLDP_DOT3_MAU_1000BASEPX10D, "1000BasePX10D - One single-mode fiber EPON OLT, 10km" }, | |
119 | { LLDP_DOT3_MAU_1000BASEPX10U, "1000BasePX10U - One single-mode fiber EPON ONU, 10km" }, | |
120 | { LLDP_DOT3_MAU_1000BASEPX20D, "1000BasePX20D - One single-mode fiber EPON OLT, 20km" }, | |
121 | { LLDP_DOT3_MAU_1000BASEPX20U, "1000BasePX20U - One single-mode fiber EPON ONU, 20km" }, | |
122 | { LLDP_DOT3_MAU_10GBASET, "10GbaseT - Four-pair Category 6A or better, full duplex mode only" }, | |
123 | { LLDP_DOT3_MAU_10GBASELRM, "10GbaseLRM - R multimode fiber over 1310 nm optics" }, | |
124 | { LLDP_DOT3_MAU_1000BASEKX, "1000baseKX - X backplane, full duplex mode only" }, | |
125 | { LLDP_DOT3_MAU_10GBASEKX4, "10GbaseKX4 - 4 lane X backplane, full duplex mode only" }, | |
126 | { LLDP_DOT3_MAU_10GBASEKR, "10GbaseKR - R backplane, full duplex mode only" }, | |
127 | { LLDP_DOT3_MAU_10G1GBASEPRXD1, "10G1GbasePRXD1 - One single-mode fiber asymmetric-rate EPON OLT, low power budget (PRX10)" }, | |
128 | { LLDP_DOT3_MAU_10G1GBASEPRXD2, "10G1GbasePRXD2 - One single-mode fiber asymmetric-rate EPON OLT, medium power budget (PRX20)" }, | |
129 | { LLDP_DOT3_MAU_10G1GBASEPRXD3, "10G1GbasePRXD3 - One single-mode fiber asymmetric-rate EPON OLT, high power budget (PRX30)" }, | |
130 | { LLDP_DOT3_MAU_10G1GBASEPRXU1, "10G1GbasePRXU1 - One single-mode fiber asymmetric-rate EPON ONU, low power budget (PRX10)" }, | |
131 | { LLDP_DOT3_MAU_10G1GBASEPRXU2, "10G1GbasePRXU2 - One single-mode fiber asymmetric-rate EPON ONU, medium power budget (PRX20)" }, | |
132 | { LLDP_DOT3_MAU_10G1GBASEPRXU3, "10G1GbasePRXU3 - One single-mode fiber asymmetric-rate EPON ONU, high power budget (PRX30)" }, | |
133 | { LLDP_DOT3_MAU_10GBASEPRD1, "10GbasePRD1 - One single-mode fiber symmetric-rate EPON OLT, low power budget (PR10)" }, | |
134 | { LLDP_DOT3_MAU_10GBASEPRD2, "10GbasePRD2 - One single-mode fiber symmetric-rate EPON OLT, medium power budget (PR20)" }, | |
135 | { LLDP_DOT3_MAU_10GBASEPRD3, "10GbasePRD3 - One single-mode fiber symmetric-rate EPON OLT, high power budget (PR30)" }, | |
136 | { LLDP_DOT3_MAU_10GBASEPRU1, "10GbasePRU1 - One single-mode fiber symmetric-rate EPON ONU, low and medium power budget" }, | |
137 | { LLDP_DOT3_MAU_10GBASEPRU3, "10GbasePRU3 - One single-mode fiber symmetric-rate EPON ONU, high power budget (PR30)" }, | |
138 | { LLDP_DOT3_MAU_40GBASEKR4, "40GbaseKR4 - 40GBASE-R PCS/PMA over an electrical backplane" }, | |
139 | { LLDP_DOT3_MAU_40GBASECR4, "40GbaseCR4 - 40GBASE-R PCS/PMA over 4 lane shielded copper balanced cable" }, | |
140 | { LLDP_DOT3_MAU_40GBASESR4, "40GbaseSR4 - 40GBASE-R PCS/PMA over 4 lane multimode fiber" }, | |
141 | { LLDP_DOT3_MAU_40GBASEFR, "40GbaseFR - 40GBASE-R PCS/PMA over single mode fiber" }, | |
142 | { LLDP_DOT3_MAU_40GBASELR4, "40GbaseLR4 - 40GBASE-R PCS/PMA over 4 WDM lane single mode fiber" }, | |
143 | { LLDP_DOT3_MAU_100GBASECR10, "100GbaseCR10 - 100GBASE-R PCS/PMA over 10 lane shielded copper balanced cable" }, | |
144 | { LLDP_DOT3_MAU_100GBASESR10, "100GbaseSR10 - 100GBASE-R PCS/PMA over 10 lane multimode fiber" }, | |
145 | { LLDP_DOT3_MAU_100GBASELR4, "100GbaseLR4 - 100GBASE-R PCS/PMA over 4 WDM lane single mode fiber, long reach" }, | |
146 | { LLDP_DOT3_MAU_100GBASEER4, "100GbaseER4 - 100GBASE-R PCS/PMA over 4 WDM lane single mode fiber PMD, extended reach" }, | |
94c98157 AA |
147 | { 0, NULL } |
148 | }; | |
5458f879 | 149 | #endif |
94c98157 | 150 | |
94c98157 AA |
151 | static lldpctl_atom_iter_t* |
152 | _lldpctl_atom_iter_ports_list(lldpctl_atom_t *atom) | |
153 | { | |
154 | struct _lldpctl_atom_any_list_t *plist = | |
155 | (struct _lldpctl_atom_any_list_t *)atom; | |
156 | return (lldpctl_atom_iter_t*)TAILQ_FIRST(&plist->parent->hardware->h_rports); | |
157 | } | |
158 | ||
159 | static lldpctl_atom_iter_t* | |
160 | _lldpctl_atom_next_ports_list(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter) | |
161 | { | |
162 | struct lldpd_port *port = (struct lldpd_port *)iter; | |
163 | return (lldpctl_atom_iter_t*)TAILQ_NEXT(port, p_entries); | |
164 | } | |
165 | ||
166 | static lldpctl_atom_t* | |
167 | _lldpctl_atom_value_ports_list(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter) | |
168 | { | |
169 | struct lldpd_port *port = (struct lldpd_port *)iter; | |
9da663f7 | 170 | return _lldpctl_new_atom(atom->conn, atom_port, 0, NULL, port, |
94c98157 AA |
171 | ((struct _lldpctl_atom_any_list_t *)atom)->parent); |
172 | } | |
173 | ||
174 | static int | |
175 | _lldpctl_atom_new_port(lldpctl_atom_t *atom, va_list ap) | |
176 | { | |
177 | struct _lldpctl_atom_port_t *port = | |
178 | (struct _lldpctl_atom_port_t *)atom; | |
9da663f7 | 179 | port->local = va_arg(ap, int); |
94c98157 AA |
180 | port->hardware = va_arg(ap, struct lldpd_hardware*); |
181 | port->port = va_arg(ap, struct lldpd_port*); | |
182 | port->parent = va_arg(ap, struct _lldpctl_atom_port_t*); | |
183 | if (port->parent) | |
184 | lldpctl_atom_inc_ref((lldpctl_atom_t*)port->parent); | |
e55e7492 | 185 | |
825b37a7 BH |
186 | if (port->port) { |
187 | /* Internal atom. We are the parent, but our reference count is | |
188 | * not incremented. */ | |
189 | port->chassis = _lldpctl_new_atom(atom->conn, atom_chassis, | |
190 | port->port->p_chassis, port, 1); | |
191 | } | |
94c98157 AA |
192 | return 1; |
193 | } | |
194 | ||
195 | TAILQ_HEAD(chassis_list, lldpd_chassis); | |
196 | ||
197 | static void | |
198 | add_chassis(struct chassis_list *chassis_list, | |
199 | struct lldpd_chassis *chassis) | |
200 | { | |
201 | struct lldpd_chassis *one_chassis; | |
202 | TAILQ_FOREACH(one_chassis, chassis_list, c_entries) { | |
203 | if (one_chassis == chassis) return; | |
204 | } | |
205 | TAILQ_INSERT_TAIL(chassis_list, | |
206 | chassis, c_entries); | |
207 | } | |
208 | ||
209 | static void | |
210 | _lldpctl_atom_free_port(lldpctl_atom_t *atom) | |
211 | { | |
212 | struct _lldpctl_atom_port_t *port = | |
213 | (struct _lldpctl_atom_port_t *)atom; | |
214 | struct lldpd_hardware *hardware = port->hardware; | |
215 | struct lldpd_chassis *one_chassis, *one_chassis_next; | |
216 | struct lldpd_port *one_port; | |
217 | ||
e55e7492 VB |
218 | /* Free internal chassis atom. Should be freed immediately since we |
219 | * should have the only reference. */ | |
220 | lldpctl_atom_dec_ref((lldpctl_atom_t*)port->chassis); | |
221 | ||
94c98157 AA |
222 | /* We need to free the whole struct lldpd_hardware: local port, local |
223 | * chassis and remote ports... The same chassis may be present several | |
224 | * times. We build a list of chassis (we don't use reference count). */ | |
225 | struct chassis_list chassis_list; | |
226 | TAILQ_INIT(&chassis_list); | |
227 | ||
228 | if (port->parent) lldpctl_atom_dec_ref((lldpctl_atom_t*)port->parent); | |
825b37a7 | 229 | else if (!hardware && port->port) { |
94c98157 AA |
230 | /* No parent, no hardware, we assume a single neighbor: one |
231 | * port, one chassis. */ | |
9da663f7 VB |
232 | if (port->port->p_chassis) { |
233 | lldpd_chassis_cleanup(port->port->p_chassis, 1); | |
234 | port->port->p_chassis = NULL; | |
235 | } | |
94c98157 AA |
236 | lldpd_port_cleanup(port->port, 1); |
237 | free(port->port); | |
238 | } | |
239 | if (!hardware) return; | |
240 | ||
241 | add_chassis(&chassis_list, port->port->p_chassis); | |
242 | TAILQ_FOREACH(one_port, &hardware->h_rports, p_entries) | |
243 | add_chassis(&chassis_list, one_port->p_chassis); | |
244 | ||
245 | /* Free hardware port */ | |
246 | lldpd_remote_cleanup(hardware, NULL, 1); | |
247 | lldpd_port_cleanup(port->port, 1); | |
248 | free(port->hardware); | |
249 | ||
250 | /* Free list of chassis */ | |
251 | for (one_chassis = TAILQ_FIRST(&chassis_list); | |
252 | one_chassis != NULL; | |
253 | one_chassis = one_chassis_next) { | |
254 | one_chassis_next = TAILQ_NEXT(one_chassis, c_entries); | |
255 | lldpd_chassis_cleanup(one_chassis, 1); | |
256 | } | |
257 | } | |
258 | ||
259 | static lldpctl_atom_t* | |
260 | _lldpctl_atom_get_atom_port(lldpctl_atom_t *atom, lldpctl_key_t key) | |
261 | { | |
262 | struct _lldpctl_atom_port_t *p = | |
263 | (struct _lldpctl_atom_port_t *)atom; | |
264 | struct lldpd_port *port = p->port; | |
265 | struct lldpd_hardware *hardware = p->hardware; | |
266 | ||
267 | /* Local port only */ | |
268 | if (hardware != NULL) { | |
269 | switch (key) { | |
270 | case lldpctl_k_port_neighbors: | |
271 | return _lldpctl_new_atom(atom->conn, atom_ports_list, p); | |
272 | default: break; | |
273 | } | |
274 | } | |
275 | ||
276 | /* Local and remote port */ | |
277 | switch (key) { | |
99ef55d3 | 278 | case lldpctl_k_port_chassis: |
9da663f7 VB |
279 | if (port->p_chassis) { |
280 | return _lldpctl_new_atom(atom->conn, atom_chassis, | |
281 | port->p_chassis, p, 0); | |
282 | } | |
283 | SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); | |
284 | return NULL; | |
94c98157 AA |
285 | #ifdef ENABLE_DOT3 |
286 | case lldpctl_k_port_dot3_power: | |
287 | return _lldpctl_new_atom(atom->conn, atom_dot3_power, | |
288 | p); | |
289 | #endif | |
290 | #ifdef ENABLE_DOT1 | |
291 | case lldpctl_k_port_vlans: | |
292 | return _lldpctl_new_atom(atom->conn, atom_vlans_list, | |
293 | p); | |
294 | case lldpctl_k_port_ppvids: | |
295 | return _lldpctl_new_atom(atom->conn, atom_ppvids_list, | |
296 | p); | |
297 | case lldpctl_k_port_pis: | |
298 | return _lldpctl_new_atom(atom->conn, atom_pis_list, | |
299 | p); | |
300 | #endif | |
301 | #ifdef ENABLE_LLDPMED | |
302 | case lldpctl_k_port_med_policies: | |
303 | return _lldpctl_new_atom(atom->conn, atom_med_policies_list, | |
304 | p); | |
305 | case lldpctl_k_port_med_locations: | |
306 | return _lldpctl_new_atom(atom->conn, atom_med_locations_list, | |
307 | p); | |
308 | case lldpctl_k_port_med_power: | |
309 | return _lldpctl_new_atom(atom->conn, atom_med_power, p); | |
310 | #endif | |
fb1b78bb | 311 | #ifdef ENABLE_CUSTOM |
c576fd21 AA |
312 | case lldpctl_k_custom_tlvs: |
313 | return _lldpctl_new_atom(atom->conn, atom_custom_list, p); | |
fb1b78bb | 314 | #endif |
94c98157 | 315 | default: |
e55e7492 | 316 | /* Compatibility: query the associated chassis too */ |
9da663f7 VB |
317 | if (port->p_chassis) |
318 | return lldpctl_atom_get(p->chassis, key); | |
319 | SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); | |
320 | return NULL; | |
94c98157 AA |
321 | } |
322 | } | |
323 | ||
324 | static lldpctl_atom_t* | |
325 | _lldpctl_atom_set_atom_port(lldpctl_atom_t *atom, lldpctl_key_t key, lldpctl_atom_t *value) | |
326 | { | |
327 | struct _lldpctl_atom_port_t *p = | |
328 | (struct _lldpctl_atom_port_t *)atom; | |
329 | struct lldpd_hardware *hardware = p->hardware; | |
330 | struct lldpd_port_set set = {}; | |
331 | int rc; | |
332 | char *canary; | |
333 | ||
334 | #ifdef ENABLE_DOT3 | |
335 | struct _lldpctl_atom_dot3_power_t *dpow; | |
336 | #endif | |
337 | #ifdef ENABLE_LLDPMED | |
338 | struct _lldpctl_atom_med_power_t *mpow; | |
339 | struct _lldpctl_atom_med_policy_t *mpol; | |
340 | struct _lldpctl_atom_med_location_t *mloc; | |
341 | #endif | |
fb1b78bb | 342 | #ifdef ENABLE_CUSTOM |
c576fd21 | 343 | struct _lldpctl_atom_custom_t *custom; |
fb1b78bb | 344 | #endif |
94c98157 | 345 | |
9da663f7 VB |
346 | /* Local and default port only */ |
347 | if (!p->local) { | |
94c98157 AA |
348 | SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); |
349 | return NULL; | |
350 | } | |
351 | ||
352 | switch (key) { | |
353 | case lldpctl_k_port_id: | |
354 | set.local_id = p->port->p_id; | |
355 | break; | |
356 | case lldpctl_k_port_descr: | |
357 | set.local_descr = p->port->p_descr; | |
358 | break; | |
e7331ce9 VB |
359 | case lldpctl_k_port_status: |
360 | set.rxtx = LLDPD_RXTX_FROM_PORT(p->port); | |
361 | break; | |
94c98157 AA |
362 | #ifdef ENABLE_DOT3 |
363 | case lldpctl_k_port_dot3_power: | |
364 | if (value->type != atom_dot3_power) { | |
365 | SET_ERROR(atom->conn, LLDPCTL_ERR_INCORRECT_ATOM_TYPE); | |
366 | return NULL; | |
367 | } | |
368 | ||
369 | dpow = (struct _lldpctl_atom_dot3_power_t *)value; | |
370 | set.dot3_power = &dpow->parent->port->p_power; | |
371 | break; | |
372 | #endif | |
373 | #ifdef ENABLE_LLDPMED | |
374 | case lldpctl_k_port_med_power: | |
375 | if (value->type != atom_med_power) { | |
376 | SET_ERROR(atom->conn, LLDPCTL_ERR_INCORRECT_ATOM_TYPE); | |
377 | return NULL; | |
378 | } | |
379 | ||
380 | mpow = (struct _lldpctl_atom_med_power_t *)value; | |
381 | set.med_power = &mpow->parent->port->p_med_power; | |
382 | break; | |
383 | case lldpctl_k_port_med_policies: | |
384 | if (value->type != atom_med_policy) { | |
385 | SET_ERROR(atom->conn, LLDPCTL_ERR_INCORRECT_ATOM_TYPE); | |
386 | return NULL; | |
387 | } | |
388 | mpol = (struct _lldpctl_atom_med_policy_t *)value; | |
389 | set.med_policy = mpol->policy; | |
390 | break; | |
391 | case lldpctl_k_port_med_locations: | |
392 | if (value->type != atom_med_location) { | |
393 | SET_ERROR(atom->conn, LLDPCTL_ERR_INCORRECT_ATOM_TYPE); | |
394 | return NULL; | |
395 | } | |
396 | mloc = (struct _lldpctl_atom_med_location_t *)value; | |
397 | set.med_location = mloc->location; | |
398 | break; | |
399 | #endif | |
fb1b78bb | 400 | #ifdef ENABLE_CUSTOM |
c576fd21 AA |
401 | case lldpctl_k_custom_tlvs_clear: |
402 | set.custom_list_clear = 1; | |
403 | break; | |
404 | case lldpctl_k_custom_tlv: | |
405 | if (value->type != atom_custom) { | |
406 | SET_ERROR(atom->conn, LLDPCTL_ERR_INCORRECT_ATOM_TYPE); | |
407 | return NULL; | |
408 | } | |
409 | custom = (struct _lldpctl_atom_custom_t *)value; | |
410 | set.custom = custom->tlv; | |
7c26c8b4 | 411 | set.custom_tlv_op = custom->op; |
c576fd21 | 412 | break; |
fb1b78bb | 413 | #endif |
94c98157 AA |
414 | default: |
415 | SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); | |
416 | return NULL; | |
417 | } | |
418 | ||
9da663f7 | 419 | set.ifname = hardware ? hardware->h_ifname : ""; |
94c98157 AA |
420 | |
421 | if (asprintf(&canary, "%d%p%s", key, value, set.ifname) == -1) { | |
422 | SET_ERROR(atom->conn, LLDPCTL_ERR_NOMEM); | |
423 | return NULL; | |
424 | } | |
425 | rc = _lldpctl_do_something(atom->conn, | |
426 | CONN_STATE_SET_PORT_SEND, CONN_STATE_SET_PORT_RECV, | |
427 | canary, | |
428 | SET_PORT, &set, &MARSHAL_INFO(lldpd_port_set), | |
429 | NULL, NULL); | |
430 | free(canary); | |
431 | if (rc == 0) return atom; | |
432 | return NULL; | |
433 | } | |
434 | ||
435 | static const char* | |
436 | _lldpctl_atom_get_str_port(lldpctl_atom_t *atom, lldpctl_key_t key) | |
437 | { | |
438 | struct _lldpctl_atom_port_t *p = | |
439 | (struct _lldpctl_atom_port_t *)atom; | |
440 | struct lldpd_port *port = p->port; | |
441 | struct lldpd_hardware *hardware = p->hardware; | |
94c98157 AA |
442 | char *ipaddress = NULL; size_t len; |
443 | ||
444 | /* Local port only */ | |
e7331ce9 VB |
445 | switch (key) { |
446 | case lldpctl_k_port_name: | |
447 | if (hardware != NULL) return hardware->h_ifname; | |
448 | break; | |
449 | case lldpctl_k_port_status: | |
450 | if (p->local) return map_lookup(port_status_map.map, | |
451 | LLDPD_RXTX_FROM_PORT(port)); | |
452 | break; | |
453 | default: break; | |
94c98157 AA |
454 | } |
455 | ||
825b37a7 BH |
456 | if (!port) |
457 | return NULL; | |
458 | ||
94c98157 AA |
459 | /* Local and remote port */ |
460 | switch (key) { | |
461 | case lldpctl_k_port_protocol: | |
462 | return map_lookup(lldpd_protocol_map.map, port->p_protocol); | |
463 | case lldpctl_k_port_id_subtype: | |
464 | return map_lookup(port_id_subtype_map, port->p_id_subtype); | |
465 | case lldpctl_k_port_id: | |
466 | switch (port->p_id_subtype) { | |
467 | case LLDP_PORTID_SUBTYPE_IFNAME: | |
468 | case LLDP_PORTID_SUBTYPE_IFALIAS: | |
469 | case LLDP_PORTID_SUBTYPE_LOCAL: | |
470 | return port->p_id; | |
471 | case LLDP_PORTID_SUBTYPE_LLADDR: | |
472 | return _lldpctl_dump_in_atom(atom, | |
473 | (uint8_t*)port->p_id, port->p_id_len, | |
474 | ':', 0); | |
475 | case LLDP_PORTID_SUBTYPE_ADDR: | |
476 | switch (port->p_id[0]) { | |
477 | case LLDP_MGMT_ADDR_IP4: len = INET_ADDRSTRLEN + 1; break; | |
478 | case LLDP_MGMT_ADDR_IP6: len = INET6_ADDRSTRLEN + 1; break; | |
479 | default: len = 0; | |
480 | } | |
481 | if (len > 0) { | |
482 | ipaddress = _lldpctl_alloc_in_atom(atom, len); | |
483 | if (!ipaddress) return NULL; | |
484 | if (inet_ntop((port->p_id[0] == LLDP_MGMT_ADDR_IP4)? | |
485 | AF_INET:AF_INET6, | |
486 | &port->p_id[1], ipaddress, len) == NULL) | |
487 | break; | |
488 | return ipaddress; | |
489 | } | |
490 | break; | |
491 | } | |
492 | SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); | |
493 | return NULL; | |
494 | case lldpctl_k_port_descr: | |
495 | return port->p_descr; | |
496 | ||
497 | #ifdef ENABLE_DOT3 | |
498 | case lldpctl_k_port_dot3_mautype: | |
499 | return map_lookup(operational_mau_type_values, | |
500 | port->p_macphy.mau_type); | |
501 | #endif | |
502 | ||
94c98157 | 503 | default: |
e55e7492 VB |
504 | /* Compatibility: query the associated chassis too */ |
505 | return lldpctl_atom_get_str(p->chassis, key); | |
94c98157 AA |
506 | } |
507 | } | |
508 | ||
e7331ce9 VB |
509 | static lldpctl_atom_t* |
510 | _lldpctl_atom_set_int_port(lldpctl_atom_t *atom, lldpctl_key_t key, | |
511 | long int value) | |
512 | { | |
513 | struct _lldpctl_atom_port_t *p = | |
514 | (struct _lldpctl_atom_port_t *)atom; | |
515 | struct lldpd_port *port = p->port; | |
516 | ||
517 | if (p->local) { | |
518 | switch (key) { | |
519 | case lldpctl_k_port_status: | |
520 | port->p_disable_rx = !LLDPD_RXTX_RXENABLED(value); | |
521 | port->p_disable_tx = !LLDPD_RXTX_TXENABLED(value); | |
522 | break; | |
523 | default: | |
524 | SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); | |
525 | return NULL; | |
526 | } | |
527 | } else { | |
528 | SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); | |
529 | return NULL; | |
530 | } | |
531 | ||
532 | return _lldpctl_atom_set_atom_port(atom, key, NULL); | |
533 | } | |
534 | ||
94c98157 AA |
535 | static lldpctl_atom_t* |
536 | _lldpctl_atom_set_str_port(lldpctl_atom_t *atom, lldpctl_key_t key, | |
537 | const char *value) | |
538 | { | |
539 | struct _lldpctl_atom_port_t *p = | |
540 | (struct _lldpctl_atom_port_t *)atom; | |
541 | struct lldpd_port *port = p->port; | |
542 | ||
543 | if (!value || !strlen(value)) | |
544 | return NULL; | |
545 | ||
e7331ce9 VB |
546 | if (p->local) { |
547 | switch (key) { | |
548 | case lldpctl_k_port_status: | |
549 | return _lldpctl_atom_set_int_port(atom, key, | |
550 | map_reverse_lookup(port_status_map.map, value)); | |
551 | default: break; | |
552 | } | |
553 | } | |
554 | ||
94c98157 AA |
555 | switch (key) { |
556 | case lldpctl_k_port_id: | |
557 | free(port->p_id); | |
558 | port->p_id = strdup(value); | |
559 | port->p_id_len = strlen(value); | |
560 | break; | |
561 | case lldpctl_k_port_descr: | |
562 | free(port->p_descr); | |
563 | port->p_descr = strdup(value); | |
564 | break; | |
565 | default: | |
566 | SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); | |
567 | return NULL; | |
568 | } | |
569 | ||
570 | return _lldpctl_atom_set_atom_port(atom, key, NULL); | |
571 | } | |
572 | ||
573 | static long int | |
574 | _lldpctl_atom_get_int_port(lldpctl_atom_t *atom, lldpctl_key_t key) | |
575 | { | |
576 | struct _lldpctl_atom_port_t *p = | |
577 | (struct _lldpctl_atom_port_t *)atom; | |
578 | struct lldpd_port *port = p->port; | |
579 | struct lldpd_hardware *hardware = p->hardware; | |
94c98157 AA |
580 | |
581 | /* Local port only */ | |
582 | if (hardware != NULL) { | |
583 | switch (key) { | |
584 | case lldpctl_k_port_index: | |
585 | return hardware->h_ifindex; | |
586 | case lldpctl_k_tx_cnt: | |
587 | return hardware->h_tx_cnt; | |
588 | case lldpctl_k_rx_cnt: | |
589 | return hardware->h_rx_cnt; | |
590 | case lldpctl_k_rx_discarded_cnt: | |
591 | return hardware->h_rx_discarded_cnt; | |
592 | case lldpctl_k_rx_unrecognized_cnt: | |
593 | return hardware->h_rx_unrecognized_cnt; | |
594 | case lldpctl_k_ageout_cnt: | |
595 | return hardware->h_ageout_cnt; | |
596 | case lldpctl_k_insert_cnt: | |
597 | return hardware->h_insert_cnt; | |
598 | case lldpctl_k_delete_cnt: | |
599 | return hardware->h_delete_cnt; | |
600 | default: break; | |
601 | } | |
602 | } | |
e7331ce9 VB |
603 | if (p->local) { |
604 | switch (key) { | |
605 | case lldpctl_k_port_status: | |
606 | return LLDPD_RXTX_FROM_PORT(port); | |
607 | default: break; | |
608 | } | |
609 | } | |
825b37a7 BH |
610 | if (!port) |
611 | return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); | |
94c98157 AA |
612 | |
613 | /* Local and remote port */ | |
614 | switch (key) { | |
615 | case lldpctl_k_port_protocol: | |
616 | return port->p_protocol; | |
617 | case lldpctl_k_port_age: | |
618 | return port->p_lastchange; | |
78346c89 VB |
619 | case lldpctl_k_port_ttl: |
620 | return port->p_ttl; | |
94c98157 AA |
621 | case lldpctl_k_port_id_subtype: |
622 | return port->p_id_subtype; | |
623 | case lldpctl_k_port_hidden: | |
624 | return port->p_hidden_in; | |
625 | #ifdef ENABLE_DOT3 | |
626 | case lldpctl_k_port_dot3_mfs: | |
627 | if (port->p_mfs > 0) | |
628 | return port->p_mfs; | |
629 | break; | |
630 | case lldpctl_k_port_dot3_aggregid: | |
631 | if (port->p_aggregid > 0) | |
632 | return port->p_aggregid; | |
633 | break; | |
634 | case lldpctl_k_port_dot3_autoneg_support: | |
635 | return port->p_macphy.autoneg_support; | |
636 | case lldpctl_k_port_dot3_autoneg_enabled: | |
637 | return port->p_macphy.autoneg_enabled; | |
638 | case lldpctl_k_port_dot3_autoneg_advertised: | |
639 | return port->p_macphy.autoneg_advertised; | |
640 | case lldpctl_k_port_dot3_mautype: | |
641 | return port->p_macphy.mau_type; | |
642 | #endif | |
643 | #ifdef ENABLE_DOT1 | |
644 | case lldpctl_k_port_vlan_pvid: | |
645 | return port->p_pvid; | |
94c98157 AA |
646 | #endif |
647 | default: | |
e55e7492 VB |
648 | /* Compatibility: query the associated chassis too */ |
649 | return lldpctl_atom_get_int(p->chassis, key); | |
94c98157 AA |
650 | } |
651 | return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); | |
652 | } | |
653 | ||
654 | static const uint8_t* | |
655 | _lldpctl_atom_get_buf_port(lldpctl_atom_t *atom, lldpctl_key_t key, size_t *n) | |
656 | { | |
657 | struct _lldpctl_atom_port_t *p = | |
658 | (struct _lldpctl_atom_port_t *)atom; | |
659 | struct lldpd_port *port = p->port; | |
94c98157 AA |
660 | |
661 | switch (key) { | |
662 | case lldpctl_k_port_id: | |
663 | *n = port->p_id_len; | |
664 | return (uint8_t*)port->p_id; | |
94c98157 | 665 | default: |
e55e7492 VB |
666 | /* Compatibility: query the associated chassis too */ |
667 | return lldpctl_atom_get_buffer(p->chassis, key, n); | |
94c98157 AA |
668 | } |
669 | } | |
670 | ||
671 | static struct atom_builder ports_list = | |
672 | { atom_ports_list, sizeof(struct _lldpctl_atom_any_list_t), | |
673 | .init = _lldpctl_atom_new_any_list, | |
674 | .free = _lldpctl_atom_free_any_list, | |
675 | .iter = _lldpctl_atom_iter_ports_list, | |
676 | .next = _lldpctl_atom_next_ports_list, | |
677 | .value = _lldpctl_atom_value_ports_list }; | |
678 | ||
679 | static struct atom_builder port = | |
680 | { atom_port, sizeof(struct _lldpctl_atom_port_t), | |
681 | .init = _lldpctl_atom_new_port, | |
682 | .free = _lldpctl_atom_free_port, | |
683 | .get = _lldpctl_atom_get_atom_port, | |
684 | .set = _lldpctl_atom_set_atom_port, | |
685 | .get_str = _lldpctl_atom_get_str_port, | |
686 | .set_str = _lldpctl_atom_set_str_port, | |
687 | .get_int = _lldpctl_atom_get_int_port, | |
e7331ce9 | 688 | .set_int = _lldpctl_atom_set_int_port, |
94c98157 AA |
689 | .get_buffer = _lldpctl_atom_get_buf_port }; |
690 | ||
691 | ATOM_BUILDER_REGISTER(ports_list, 4); | |
692 | ATOM_BUILDER_REGISTER(port, 5); | |
693 |