chiark / gitweb /
e9d5d7bb60e0c72db6fd96cfe79dd39dc46c73eb
[elogind.git] / src / libsystemd-network / test-lldp.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright (C) 2014 Tom Gundersen
7   Copyright (C) 2014 Susant Sahani
8
9   systemd is free software; you can redistribute it and/or modify it
10   under the terms of the GNU Lesser General Public License as published by
11   the Free Software Foundation; either version 2.1 of the License, or
12   (at your option) any later version.
13
14   systemd is distributed in the hope that it will be useful, but
15   WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17   Lesser General Public License for more details.
18
19   You should have received a copy of the GNU Lesser General Public License
20   along with systemd; If not, see <http://www.gnu.org/licenses/>.
21 ***/
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sys/socket.h>
27 #include <linux/if.h>
28 #include <linux/if_ether.h>
29 #include <net/ethernet.h>
30 #include <sys/types.h>
31 #include <arpa/inet.h>
32
33 #include "macro.h"
34 #include "lldp.h"
35 #include "lldp-tlv.h"
36
37 #define TEST_LLDP_PORT "em1"
38 #define TEST_LLDP_TYPE_SYSTEM_NAME "systemd-lldp"
39 #define TEST_LLDP_TYPE_SYSTEM_DESC "systemd-lldp-desc"
40
41 static struct ether_addr mac_addr = {
42         .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}
43 };
44
45 static int lldp_build_tlv_packet(tlv_packet **ret) {
46         _cleanup_tlv_packet_free_ tlv_packet *m = NULL;
47         const uint8_t lldp_dst[] = LLDP_MULTICAST_ADDR;
48         struct ether_header ether;
49
50         /* Append ethernet header */
51         memset(&ether, 0, sizeof(ether));
52         memcpy(&ether.ether_dhost, lldp_dst, ETHER_ADDR_LEN);
53         memcpy(&ether.ether_shost, &mac_addr, ETHER_ADDR_LEN);
54         ether.ether_type = htons(ETHERTYPE_LLDP);
55
56         assert_se(tlv_packet_new(&m) >= 0);
57
58         assert_se(tlv_packet_append_bytes(m, &ether, sizeof(struct ether_header)) >= 0);
59
60         assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_CHASSIS_ID) >= 0);
61
62         assert_se(tlv_packet_append_u8(m, LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS) >= 0);
63         assert_se(tlv_packet_append_bytes(m, &mac_addr, ETHER_ADDR_LEN) >= 0);
64
65         assert_se(lldp_tlv_packet_close_container(m) >= 0);
66
67         /* port name */
68         assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_PORT_ID) >= 0);
69
70         assert_se(tlv_packet_append_u8(m, LLDP_PORT_SUBTYPE_INTERFACE_NAME) >= 0);
71         assert_se(tlv_packet_append_bytes(m, TEST_LLDP_PORT, strlen(TEST_LLDP_PORT) + 1) >= 0);
72
73         assert_se(lldp_tlv_packet_close_container(m) >= 0);
74
75         /* ttl */
76         assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_TTL) >= 0);
77
78         assert_se(tlv_packet_append_u16(m, 170) >= 0);
79
80         assert_se(lldp_tlv_packet_close_container(m) >= 0);
81
82         /* system name */
83         assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_SYSTEM_NAME) >= 0);
84
85         assert_se(tlv_packet_append_bytes(m, TEST_LLDP_TYPE_SYSTEM_NAME,
86                                           strlen(TEST_LLDP_TYPE_SYSTEM_NAME)) >= 0);
87         assert_se(lldp_tlv_packet_close_container(m) >= 0);
88
89         /* system descrition */
90         assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_SYSTEM_DESCRIPTION) >= 0);
91
92         assert_se(tlv_packet_append_bytes(m, TEST_LLDP_TYPE_SYSTEM_DESC,
93                                           strlen(TEST_LLDP_TYPE_SYSTEM_DESC)) >= 0);
94
95         assert_se(lldp_tlv_packet_close_container(m) >= 0);
96
97         /* Mark end of packet */
98         assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_END) >= 0);
99         assert_se(lldp_tlv_packet_close_container(m) >= 0);
100
101         *ret = m;
102
103         m = NULL;
104
105         return 0;
106 }
107
108 static int lldp_parse_chassis_tlv(tlv_packet *m, uint8_t *type) {
109         uint8_t *p, subtype;
110         uint16_t length;
111
112         assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_CHASSIS_ID) >= 0);
113         assert_se(tlv_packet_read_u8(m, &subtype) >= 0);
114
115         switch (subtype) {
116         case LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS:
117
118                 *type = LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS;
119                 assert_se(tlv_packet_read_bytes(m, &p, &length) >= 0);
120
121                 assert_se(memcmp(p, &mac_addr.ether_addr_octet, ETHER_ADDR_LEN) == 0);
122
123                 break;
124         default:
125                 assert_not_reached("Unhandled option");
126         }
127
128         assert_se(lldp_tlv_packet_exit_container(m) >= 0);
129
130         return 0;
131 }
132
133 static int lldp_parse_port_id_tlv(tlv_packet *m) {
134         char *str = NULL, *p;
135         uint16_t length;
136         uint8_t subtype;
137
138         assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_PORT_ID) >= 0);
139
140         assert_se(tlv_packet_read_u8(m, &subtype) >= 0);
141
142         switch (subtype) {
143         case LLDP_PORT_SUBTYPE_INTERFACE_NAME:
144                 assert_se(tlv_packet_read_string(m, &str, &length) >= 0);
145
146                 p = malloc0(length + 1);
147                 strncpy(p, str, length-1);
148
149                 assert_se(streq(p, TEST_LLDP_PORT) == 1);
150                 break;
151         default:
152                 assert_not_reached("Unhandled option");
153         }
154
155         assert_se(lldp_tlv_packet_exit_container(m) >= 0);
156
157         return 0;
158 }
159
160 static int lldp_parse_system_name_tlv(tlv_packet *m) {
161         char *str = NULL, *p;
162         uint16_t length;
163
164         assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_SYSTEM_NAME) >= 0);
165         assert_se(tlv_packet_read_string(m, &str, &length) >= 0);
166
167         p = malloc0(length + 1);
168         strncpy(p, str, length);
169
170         assert_se(streq(p, TEST_LLDP_TYPE_SYSTEM_NAME) == 1);
171
172         assert_se(lldp_tlv_packet_exit_container(m) >= 0);
173
174         return 1;
175 }
176
177 static int lldp_parse_system_desc_tlv(tlv_packet *m) {
178         char *str = NULL, *p;
179         uint16_t length;
180
181         assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_SYSTEM_DESCRIPTION) >= 0);
182         assert_se(tlv_packet_read_string(m, &str, &length) >= 0);
183
184         p = malloc0(length + 1);
185         strncpy(p, str, length);
186
187         assert_se(streq(p, TEST_LLDP_TYPE_SYSTEM_DESC) == 1);
188
189         assert_se(lldp_tlv_packet_exit_container(m) >= 0);
190
191         return 0;
192 }
193
194 static int lldp_parse_ttl_tlv(tlv_packet *m) {
195         uint16_t ttl;
196
197         assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_TTL) >= 0);
198         assert_se(tlv_packet_read_u16(m, &ttl) >= 0);
199
200         assert_se(ttl == 170);
201
202         assert_se(lldp_tlv_packet_exit_container(m) >= 0);
203
204         return 0;
205 }
206
207 static int lldp_parse_tlv_packet(tlv_packet *m, int len) {
208         uint8_t subtype;
209
210         assert_se(tlv_packet_parse_pdu(m, len) >= 0);
211         assert_se(lldp_parse_chassis_tlv(m, &subtype) >= 0);
212         assert_se(lldp_parse_port_id_tlv(m) >= 0);
213         assert_se(lldp_parse_system_name_tlv(m) >= 0);
214         assert_se(lldp_parse_ttl_tlv(m) >= 0);
215         assert_se(lldp_parse_system_desc_tlv(m) >= 0);
216
217         return 0;
218 }
219
220 int main(int argc, char *argv[]) {
221         _cleanup_tlv_packet_free_ tlv_packet *tlv = NULL;
222
223         /* form a packet */
224         lldp_build_tlv_packet(&tlv);
225
226         /* parse the packet */
227         tlv_packet_parse_pdu(tlv, tlv->length);
228
229         /* verify */
230         lldp_parse_tlv_packet(tlv, tlv->length);
231
232         return 0;
233 }