chiark / gitweb /
ee74ebd418951fe5b566ecf782451ba2f412caed
[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                 .ether_type = htons(ETHERTYPE_LLDP),
50         };
51
52         /* Append ethernet header */
53         memcpy(&ether.ether_dhost, lldp_dst, ETHER_ADDR_LEN);
54         memcpy(&ether.ether_shost, &mac_addr, ETHER_ADDR_LEN);
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         _cleanup_free_ char *p = NULL;
135         char *str = NULL;
136         uint16_t length;
137         uint8_t subtype;
138
139         assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_PORT_ID) >= 0);
140
141         assert_se(tlv_packet_read_u8(m, &subtype) >= 0);
142
143         switch (subtype) {
144         case LLDP_PORT_SUBTYPE_INTERFACE_NAME:
145                 assert_se(tlv_packet_read_string(m, &str, &length) >= 0);
146
147                 p = strndup(str, length-1);
148                 assert_se(p);
149
150                 assert_se(streq(p, TEST_LLDP_PORT) == 1);
151                 break;
152         default:
153                 assert_not_reached("Unhandled option");
154         }
155
156         assert_se(lldp_tlv_packet_exit_container(m) >= 0);
157
158         return 0;
159 }
160
161 static int lldp_parse_system_name_tlv(tlv_packet *m) {
162         _cleanup_free_ char *p = NULL;
163         char *str = NULL;
164         uint16_t length;
165
166         assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_SYSTEM_NAME) >= 0);
167         assert_se(tlv_packet_read_string(m, &str, &length) >= 0);
168
169         p = strndup(str, length);
170         assert_se(p);
171
172         assert_se(streq(p, TEST_LLDP_TYPE_SYSTEM_NAME) == 1);
173
174         assert_se(lldp_tlv_packet_exit_container(m) >= 0);
175
176         return 1;
177 }
178
179 static int lldp_parse_system_desc_tlv(tlv_packet *m) {
180         _cleanup_free_ char *p = NULL;
181         char *str = NULL;
182         uint16_t length;
183
184         assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_SYSTEM_DESCRIPTION) >= 0);
185         assert_se(tlv_packet_read_string(m, &str, &length) >= 0);
186
187         p = strndup(str, length);
188         assert_se(p);
189
190         assert_se(streq(p, TEST_LLDP_TYPE_SYSTEM_DESC) == 1);
191
192         assert_se(lldp_tlv_packet_exit_container(m) >= 0);
193
194         return 0;
195 }
196
197 static int lldp_parse_ttl_tlv(tlv_packet *m) {
198         uint16_t ttl;
199
200         assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_TTL) >= 0);
201         assert_se(tlv_packet_read_u16(m, &ttl) >= 0);
202
203         assert_se(ttl == 170);
204
205         assert_se(lldp_tlv_packet_exit_container(m) >= 0);
206
207         return 0;
208 }
209
210 static int lldp_parse_tlv_packet(tlv_packet *m, int len) {
211         uint8_t subtype;
212
213         assert_se(tlv_packet_parse_pdu(m, len) >= 0);
214         assert_se(lldp_parse_chassis_tlv(m, &subtype) >= 0);
215         assert_se(lldp_parse_port_id_tlv(m) >= 0);
216         assert_se(lldp_parse_system_name_tlv(m) >= 0);
217         assert_se(lldp_parse_ttl_tlv(m) >= 0);
218         assert_se(lldp_parse_system_desc_tlv(m) >= 0);
219
220         return 0;
221 }
222
223 int main(int argc, char *argv[]) {
224         _cleanup_tlv_packet_free_ tlv_packet *tlv = NULL;
225
226         /* form a packet */
227         lldp_build_tlv_packet(&tlv);
228
229         /* parse the packet */
230         tlv_packet_parse_pdu(tlv, tlv->length);
231
232         /* verify */
233         lldp_parse_tlv_packet(tlv, tlv->length);
234
235         return 0;
236 }