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"
24 #include "../log.h"
25 #include "atom.h"
26 #include "helpers.h"
27
28 static lldpctl_map_t chassis_id_subtype_map[] = {
29 { LLDP_CHASSISID_SUBTYPE_IFNAME, "ifname"},
30 { LLDP_CHASSISID_SUBTYPE_IFALIAS, "ifalias" },
31 { LLDP_CHASSISID_SUBTYPE_LOCAL, "local" },
32 { LLDP_CHASSISID_SUBTYPE_LLADDR, "mac" },
33 { LLDP_CHASSISID_SUBTYPE_ADDR, "ip" },
34 { LLDP_CHASSISID_SUBTYPE_PORT, "unhandled" },
35 { LLDP_CHASSISID_SUBTYPE_CHASSIS, "unhandled" },
36 { 0, NULL},
37 };
38
39 #ifdef ENABLE_LLDPMED
40
41 static lldpctl_map_t chassis_med_type_map[] = {
42 { LLDP_MED_CLASS_I, "Generic Endpoint (Class I)" },
43 { LLDP_MED_CLASS_II, "Media Endpoint (Class II)" },
44 { LLDP_MED_CLASS_III, "Communication Device Endpoint (Class III)" },
45 { LLDP_MED_NETWORK_DEVICE, "Network Connectivity Device" },
46 { 0, NULL },
47 };
48
49 #endif
50
51 static int
_lldpctl_atom_new_chassis(lldpctl_atom_t * atom,va_list ap)52 _lldpctl_atom_new_chassis(lldpctl_atom_t *atom, va_list ap)
53 {
54 struct _lldpctl_atom_chassis_t *p =
55 (struct _lldpctl_atom_chassis_t *)atom;
56 p->chassis = va_arg(ap, struct lldpd_chassis*);
57 p->parent = va_arg(ap, struct _lldpctl_atom_port_t*);
58 p->embedded = va_arg(ap, int);
59 if (p->parent && !p->embedded)
60 lldpctl_atom_inc_ref((lldpctl_atom_t*)p->parent);
61 return 1;
62 }
63
64 static void
_lldpctl_atom_free_chassis(lldpctl_atom_t * atom)65 _lldpctl_atom_free_chassis(lldpctl_atom_t *atom)
66 {
67 struct _lldpctl_atom_chassis_t *p =
68 (struct _lldpctl_atom_chassis_t *)atom;
69 /* When we have a parent, the chassis structure is in fact part of the
70 * parent, just decrement the reference count of the parent. Otherwise,
71 * we need to free the whole chassis. When embedded, we don't alter the
72 * reference count of the parent. Therefore, it's important to also not
73 * increase the reference count of this atom. See
74 * `_lldpctl_atom_get_atom_chassis' for how to handle that. */
75 if (p->parent) {
76 if (!p->embedded)
77 lldpctl_atom_dec_ref((lldpctl_atom_t*)p->parent);
78 } else
79 lldpd_chassis_cleanup(p->chassis, 1);
80 }
81
82 static lldpctl_atom_t*
_lldpctl_atom_get_atom_chassis(lldpctl_atom_t * atom,lldpctl_key_t key)83 _lldpctl_atom_get_atom_chassis(lldpctl_atom_t *atom, lldpctl_key_t key)
84 {
85 struct _lldpctl_atom_chassis_t *p =
86 (struct _lldpctl_atom_chassis_t *)atom;
87 struct lldpd_chassis *chassis = p->chassis;
88
89 switch (key) {
90 case lldpctl_k_chassis_mgmt:
91 return _lldpctl_new_atom(atom->conn, atom_mgmts_list,
92 (p->parent && p->embedded)?
93 (lldpctl_atom_t *)p->parent:
94 (lldpctl_atom_t *)p,
95 chassis);
96 default:
97 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
98 return NULL;
99 }
100 }
101
102 static const char*
_lldpctl_atom_get_str_chassis(lldpctl_atom_t * atom,lldpctl_key_t key)103 _lldpctl_atom_get_str_chassis(lldpctl_atom_t *atom, lldpctl_key_t key)
104 {
105 struct _lldpctl_atom_chassis_t *p =
106 (struct _lldpctl_atom_chassis_t *)atom;
107 struct lldpd_chassis *chassis = p->chassis;
108 char *ipaddress = NULL; size_t len;
109
110 /* Local and remote port */
111 switch (key) {
112
113 case lldpctl_k_chassis_id_subtype:
114 return map_lookup(chassis_id_subtype_map, chassis->c_id_subtype);
115 case lldpctl_k_chassis_id:
116 switch (chassis->c_id_subtype) {
117 case LLDP_CHASSISID_SUBTYPE_IFNAME:
118 case LLDP_CHASSISID_SUBTYPE_IFALIAS:
119 case LLDP_CHASSISID_SUBTYPE_LOCAL:
120 return chassis->c_id;
121 case LLDP_CHASSISID_SUBTYPE_LLADDR:
122 return _lldpctl_dump_in_atom(atom,
123 (uint8_t*)chassis->c_id, chassis->c_id_len,
124 ':', 0);
125 case LLDP_CHASSISID_SUBTYPE_ADDR:
126 switch (chassis->c_id[0]) {
127 case LLDP_MGMT_ADDR_IP4: len = INET_ADDRSTRLEN + 1; break;
128 case LLDP_MGMT_ADDR_IP6: len = INET6_ADDRSTRLEN + 1; break;
129 default: len = 0;
130 }
131 if (len > 0) {
132 ipaddress = _lldpctl_alloc_in_atom(atom, len);
133 if (!ipaddress) return NULL;
134 if (inet_ntop((chassis->c_id[0] == LLDP_MGMT_ADDR_IP4)?
135 AF_INET:AF_INET6,
136 &chassis->c_id[1], ipaddress, len) == NULL)
137 break;
138 return ipaddress;
139 }
140 break;
141 }
142 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
143 return NULL;
144 case lldpctl_k_chassis_name: return chassis->c_name;
145 case lldpctl_k_chassis_descr: return chassis->c_descr;
146
147 #ifdef ENABLE_LLDPMED
148 case lldpctl_k_chassis_med_type:
149 return map_lookup(chassis_med_type_map, chassis->c_med_type);
150 case lldpctl_k_chassis_med_inventory_hw:
151 return chassis->c_med_hw;
152 case lldpctl_k_chassis_med_inventory_sw:
153 return chassis->c_med_sw;
154 case lldpctl_k_chassis_med_inventory_fw:
155 return chassis->c_med_fw;
156 case lldpctl_k_chassis_med_inventory_sn:
157 return chassis->c_med_sn;
158 case lldpctl_k_chassis_med_inventory_manuf:
159 return chassis->c_med_manuf;
160 case lldpctl_k_chassis_med_inventory_model:
161 return chassis->c_med_model;
162 case lldpctl_k_chassis_med_inventory_asset:
163 return chassis->c_med_asset;
164 #endif
165
166 default:
167 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
168 return NULL;
169 }
170 }
171
172 static long int
_lldpctl_atom_get_int_chassis(lldpctl_atom_t * atom,lldpctl_key_t key)173 _lldpctl_atom_get_int_chassis(lldpctl_atom_t *atom, lldpctl_key_t key)
174 {
175 struct _lldpctl_atom_chassis_t *p =
176 (struct _lldpctl_atom_chassis_t *)atom;
177 struct lldpd_chassis *chassis = p->chassis;
178
179 /* Local and remote port */
180 switch (key) {
181 case lldpctl_k_chassis_index:
182 return chassis->c_index;
183 case lldpctl_k_chassis_id_subtype:
184 return chassis->c_id_subtype;
185 case lldpctl_k_chassis_cap_available:
186 return chassis->c_cap_available;
187 case lldpctl_k_chassis_cap_enabled:
188 return chassis->c_cap_enabled;
189 #ifdef ENABLE_LLDPMED
190 case lldpctl_k_chassis_med_type:
191 return chassis->c_med_type;
192 case lldpctl_k_chassis_med_cap:
193 return chassis->c_med_cap_available;
194 #endif
195 default:
196 return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
197 }
198 return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
199 }
200
201 static const uint8_t*
_lldpctl_atom_get_buf_chassis(lldpctl_atom_t * atom,lldpctl_key_t key,size_t * n)202 _lldpctl_atom_get_buf_chassis(lldpctl_atom_t *atom, lldpctl_key_t key, size_t *n)
203 {
204 struct _lldpctl_atom_chassis_t *p =
205 (struct _lldpctl_atom_chassis_t *)atom;
206 struct lldpd_chassis *chassis = p->chassis;
207
208 switch (key) {
209 case lldpctl_k_chassis_id:
210 *n = chassis->c_id_len;
211 return (uint8_t*)chassis->c_id;
212 default:
213 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
214 return NULL;
215 }
216 }
217
218 static struct atom_builder chassis =
219 { atom_chassis, sizeof(struct _lldpctl_atom_chassis_t),
220 .init = _lldpctl_atom_new_chassis,
221 .free = _lldpctl_atom_free_chassis,
222 .get = _lldpctl_atom_get_atom_chassis,
223 .get_str = _lldpctl_atom_get_str_chassis,
224 .get_int = _lldpctl_atom_get_int_chassis,
225 .get_buffer = _lldpctl_atom_get_buf_chassis };
226
227 ATOM_BUILDER_REGISTER(chassis, 3);
228