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 
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25 
26 /** @file
27  *
28  * Link Layer Discovery Protocol
29  *
30  */
31 
32 #include <stdlib.h>
33 #include <errno.h>
34 #include <byteswap.h>
35 #include <ipxe/iobuf.h>
36 #include <ipxe/netdevice.h>
37 #include <ipxe/if_ether.h>
38 #include <ipxe/settings.h>
39 #include <ipxe/lldp.h>
40 
41 /** An LLDP settings block */
42 struct lldp_settings {
43  /** Settings interface */
45  /** Name */
46  const char *name;
47  /** LLDP data */
48  void *data;
49  /** Length of LLDP data */
50  size_t len;
51 };
52 
53 /* Forward declaration */
54 struct net_driver lldp_driver __net_driver;
55 
56 /** LLDP settings scope */
57 static const struct settings_scope lldp_settings_scope;
58 
59 /**
60  * Check applicability of LLDP setting
61  *
62  * @v settings Settings block
63  * @v setting Setting to fetch
64  * @ret applies Setting applies within this settings block
65  */
66 static int lldp_applies ( struct settings *settings __unused,
67  const struct setting *setting ) {
68 
69  return ( setting->scope == &lldp_settings_scope );
70 }
71 
72 /**
73  * Fetch value of LLDP setting
74  *
75  * @v settings Settings block
76  * @v setting Setting to fetch
77  * @v buf Buffer to fill with setting data
78  * @v len Length of buffer
79  * @ret len Length of setting data, or negative error
80  */
81 static int lldp_fetch ( struct settings *settings,
82  struct setting *setting,
83  void *buf, size_t len ) {
84  struct lldp_settings *lldpset =
86  union {
87  uint32_t high;
88  uint8_t raw[4];
89  } tag_prefix;
90  uint32_t tag_low;
91  uint8_t tag_type;
92  uint8_t tag_index;
93  uint8_t tag_offset;
94  uint8_t tag_length;
95  const void *match;
96  const void *data;
97  size_t match_len;
98  size_t remaining;
99  const struct lldp_tlv *tlv;
100  unsigned int tlv_type_len;
101  unsigned int tlv_type;
102  unsigned int tlv_len;
103 
104  /* Parse setting tag */
105  tag_prefix.high = htonl ( setting->tag >> 32 );
106  tag_low = setting->tag;
107  tag_type = ( tag_low >> 24 );
108  tag_index = ( tag_low >> 16 );
109  tag_offset = ( tag_low >> 8 );
110  tag_length = ( tag_low >> 0 );
111 
112  /* Identify match prefix */
113  match_len = tag_offset;
114  if ( match_len > sizeof ( tag_prefix ) )
115  match_len = sizeof ( tag_prefix );
116  if ( ! tag_prefix.high )
117  match_len = 0;
118  match = &tag_prefix.raw[ sizeof ( tag_prefix ) - match_len ];
119 
120  /* Locate matching TLV */
121  for ( data = lldpset->data, remaining = lldpset->len ; remaining ;
122  data += tlv_len, remaining -= tlv_len ) {
123 
124  /* Parse TLV header */
125  if ( remaining < sizeof ( *tlv ) ) {
126  DBGC ( lldpset, "LLDP %s underlength TLV header\n",
127  lldpset->name );
128  DBGC_HDA ( lldpset, 0, data, remaining );
129  break;
130  }
131  tlv = data;
132  data += sizeof ( *tlv );
133  remaining -= sizeof ( *tlv );
134  tlv_type_len = ntohs ( tlv->type_len );
135  tlv_type = LLDP_TLV_TYPE ( tlv_type_len );
136  if ( tlv_type == LLDP_TYPE_END )
137  break;
138  tlv_len = LLDP_TLV_LEN ( tlv_type_len );
139  if ( remaining < tlv_len ) {
140  DBGC ( lldpset, "LLDP %s underlength TLV value\n",
141  lldpset->name );
142  DBGC_HDA ( lldpset, 0, data, remaining );
143  break;
144  }
145  DBGC2 ( lldpset, "LLDP %s found type %d:\n",
146  lldpset->name, tlv_type );
147  DBGC2_HDA ( lldpset, 0, data, tlv_len );
148 
149  /* Check for matching tag type */
150  if ( tlv_type != tag_type )
151  continue;
152 
153  /* Check for matching prefix */
154  if ( tlv_len < match_len )
155  continue;
156  if ( memcmp ( data, match, match_len ) != 0 )
157  continue;
158 
159  /* Check for matching index */
160  if ( tag_index-- )
161  continue;
162 
163  /* Skip offset */
164  if ( tlv_len < tag_offset )
165  return 0;
166  data += tag_offset;
167  tlv_len -= tag_offset;
168 
169  /* Set type if not already specified */
170  if ( ! setting->type ) {
171  setting->type = ( tag_length ? &setting_type_hex :
172  &setting_type_string );
173  }
174 
175  /* Extract value */
176  if ( tag_length && ( tlv_len > tag_length ) )
177  tlv_len = tag_length;
178  if ( len > tlv_len )
179  len = tlv_len;
180  memcpy ( buf, data, len );
181  return tlv_len;
182  }
183 
184  return -ENOENT;
185 }
186 
187 /** LLDP settings operations */
190  .fetch = lldp_fetch,
191 };
192 
193 /**
194  * Process LLDP packet
195  *
196  * @v iobuf I/O buffer
197  * @v netdev Network device
198  * @v ll_dest Link-layer destination address
199  * @v ll_source Link-layer source address
200  * @v flags Packet flags
201  * @ret rc Return status code
202  */
203 static int lldp_rx ( struct io_buffer *iobuf, struct net_device *netdev,
204  const void *ll_dest, const void *ll_source,
205  unsigned int flags __unused ) {
206  struct lldp_settings *lldpset;
207  size_t len;
208  void *data;
209  int rc;
210 
211  /* Find matching LLDP settings block */
212  lldpset = netdev_priv ( netdev, &lldp_driver );
213 
214  /* Create trimmed copy of received LLDP data */
215  len = iob_len ( iobuf );
216  data = malloc ( len );
217  if ( ! data ) {
218  rc = -ENOMEM;
219  goto err_alloc;
220  }
221  memcpy ( data, iobuf->data, len );
222 
223  /* Free any existing LLDP data */
224  free ( lldpset->data );
225 
226  /* Transfer data to LLDP settings block */
227  lldpset->data = data;
228  lldpset->len = len;
229  data = NULL;
230  DBGC2 ( lldpset, "LLDP %s src %s ",
231  lldpset->name, netdev->ll_protocol->ntoa ( ll_source ) );
232  DBGC2 ( lldpset, "dst %s\n", netdev->ll_protocol->ntoa ( ll_dest ) );
233  DBGC2_HDA ( lldpset, 0, lldpset->data, lldpset->len );
234 
235  /* Success */
236  rc = 0;
237 
238  free ( data );
239  err_alloc:
240  free_iob ( iobuf );
241  return rc;
242 }
243 
244 /** LLDP protocol */
245 struct net_protocol lldp_protocol __net_protocol = {
246  .name = "LLDP",
247  .net_proto = htons ( ETH_P_LLDP ),
248  .rx = lldp_rx,
249 };
250 
251 /**
252  * Create LLDP settings block
253  *
254  * @v netdev Network device
255  * @v priv Private data
256  * @ret rc Return status code
257  */
258 static int lldp_probe ( struct net_device *netdev, void *priv ) {
259  struct lldp_settings *lldpset = priv;
260  int rc;
261 
262  /* Initialise LLDP settings block */
265  lldpset->name = netdev->name;
266 
267  /* Register settings */
268  if ( ( rc = register_settings ( &lldpset->settings,
270  LLDP_SETTINGS_NAME ) ) != 0 ) {
271  DBGC ( lldpset, "LLDP %s could not register settings: %s\n",
272  lldpset->name, strerror ( rc ) );
273  goto err_register;
274  }
275  DBGC ( lldpset, "LLDP %s registered\n", lldpset->name );
276 
277  return 0;
278 
279  unregister_settings ( &lldpset->settings );
280  err_register:
281  assert ( lldpset->data == NULL );
282  return rc;
283 }
284 
285 /**
286  * Remove LLDP settings block
287  *
288  * @v netdev Network device
289  * @v priv Private data
290  */
291 static void lldp_remove ( struct net_device *netdev __unused, void *priv ) {
292  struct lldp_settings *lldpset = priv;
293 
294  /* Unregister settings */
295  unregister_settings ( &lldpset->settings );
296  DBGC ( lldpset, "LLDP %s unregistered\n", lldpset->name );
297 
298  /* Free any LLDP data */
299  free ( lldpset->data );
300  lldpset->data = NULL;
301 }
302 
303 /** LLDP driver */
304 struct net_driver lldp_driver __net_driver = {
305  .name = "LLDP",
306  .priv_len = sizeof ( struct lldp_settings ),
307  .probe = lldp_probe,
308  .remove = lldp_remove,
309 };
struct eth_slow_tlv_header tlv
TLV header.
Definition: eth_slow.h:12
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
const char * name
Protocol name.
Definition: netdevice.h:66
size_t len
Length of LLDP data.
Definition: lldp.c:50
void * data
LLDP data.
Definition: lldp.c:48
void unregister_settings(struct settings *settings)
Unregister settings block.
Definition: settings.c:514
Error codes.
I/O buffers.
void free_iob(struct io_buffer *iobuf)
Free I/O buffer.
Definition: iobuf.c:146
static int lldp_probe(struct net_device *netdev, void *priv)
Create LLDP settings block.
Definition: lldp.c:258
#define DBGC(...)
Definition: compiler.h:505
#define ETH_P_LLDP
Definition: if_ether.h:26
#define ENOENT
No such file or directory.
Definition: errno.h:514
#define ntohs(value)
Definition: byteswap.h:136
#define htonl(value)
Definition: byteswap.h:133
A network upper-layer driver.
Definition: netdevice.h:473
static struct settings * netdev_settings(struct net_device *netdev)
Get per-netdevice configuration settings block.
Definition: netdevice.h:583
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:500
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
uint64_t tag
Setting tag, if applicable.
Definition: settings.h:43
#define LLDP_TLV_LEN(type_len)
Extract LLDP TLV length.
Definition: lldp.h:36
#define ENOMEM
Not enough space.
Definition: errno.h:534
void * memcpy(void *dest, const void *src, size_t len) __nonnull
const char * name
Name.
Definition: netdevice.h:475
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:203
static void lldp_remove(struct net_device *netdev __unused, void *priv)
Remove LLDP settings block.
Definition: lldp.c:291
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
#define container_of(ptr, type, field)
Get containing structure.
Definition: stddef.h:35
void * netdev_priv(struct net_device *netdev, struct net_driver *driver)
Get network device driver private data.
Definition: netdevice.c:152
#define DBGC_HDA(...)
Definition: compiler.h:506
#define LLDP_TYPE_END
End of LLDP data unit.
Definition: lldp.h:39
static struct net_device * netdev
Definition: gdbudp.c:52
const char * name
Name.
Definition: lldp.c:46
const struct setting_type * type
Setting type.
Definition: settings.h:36
static int lldp_fetch(struct settings *settings, struct setting *setting, void *buf, size_t len)
Fetch value of LLDP setting.
Definition: lldp.c:81
Link Layer Discovery Protocol.
uint32_t high
High 32 bits of address.
Definition: myson.h:20
#define DBGC2_HDA(...)
Definition: compiler.h:523
Configuration settings.
struct settings settings
Settings interface.
Definition: lldp.c:44
char * strerror(int errno)
Retrieve string representation of error number.
Definition: strerror.c:78
struct refcnt refcnt
Reference counter.
Definition: netdevice.h:354
static void(* free)(struct refcnt *refcnt))
Definition: refcnt.h:54
static size_t iob_len(struct io_buffer *iobuf)
Calculate length of data in an I/O buffer.
Definition: iobuf.h:155
A network device.
Definition: netdevice.h:352
Settings block operations.
Definition: settings.h:85
A settings block.
Definition: settings.h:132
unsigned char uint8_t
Definition: stdint.h:10
A setting scope.
Definition: settings.h:176
unsigned int uint32_t
Definition: stdint.h:12
void * malloc(size_t size)
Allocate memory.
Definition: malloc.c:583
Definition: bnxt_hsi.h:52
An LLDP settings block.
Definition: lldp.c:42
A setting.
Definition: settings.h:23
static int lldp_applies(struct settings *settings __unused, const struct setting *setting)
Check applicability of LLDP setting.
Definition: lldp.c:66
A network-layer protocol.
Definition: netdevice.h:64
Network device management.
#define __unused
Declare a variable or data structure as unused.
Definition: compiler.h:573
char name[NETDEV_NAME_LEN]
Name of this network device.
Definition: netdevice.h:362
uint32_t len
Length.
Definition: ena.h:14
#define DBGC2(...)
Definition: compiler.h:522
static struct tlan_private * priv
Definition: tlan.c:224
void * data
Start of data.
Definition: iobuf.h:48
#define LLDP_TLV_TYPE(type_len)
Extract LLDP TLV type.
Definition: lldp.h:28
uint8_t data[48]
Additional event data.
Definition: ena.h:22
const char *(* ntoa)(const void *ll_addr)
Transcribe link-layer address.
Definition: netdevice.h:163
__be32 raw[7]
Definition: CIB_PRM.h:28
int(* applies)(struct settings *settings, const struct setting *setting)
Check applicability of setting.
Definition: settings.h:98
int register_settings(struct settings *settings, struct settings *parent, const char *name)
Register settings block.
Definition: settings.c:475
#define LLDP_SETTINGS_NAME
LLDP settings block name.
Definition: lldp.h:42
const struct settings_scope * scope
Setting scope (or NULL)
Definition: settings.h:49
An LLDP TLV header.
Definition: lldp.h:15
int memcmp(const void *first, const void *second, size_t len)
Compare memory regions.
Definition: string.c:114
static const struct settings_scope lldp_settings_scope
LLDP settings scope.
Definition: lldp.c:57
#define NULL
NULL pointer (VOID *)
Definition: Base.h:321
#define htons(value)
Definition: byteswap.h:135
struct net_protocol lldp_protocol __net_protocol
LLDP protocol.
Definition: lldp.c:245
struct ll_protocol * ll_protocol
Link-layer protocol.
Definition: netdevice.h:372
static struct settings_operations lldp_settings_operations
LLDP settings operations.
Definition: lldp.c:188
struct net_driver lldp_driver __net_driver
LLDP driver.
Definition: lldp.c:54
A persistent I/O buffer.
Definition: iobuf.h:33
uint8_t flags
Flags.
Definition: ena.h:18