1 /* NHRP packet handling functions
2 * Copyright (c) 2014-2015 Timo Teräs
4 * This file is free software: you may copy, redistribute and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
14 #include <netinet/if_ether.h>
20 #include "nhrp_protocol.h"
23 struct nhrp_reqid_pool nhrp_packet_reqid
;
25 static uint16_t family2proto(int family
)
36 static int proto2family(uint16_t proto
)
47 struct nhrp_packet_header
*nhrp_packet_push(struct zbuf
*zb
, uint8_t type
,
48 const union sockunion
*src_nbma
,
49 const union sockunion
*src_proto
,
50 const union sockunion
*dst_proto
)
52 struct nhrp_packet_header
*hdr
;
54 hdr
= zbuf_push(zb
, struct nhrp_packet_header
);
58 *hdr
= (struct nhrp_packet_header
){
59 .afnum
= htons(family2afi(sockunion_family(src_nbma
))),
61 htons(family2proto(sockunion_family(src_proto
))),
62 .version
= NHRP_VERSION_RFC2332
,
65 .src_nbma_address_len
= sockunion_get_addrlen(src_nbma
),
66 .src_protocol_address_len
= sockunion_get_addrlen(src_proto
),
67 .dst_protocol_address_len
= sockunion_get_addrlen(dst_proto
),
70 zbuf_put(zb
, sockunion_get_addr(src_nbma
), hdr
->src_nbma_address_len
);
71 zbuf_put(zb
, sockunion_get_addr(src_proto
),
72 hdr
->src_protocol_address_len
);
73 zbuf_put(zb
, sockunion_get_addr(dst_proto
),
74 hdr
->dst_protocol_address_len
);
79 struct nhrp_packet_header
*nhrp_packet_pull(struct zbuf
*zb
,
80 union sockunion
*src_nbma
,
81 union sockunion
*src_proto
,
82 union sockunion
*dst_proto
)
84 struct nhrp_packet_header
*hdr
;
86 hdr
= zbuf_pull(zb
, struct nhrp_packet_header
);
90 sockunion_set(src_nbma
, afi2family(htons(hdr
->afnum
)),
92 hdr
->src_nbma_address_len
93 + hdr
->src_nbma_subaddress_len
),
94 hdr
->src_nbma_address_len
+ hdr
->src_nbma_subaddress_len
);
95 sockunion_set(src_proto
, proto2family(htons(hdr
->protocol_type
)),
96 zbuf_pulln(zb
, hdr
->src_protocol_address_len
),
97 hdr
->src_protocol_address_len
);
98 sockunion_set(dst_proto
, proto2family(htons(hdr
->protocol_type
)),
99 zbuf_pulln(zb
, hdr
->dst_protocol_address_len
),
100 hdr
->dst_protocol_address_len
);
105 uint16_t nhrp_packet_calculate_checksum(const uint8_t *pdu
, uint16_t len
)
107 const uint16_t *pdu16
= (const uint16_t *)pdu
;
111 for (i
= 0; i
< len
/ 2; i
++)
114 csum
+= htons(pdu
[len
- 1]);
116 while (csum
& 0xffff0000)
117 csum
= (csum
& 0xffff) + (csum
>> 16);
119 return (~csum
) & 0xffff;
122 void nhrp_packet_complete(struct zbuf
*zb
, struct nhrp_packet_header
*hdr
)
126 if (hdr
->extension_offset
)
127 nhrp_ext_push(zb
, hdr
,
129 | NHRP_EXTENSION_FLAG_COMPULSORY
);
131 size
= zb
->tail
- (uint8_t *)hdr
;
132 hdr
->packet_size
= htons(size
);
134 hdr
->checksum
= nhrp_packet_calculate_checksum((uint8_t *)hdr
, size
);
137 struct nhrp_cie_header
*nhrp_cie_push(struct zbuf
*zb
, uint8_t code
,
138 const union sockunion
*nbma
,
139 const union sockunion
*proto
)
141 struct nhrp_cie_header
*cie
;
143 cie
= zbuf_push(zb
, struct nhrp_cie_header
);
144 *cie
= (struct nhrp_cie_header
){
148 cie
->nbma_address_len
= sockunion_get_addrlen(nbma
);
149 zbuf_put(zb
, sockunion_get_addr(nbma
), cie
->nbma_address_len
);
152 cie
->protocol_address_len
= sockunion_get_addrlen(proto
);
153 zbuf_put(zb
, sockunion_get_addr(proto
),
154 cie
->protocol_address_len
);
160 struct nhrp_cie_header
*nhrp_cie_pull(struct zbuf
*zb
,
161 struct nhrp_packet_header
*hdr
,
162 union sockunion
*nbma
,
163 union sockunion
*proto
)
165 struct nhrp_cie_header
*cie
;
167 cie
= zbuf_pull(zb
, struct nhrp_cie_header
);
171 if (cie
->nbma_address_len
+ cie
->nbma_subaddress_len
> 0) {
172 sockunion_set(nbma
, afi2family(htons(hdr
->afnum
)),
174 cie
->nbma_address_len
175 + cie
->nbma_subaddress_len
),
176 cie
->nbma_address_len
+ cie
->nbma_subaddress_len
);
178 sockunion_family(nbma
) = AF_UNSPEC
;
181 if (cie
->protocol_address_len
) {
182 sockunion_set(proto
, proto2family(htons(hdr
->protocol_type
)),
183 zbuf_pulln(zb
, cie
->protocol_address_len
),
184 cie
->protocol_address_len
);
186 sockunion_family(proto
) = AF_UNSPEC
;
192 struct nhrp_extension_header
*
193 nhrp_ext_push(struct zbuf
*zb
, struct nhrp_packet_header
*hdr
, uint16_t type
)
195 struct nhrp_extension_header
*ext
;
196 ext
= zbuf_push(zb
, struct nhrp_extension_header
);
200 if (!hdr
->extension_offset
)
201 hdr
->extension_offset
=
202 htons(zb
->tail
- (uint8_t *)hdr
203 - sizeof(struct nhrp_extension_header
));
205 *ext
= (struct nhrp_extension_header
){
206 .type
= htons(type
), .length
= 0,
211 void nhrp_ext_complete(struct zbuf
*zb
, struct nhrp_extension_header
*ext
)
213 ext
->length
= htons(zb
->tail
- (uint8_t *)ext
214 - sizeof(struct nhrp_extension_header
));
217 struct nhrp_extension_header
*nhrp_ext_pull(struct zbuf
*zb
,
218 struct zbuf
*payload
)
220 struct nhrp_extension_header
*ext
;
223 ext
= zbuf_pull(zb
, struct nhrp_extension_header
);
227 plen
= htons(ext
->length
);
228 zbuf_init(payload
, zbuf_pulln(zb
, plen
), plen
, plen
);
232 void nhrp_ext_request(struct zbuf
*zb
, struct nhrp_packet_header
*hdr
,
233 struct interface
*ifp
)
235 /* Place holders for standard extensions */
236 nhrp_ext_push(zb
, hdr
,
237 NHRP_EXTENSION_FORWARD_TRANSIT_NHS
238 | NHRP_EXTENSION_FLAG_COMPULSORY
);
239 nhrp_ext_push(zb
, hdr
,
240 NHRP_EXTENSION_REVERSE_TRANSIT_NHS
241 | NHRP_EXTENSION_FLAG_COMPULSORY
);
242 nhrp_ext_push(zb
, hdr
,
243 NHRP_EXTENSION_RESPONDER_ADDRESS
244 | NHRP_EXTENSION_FLAG_COMPULSORY
);
247 int nhrp_ext_reply(struct zbuf
*zb
, struct nhrp_packet_header
*hdr
,
248 struct interface
*ifp
, struct nhrp_extension_header
*ext
,
249 struct zbuf
*extpayload
)
251 struct nhrp_interface
*nifp
= ifp
->info
;
252 struct nhrp_afi_data
*ad
= &nifp
->afi
[htons(hdr
->afnum
)];
253 struct nhrp_extension_header
*dst
;
254 struct nhrp_cie_header
*cie
;
257 type
= htons(ext
->type
) & ~NHRP_EXTENSION_FLAG_COMPULSORY
;
258 if (type
== NHRP_EXTENSION_END
)
261 dst
= nhrp_ext_push(zb
, hdr
, htons(ext
->type
));
266 case NHRP_EXTENSION_RESPONDER_ADDRESS
:
267 cie
= nhrp_cie_push(zb
, NHRP_CODE_SUCCESS
, &nifp
->nbma
,
271 cie
->holding_time
= htons(ad
->holdtime
);
274 if (type
& NHRP_EXTENSION_FLAG_COMPULSORY
)
277 case NHRP_EXTENSION_FORWARD_TRANSIT_NHS
:
278 case NHRP_EXTENSION_REVERSE_TRANSIT_NHS
:
279 /* Supported compulsory extensions, and any
280 * non-compulsory that is not explicitly handled,
281 * should be just copied. */
282 zbuf_copy(zb
, extpayload
, zbuf_used(extpayload
));
285 nhrp_ext_complete(zb
, dst
);
292 static int nhrp_packet_recvraw(struct thread
*t
)
294 int fd
= THREAD_FD(t
), ifindex
;
296 struct interface
*ifp
;
298 union sockunion remote_nbma
;
302 thread_add_read(master
, nhrp_packet_recvraw
, 0, fd
, NULL
);
304 zb
= zbuf_alloc(1500);
309 addrlen
= sizeof(addr
);
310 if (os_recvmsg(zb
->buf
, &len
, &ifindex
, addr
, &addrlen
) < 0)
314 zb
->tail
= zb
->buf
+ len
;
318 sockunion_set(&remote_nbma
, AF_INET
, addr
, addrlen
);
324 ifp
= if_lookup_by_index(ifindex
, VRF_DEFAULT
);
328 p
= nhrp_peer_get(ifp
, &remote_nbma
);
332 nhrp_peer_recv(p
, zb
);
341 int nhrp_packet_init(void)
343 thread_add_read(master
, nhrp_packet_recvraw
, 0, os_socket(), NULL
);