iPXE
lldp.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2023 Michael Brown <mbrown@fensystems.co.uk>.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301, USA.
18 *
19 * You can also choose to distribute this program under the terms of
20 * the Unmodified Binary Distribution Licence (as given in the file
21 * COPYING.UBDL), provided that you have satisfied its requirements.
22 */
23
24FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25FILE_SECBOOT ( PERMITTED );
26
27/** @file
28 *
29 * Link Layer Discovery Protocol
30 *
31 */
32
33#include <stdlib.h>
34#include <string.h>
35#include <errno.h>
36#include <byteswap.h>
37#include <ipxe/iobuf.h>
38#include <ipxe/netdevice.h>
39#include <ipxe/if_ether.h>
40#include <ipxe/settings.h>
41#include <ipxe/lldp.h>
42
43/** An LLDP settings block */
45 /** Settings interface */
47 /** Name */
48 const char *name;
49 /** LLDP data */
50 void *data;
51 /** Length of LLDP data */
52 size_t len;
53};
54
55/* Forward declaration */
56struct net_driver lldp_driver __net_driver;
57
58/** LLDP settings scope */
60
61/**
62 * Check applicability of LLDP setting
63 *
64 * @v settings Settings block
65 * @v setting Setting to fetch
66 * @ret applies Setting applies within this settings block
67 */
69 const struct setting *setting ) {
70
71 return ( setting->scope == &lldp_settings_scope );
72}
73
74/**
75 * Fetch value of LLDP setting
76 *
77 * @v settings Settings block
78 * @v setting Setting to fetch
79 * @v buf Buffer to fill with setting data
80 * @v len Length of buffer
81 * @ret len Length of setting data, or negative error
82 */
83static int lldp_fetch ( struct settings *settings,
84 struct setting *setting,
85 void *buf, size_t len ) {
86 struct lldp_settings *lldpset =
88 union {
90 uint8_t raw[4];
91 } tag_prefix;
92 uint32_t tag_low;
93 uint8_t tag_type;
94 uint8_t tag_index;
95 uint8_t tag_offset;
96 uint8_t tag_length;
97 const void *match;
98 const void *data;
99 size_t match_len;
100 size_t remaining;
101 const struct lldp_tlv *tlv;
102 unsigned int tlv_type_len;
103 unsigned int tlv_type;
104 unsigned int tlv_len;
105
106 /* Parse setting tag */
107 tag_prefix.high = htonl ( setting->tag >> 32 );
108 tag_low = setting->tag;
109 tag_type = ( tag_low >> 24 );
110 tag_index = ( tag_low >> 16 );
111 tag_offset = ( tag_low >> 8 );
112 tag_length = ( tag_low >> 0 );
113
114 /* Identify match prefix */
115 match_len = tag_offset;
116 if ( match_len > sizeof ( tag_prefix ) )
117 match_len = sizeof ( tag_prefix );
118 if ( ! tag_prefix.high )
119 match_len = 0;
120 match = &tag_prefix.raw[ sizeof ( tag_prefix ) - match_len ];
121
122 /* Locate matching TLV */
123 for ( data = lldpset->data, remaining = lldpset->len ; remaining ;
124 data += tlv_len, remaining -= tlv_len ) {
125
126 /* Parse TLV header */
127 if ( remaining < sizeof ( *tlv ) ) {
128 DBGC ( lldpset, "LLDP %s underlength TLV header\n",
129 lldpset->name );
130 DBGC_HDA ( lldpset, 0, data, remaining );
131 break;
132 }
133 tlv = data;
134 data += sizeof ( *tlv );
135 remaining -= sizeof ( *tlv );
136 tlv_type_len = ntohs ( tlv->type_len );
137 tlv_type = LLDP_TLV_TYPE ( tlv_type_len );
138 if ( tlv_type == LLDP_TYPE_END )
139 break;
140 tlv_len = LLDP_TLV_LEN ( tlv_type_len );
141 if ( remaining < tlv_len ) {
142 DBGC ( lldpset, "LLDP %s underlength TLV value\n",
143 lldpset->name );
144 DBGC_HDA ( lldpset, 0, data, remaining );
145 break;
146 }
147 DBGC2 ( lldpset, "LLDP %s found type %d:\n",
148 lldpset->name, tlv_type );
149 DBGC2_HDA ( lldpset, 0, data, tlv_len );
150
151 /* Check for matching tag type */
152 if ( tlv_type != tag_type )
153 continue;
154
155 /* Check for matching prefix */
156 if ( tlv_len < match_len )
157 continue;
158 if ( memcmp ( data, match, match_len ) != 0 )
159 continue;
160
161 /* Check for matching index */
162 if ( tag_index-- )
163 continue;
164
165 /* Skip offset */
166 if ( tlv_len < tag_offset )
167 return 0;
168 data += tag_offset;
169 tlv_len -= tag_offset;
170
171 /* Set type if not already specified */
172 if ( ! setting->type ) {
173 setting->type = ( tag_length ? &setting_type_hex :
174 &setting_type_string );
175 }
176
177 /* Extract value */
178 if ( tag_length && ( tlv_len > tag_length ) )
179 tlv_len = tag_length;
180 if ( len > tlv_len )
181 len = tlv_len;
182 memcpy ( buf, data, len );
183 return tlv_len;
184 }
185
186 return -ENOENT;
187}
188
189/** LLDP settings operations */
191 .applies = lldp_applies,
192 .fetch = lldp_fetch,
193};
194
195/**
196 * Process LLDP packet
197 *
198 * @v iobuf I/O buffer
199 * @v netdev Network device
200 * @v ll_dest Link-layer destination address
201 * @v ll_source Link-layer source address
202 * @v flags Packet flags
203 * @ret rc Return status code
204 */
205static int lldp_rx ( struct io_buffer *iobuf, struct net_device *netdev,
206 const void *ll_dest, const void *ll_source,
207 unsigned int flags __unused ) {
208 struct lldp_settings *lldpset;
209 size_t len;
210 void *data;
211 int rc;
212
213 /* Find matching LLDP settings block */
214 lldpset = netdev_priv ( netdev, &lldp_driver );
215
216 /* Create trimmed copy of received LLDP data */
217 len = iob_len ( iobuf );
218 data = malloc ( len );
219 if ( ! data ) {
220 rc = -ENOMEM;
221 goto err_alloc;
222 }
223 memcpy ( data, iobuf->data, len );
224
225 /* Free any existing LLDP data */
226 free ( lldpset->data );
227
228 /* Transfer data to LLDP settings block */
229 lldpset->data = data;
230 lldpset->len = len;
231 data = NULL;
232 DBGC2 ( lldpset, "LLDP %s src %s ",
233 lldpset->name, netdev->ll_protocol->ntoa ( ll_source ) );
234 DBGC2 ( lldpset, "dst %s\n", netdev->ll_protocol->ntoa ( ll_dest ) );
235 DBGC2_HDA ( lldpset, 0, lldpset->data, lldpset->len );
236
237 /* Success */
238 rc = 0;
239
240 free ( data );
241 err_alloc:
242 free_iob ( iobuf );
243 return rc;
244}
245
246/** LLDP protocol */
247struct net_protocol lldp_protocol __net_protocol = {
248 .name = "LLDP",
249 .net_proto = htons ( ETH_P_LLDP ),
250 .rx = lldp_rx,
251};
252
253/**
254 * Create LLDP settings block
255 *
256 * @v netdev Network device
257 * @v priv Private data
258 * @ret rc Return status code
259 */
260static int lldp_probe ( struct net_device *netdev, void *priv ) {
261 struct lldp_settings *lldpset = priv;
262 int rc;
263
264 /* Initialise LLDP settings block */
266 &netdev->refcnt, &lldp_settings_scope );
267 lldpset->name = netdev->name;
268
269 /* Register settings */
270 if ( ( rc = register_settings ( &lldpset->settings,
272 LLDP_SETTINGS_NAME ) ) != 0 ) {
273 DBGC ( lldpset, "LLDP %s could not register settings: %s\n",
274 lldpset->name, strerror ( rc ) );
275 goto err_register;
276 }
277 DBGC ( lldpset, "LLDP %s registered\n", lldpset->name );
278
279 return 0;
280
281 unregister_settings ( &lldpset->settings );
282 err_register:
283 assert ( lldpset->data == NULL );
284 return rc;
285}
286
287/**
288 * Remove LLDP settings block
289 *
290 * @v netdev Network device
291 * @v priv Private data
292 */
293static void lldp_remove ( struct net_device *netdev __unused, void *priv ) {
294 struct lldp_settings *lldpset = priv;
295
296 /* Unregister settings */
297 unregister_settings ( &lldpset->settings );
298 DBGC ( lldpset, "LLDP %s unregistered\n", lldpset->name );
299
300 /* Free any LLDP data */
301 free ( lldpset->data );
302 lldpset->data = NULL;
303}
304
305/** LLDP driver */
306struct net_driver lldp_driver __net_driver = {
307 .name = "LLDP",
308 .priv_len = sizeof ( struct lldp_settings ),
309 .probe = lldp_probe,
310 .remove = lldp_remove,
311};
#define NULL
NULL pointer (VOID *)
Definition Base.h:322
__be32 raw[7]
Definition CIB_PRM.h:0
struct arbelprm_rc_send_wqe rc
Definition arbel.h:3
unsigned int uint32_t
Definition stdint.h:12
unsigned char uint8_t
Definition stdint.h:10
#define assert(condition)
Assert a condition at run-time.
Definition assert.h:50
ring len
Length.
Definition dwmac.h:226
uint8_t data[48]
Additional event data.
Definition ena.h:11
uint8_t flags
Flags.
Definition ena.h:7
Error codes.
static struct net_device * netdev
Definition gdbudp.c:53
#define __unused
Declare a variable or data structure as unused.
Definition compiler.h:573
#define DBGC2(...)
Definition compiler.h:522
#define DBGC2_HDA(...)
Definition compiler.h:523
#define DBGC(...)
Definition compiler.h:505
#define DBGC_HDA(...)
Definition compiler.h:506
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:896
#define ENOENT
No such file or directory.
Definition errno.h:515
#define ENOMEM
Not enough space.
Definition errno.h:535
#define FILE_SECBOOT(_status)
Declare a file's UEFI Secure Boot permission status.
Definition compiler.h:926
#define ETH_P_LLDP
Definition if_ether.h:27
#define htonl(value)
Definition byteswap.h:134
#define htons(value)
Definition byteswap.h:136
#define ntohs(value)
Definition byteswap.h:137
Configuration settings.
static void settings_init(struct settings *settings, struct settings_operations *op, struct refcnt *refcnt, const struct settings_scope *default_scope)
Initialise a settings block.
Definition settings.h:503
String functions.
void * memcpy(void *dest, const void *src, size_t len) __nonnull
void free_iob(struct io_buffer *iobuf)
Free I/O buffer.
Definition iobuf.c:153
I/O buffers.
static size_t iob_len(struct io_buffer *iobuf)
Calculate length of data in an I/O buffer.
Definition iobuf.h:160
static void lldp_remove(struct net_device *netdev __unused, void *priv)
Remove LLDP settings block.
Definition lldp.c:293
static int lldp_probe(struct net_device *netdev, void *priv)
Create LLDP settings block.
Definition lldp.c:260
static const struct settings_scope lldp_settings_scope
LLDP settings scope.
Definition lldp.c:59
static struct settings_operations lldp_settings_operations
LLDP settings operations.
Definition lldp.c:190
static int lldp_rx(struct io_buffer *iobuf, struct net_device *netdev, const void *ll_dest, const void *ll_source, unsigned int flags __unused)
Process LLDP packet.
Definition lldp.c:205
static int lldp_fetch(struct settings *settings, struct setting *setting, void *buf, size_t len)
Fetch value of LLDP setting.
Definition lldp.c:83
static int lldp_applies(struct settings *settings __unused, const struct setting *setting)
Check applicability of LLDP setting.
Definition lldp.c:68
Link Layer Discovery Protocol.
#define LLDP_SETTINGS_NAME
LLDP settings block name.
Definition lldp.h:43
#define LLDP_TLV_LEN(type_len)
Extract LLDP TLV length.
Definition lldp.h:37
#define LLDP_TYPE_END
End of LLDP data unit.
Definition lldp.h:40
#define LLDP_TLV_TYPE(type_len)
Extract LLDP TLV type.
Definition lldp.h:29
void * malloc(size_t size)
Allocate memory.
Definition malloc.c:621
uint32_t high
High 32 bits of address.
Definition myson.h:1
void * netdev_priv(struct net_device *netdev, struct net_driver *driver)
Get network device driver private data.
Definition netdevice.c:153
Network device management.
#define __net_driver
Declare a network driver.
Definition netdevice.h:507
#define __net_protocol
Declare a network-layer protocol.
Definition netdevice.h:474
static struct settings * netdev_settings(struct net_device *netdev)
Get per-netdevice configuration settings block.
Definition netdevice.h:587
static void(* free)(struct refcnt *refcnt))
Definition refcnt.h:55
int register_settings(struct settings *settings, struct settings *parent, const char *name)
Register settings block.
Definition settings.c:476
void unregister_settings(struct settings *settings)
Unregister settings block.
Definition settings.c:515
#define container_of(ptr, type, field)
Get containing structure.
Definition stddef.h:36
char * strerror(int errno)
Retrieve string representation of error number.
Definition strerror.c:79
int memcmp(const void *first, const void *second, size_t len)
Compare memory regions.
Definition string.c:115
A persistent I/O buffer.
Definition iobuf.h:38
void * data
Start of data.
Definition iobuf.h:53
An LLDP settings block.
Definition lldp.c:44
void * data
LLDP data.
Definition lldp.c:50
const char * name
Name.
Definition lldp.c:48
struct settings settings
Settings interface.
Definition lldp.c:46
size_t len
Length of LLDP data.
Definition lldp.c:52
An LLDP TLV header.
Definition lldp.h:16
A network device.
Definition netdevice.h:353
A network upper-layer driver.
Definition netdevice.h:477
A network-layer protocol.
Definition netdevice.h:65
A setting.
Definition settings.h:24
const struct settings_scope * scope
Setting scope (or NULL)
Definition settings.h:50
const struct setting_type * type
Setting type.
Definition settings.h:37
uint64_t tag
Setting tag, if applicable.
Definition settings.h:44
Settings block operations.
Definition settings.h:86
A setting scope.
Definition settings.h:177
A settings block.
Definition settings.h:133
Definition bnxt_hsi.h:52
static struct tlan_private * priv
Definition tlan.c:225