1*9246985aSrenato /* $OpenBSD: init.c,v 1.37 2017/03/04 00:15:35 renato Exp $ */
2ab0c2486Smichele
3ab0c2486Smichele /*
4ab0c2486Smichele * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
5ab0c2486Smichele *
6ab0c2486Smichele * Permission to use, copy, modify, and distribute this software for any
7ab0c2486Smichele * purpose with or without fee is hereby granted, provided that the above
8ab0c2486Smichele * copyright notice and this permission notice appear in all copies.
9ab0c2486Smichele *
10ab0c2486Smichele * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11ab0c2486Smichele * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12ab0c2486Smichele * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13ab0c2486Smichele * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14ab0c2486Smichele * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15ab0c2486Smichele * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16ab0c2486Smichele * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17ab0c2486Smichele */
18ab0c2486Smichele
19ab0c2486Smichele #include <sys/types.h>
20ab0c2486Smichele #include <arpa/inet.h>
21ab0c2486Smichele #include <string.h>
22ab0c2486Smichele
23ab0c2486Smichele #include "ldpd.h"
24ab0c2486Smichele #include "ldpe.h"
255411bbb6Srenato #include "log.h"
26ab0c2486Smichele
27d3e006a4Srenato static int gen_init_prms_tlv(struct ibuf *, struct nbr *);
283b4c1866Srenato static int gen_cap_dynamic_tlv(struct ibuf *);
29c7c5a728Srenato static int gen_cap_twcard_tlv(struct ibuf *, int);
30*9246985aSrenato static int gen_cap_unotif_tlv(struct ibuf *, int);
31ab0c2486Smichele
32a6fc12d8Smichele void
send_init(struct nbr * nbr)33ab0c2486Smichele send_init(struct nbr *nbr)
34ab0c2486Smichele {
35e39620e5Snicm struct ibuf *buf;
363de94509Srenato uint16_t size;
3765f1d9c1Srenato int err = 0;
38ab0c2486Smichele
39d99a8fc3Srenato log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id));
40ab0c2486Smichele
413b4c1866Srenato size = LDP_HDR_SIZE + LDP_MSG_SIZE + SESS_PRMS_SIZE +
42*9246985aSrenato CAP_TLV_DYNAMIC_SIZE + CAP_TLV_TWCARD_SIZE + CAP_TLV_UNOTIF_SIZE;
439277622bSrenato if ((buf = ibuf_open(size)) == NULL)
44b7b4db73Srenato fatal(__func__);
45ab0c2486Smichele
4665f1d9c1Srenato err |= gen_ldp_hdr(buf, size);
47ab0c2486Smichele size -= LDP_HDR_SIZE;
4865f1d9c1Srenato err |= gen_msg_hdr(buf, MSG_TYPE_INIT, size);
49d3e006a4Srenato err |= gen_init_prms_tlv(buf, nbr);
503b4c1866Srenato err |= gen_cap_dynamic_tlv(buf);
51c7c5a728Srenato err |= gen_cap_twcard_tlv(buf, 1);
52*9246985aSrenato err |= gen_cap_unotif_tlv(buf, 1);
5365f1d9c1Srenato if (err) {
5465f1d9c1Srenato ibuf_free(buf);
5565f1d9c1Srenato return;
5665f1d9c1Srenato }
57ab0c2486Smichele
58699b7d06Sclaudio evbuf_enqueue(&nbr->tcp->wbuf, buf);
59ab0c2486Smichele }
60ab0c2486Smichele
61ab0c2486Smichele int
recv_init(struct nbr * nbr,char * buf,uint16_t len)623de94509Srenato recv_init(struct nbr *nbr, char *buf, uint16_t len)
63ab0c2486Smichele {
6460e1e0e7Srenato struct ldp_msg msg;
6589f23408Sclaudio struct sess_prms_tlv sess;
66feeedd8aSrenato uint16_t max_pdu_len;
673b4c1866Srenato int caps_rcvd = 0;
68ab0c2486Smichele
69d99a8fc3Srenato log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id));
70ab0c2486Smichele
7160e1e0e7Srenato memcpy(&msg, buf, sizeof(msg));
723de94509Srenato buf += LDP_MSG_SIZE;
733de94509Srenato len -= LDP_MSG_SIZE;
74ab0c2486Smichele
7589f23408Sclaudio if (len < SESS_PRMS_SIZE) {
7660e1e0e7Srenato session_shutdown(nbr, S_BAD_MSG_LEN, msg.id, msg.type);
7789f23408Sclaudio return (-1);
7889f23408Sclaudio }
793de94509Srenato memcpy(&sess, buf, sizeof(sess));
8060e1e0e7Srenato if (ntohs(sess.length) != SESS_PRMS_LEN) {
8160e1e0e7Srenato session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
82ab0c2486Smichele return (-1);
83ab0c2486Smichele }
8435791d36Srenato if (ntohs(sess.proto_version) != LDP_VERSION) {
8560e1e0e7Srenato session_shutdown(nbr, S_BAD_PROTO_VER, msg.id, msg.type);
8635791d36Srenato return (-1);
8735791d36Srenato }
88d3e006a4Srenato if (ntohs(sess.keepalive_time) < MIN_KEEPALIVE) {
8960e1e0e7Srenato session_shutdown(nbr, S_KEEPALIVE_BAD, msg.id, msg.type);
90d3e006a4Srenato return (-1);
91d3e006a4Srenato }
926af85cd7Srenato if (sess.lsr_id != leconf->rtr_id.s_addr ||
936af85cd7Srenato ntohs(sess.lspace_id) != 0) {
9460e1e0e7Srenato session_shutdown(nbr, S_NO_HELLO, msg.id, msg.type);
956af85cd7Srenato return (-1);
966af85cd7Srenato }
9735791d36Srenato
98080776f3Sclaudio buf += SESS_PRMS_SIZE;
99080776f3Sclaudio len -= SESS_PRMS_SIZE;
100080776f3Sclaudio
101a78ea73fSrenato /* Optional Parameters */
102a78ea73fSrenato while (len > 0) {
103a78ea73fSrenato struct tlv tlv;
1043b4c1866Srenato uint16_t tlv_type;
105a78ea73fSrenato uint16_t tlv_len;
106a78ea73fSrenato
107a78ea73fSrenato if (len < sizeof(tlv)) {
108a78ea73fSrenato session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
109a78ea73fSrenato return (-1);
110a78ea73fSrenato }
111a78ea73fSrenato
112a78ea73fSrenato memcpy(&tlv, buf, TLV_HDR_SIZE);
1133b4c1866Srenato tlv_type = ntohs(tlv.type);
114a78ea73fSrenato tlv_len = ntohs(tlv.length);
115a78ea73fSrenato if (tlv_len + TLV_HDR_SIZE > len) {
116a78ea73fSrenato session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
117a78ea73fSrenato return (-1);
118a78ea73fSrenato }
119a78ea73fSrenato buf += TLV_HDR_SIZE;
120a78ea73fSrenato len -= TLV_HDR_SIZE;
121a78ea73fSrenato
1223b4c1866Srenato /*
1233b4c1866Srenato * RFC 5561 - Section 6:
1243b4c1866Srenato * "The S-bit of a Capability Parameter in an Initialization
1253b4c1866Srenato * message MUST be 1 and SHOULD be ignored on receipt".
1263b4c1866Srenato */
1273b4c1866Srenato switch (tlv_type) {
128a78ea73fSrenato case TLV_TYPE_ATMSESSIONPAR:
12960e1e0e7Srenato session_shutdown(nbr, S_BAD_TLV_VAL, msg.id, msg.type);
130080776f3Sclaudio return (-1);
131a78ea73fSrenato case TLV_TYPE_FRSESSION:
132a78ea73fSrenato session_shutdown(nbr, S_BAD_TLV_VAL, msg.id, msg.type);
133a78ea73fSrenato return (-1);
1343b4c1866Srenato case TLV_TYPE_DYNAMIC_CAP:
1353b4c1866Srenato if (tlv_len != CAP_TLV_DYNAMIC_LEN) {
1363b4c1866Srenato session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
1373b4c1866Srenato msg.type);
1383b4c1866Srenato return (-1);
1393b4c1866Srenato }
1403b4c1866Srenato
1413b4c1866Srenato if (caps_rcvd & F_CAP_TLV_RCVD_DYNAMIC) {
1423b4c1866Srenato session_shutdown(nbr, S_BAD_TLV_VAL, msg.id,
1433b4c1866Srenato msg.type);
1443b4c1866Srenato return (-1);
1453b4c1866Srenato }
1463b4c1866Srenato caps_rcvd |= F_CAP_TLV_RCVD_DYNAMIC;
1473b4c1866Srenato
1483b4c1866Srenato nbr->flags |= F_NBR_CAP_DYNAMIC;
1493b4c1866Srenato
1503b4c1866Srenato log_debug("%s: lsr-id %s announced the Dynamic "
1513b4c1866Srenato "Capability Announcement capability", __func__,
1523b4c1866Srenato inet_ntoa(nbr->id));
1533b4c1866Srenato break;
154c7c5a728Srenato case TLV_TYPE_TWCARD_CAP:
155c7c5a728Srenato if (tlv_len != CAP_TLV_TWCARD_LEN) {
156c7c5a728Srenato session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
157c7c5a728Srenato msg.type);
158c7c5a728Srenato return (-1);
159c7c5a728Srenato }
160c7c5a728Srenato
161c7c5a728Srenato if (caps_rcvd & F_CAP_TLV_RCVD_TWCARD) {
162c7c5a728Srenato session_shutdown(nbr, S_BAD_TLV_VAL, msg.id,
163c7c5a728Srenato msg.type);
164c7c5a728Srenato return (-1);
165c7c5a728Srenato }
166c7c5a728Srenato caps_rcvd |= F_CAP_TLV_RCVD_TWCARD;
167c7c5a728Srenato
168c7c5a728Srenato nbr->flags |= F_NBR_CAP_TWCARD;
169c7c5a728Srenato
170c7c5a728Srenato log_debug("%s: lsr-id %s announced the Typed Wildcard "
171c7c5a728Srenato "FEC capability", __func__, inet_ntoa(nbr->id));
172c7c5a728Srenato break;
173*9246985aSrenato case TLV_TYPE_UNOTIF_CAP:
174*9246985aSrenato if (tlv_len != CAP_TLV_UNOTIF_LEN) {
175*9246985aSrenato session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
176*9246985aSrenato msg.type);
177*9246985aSrenato return (-1);
178*9246985aSrenato }
179*9246985aSrenato
180*9246985aSrenato if (caps_rcvd & F_CAP_TLV_RCVD_UNOTIF) {
181*9246985aSrenato session_shutdown(nbr, S_BAD_TLV_VAL, msg.id,
182*9246985aSrenato msg.type);
183*9246985aSrenato return (-1);
184*9246985aSrenato }
185*9246985aSrenato caps_rcvd |= F_CAP_TLV_RCVD_UNOTIF;
186*9246985aSrenato
187*9246985aSrenato nbr->flags |= F_NBR_CAP_UNOTIF;
188*9246985aSrenato
189*9246985aSrenato log_debug("%s: lsr-id %s announced the Unrecognized "
190*9246985aSrenato "Notification capability", __func__,
191*9246985aSrenato inet_ntoa(nbr->id));
192*9246985aSrenato break;
193a78ea73fSrenato default:
194a78ea73fSrenato if (!(ntohs(tlv.type) & UNKNOWN_FLAG))
1953b4c1866Srenato send_notification_rtlvs(nbr, S_UNSSUPORTDCAP,
1963b4c1866Srenato msg.id, msg.type, tlv_type, tlv_len, buf);
197a78ea73fSrenato /* ignore unknown tlv */
198a78ea73fSrenato break;
199a78ea73fSrenato }
200a78ea73fSrenato buf += tlv_len;
201a78ea73fSrenato len -= tlv_len;
202080776f3Sclaudio }
20389f23408Sclaudio
204a8c39dc0Srenato nbr->keepalive = min(nbr_get_keepalive(nbr->af, nbr->id),
2053d39db89Srenato ntohs(sess.keepalive_time));
206ab0c2486Smichele
207feeedd8aSrenato max_pdu_len = ntohs(sess.max_pdu_len);
208feeedd8aSrenato /*
209feeedd8aSrenato * RFC 5036 - Section 3.5.3:
210feeedd8aSrenato * "A value of 255 or less specifies the default maximum length of
211feeedd8aSrenato * 4096 octets".
212feeedd8aSrenato */
213feeedd8aSrenato if (max_pdu_len <= 255)
214feeedd8aSrenato max_pdu_len = LDP_MAX_LEN;
215feeedd8aSrenato nbr->max_pdu_len = min(max_pdu_len, LDP_MAX_LEN);
216feeedd8aSrenato
217ab0c2486Smichele nbr_fsm(nbr, NBR_EVT_INIT_RCVD);
218ab0c2486Smichele
2199277622bSrenato return (0);
220ab0c2486Smichele }
221ab0c2486Smichele
2223b4c1866Srenato void
send_capability(struct nbr * nbr,uint16_t capability,int enable)2233b4c1866Srenato send_capability(struct nbr *nbr, uint16_t capability, int enable)
2243b4c1866Srenato {
2253b4c1866Srenato struct ibuf *buf;
2263b4c1866Srenato uint16_t size;
2273b4c1866Srenato int err = 0;
2283b4c1866Srenato
2293b4c1866Srenato log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id));
2303b4c1866Srenato
2313b4c1866Srenato size = LDP_HDR_SIZE + LDP_MSG_SIZE + CAP_TLV_DYNAMIC_SIZE;
2323b4c1866Srenato if ((buf = ibuf_open(size)) == NULL)
2333b4c1866Srenato fatal(__func__);
2343b4c1866Srenato
2353b4c1866Srenato err |= gen_ldp_hdr(buf, size);
2363b4c1866Srenato size -= LDP_HDR_SIZE;
2373b4c1866Srenato err |= gen_msg_hdr(buf, MSG_TYPE_CAPABILITY, size);
2383b4c1866Srenato
2393b4c1866Srenato switch (capability) {
240c7c5a728Srenato case TLV_TYPE_TWCARD_CAP:
241c7c5a728Srenato err |= gen_cap_twcard_tlv(buf, enable);
242c7c5a728Srenato break;
243*9246985aSrenato case TLV_TYPE_UNOTIF_CAP:
244*9246985aSrenato err |= gen_cap_unotif_tlv(buf, enable);
245*9246985aSrenato break;
2463b4c1866Srenato case TLV_TYPE_DYNAMIC_CAP:
2473b4c1866Srenato /*
2483b4c1866Srenato * RFC 5561 - Section 9:
2493b4c1866Srenato * "An LDP speaker MUST NOT include the Dynamic Capability
2503b4c1866Srenato * Announcement Parameter in Capability messages sent to
2513b4c1866Srenato * its peers".
2523b4c1866Srenato */
2533b4c1866Srenato /* FALLTHROUGH */
2543b4c1866Srenato default:
2553b4c1866Srenato fatalx("send_capability: unsupported capability");
2563b4c1866Srenato }
2573b4c1866Srenato
2583b4c1866Srenato if (err) {
2593b4c1866Srenato ibuf_free(buf);
2603b4c1866Srenato return;
2613b4c1866Srenato }
2623b4c1866Srenato
2633b4c1866Srenato evbuf_enqueue(&nbr->tcp->wbuf, buf);
2643b4c1866Srenato nbr_fsm(nbr, NBR_EVT_PDU_SENT);
2653b4c1866Srenato }
2663b4c1866Srenato
2673b4c1866Srenato int
recv_capability(struct nbr * nbr,char * buf,uint16_t len)2683b4c1866Srenato recv_capability(struct nbr *nbr, char *buf, uint16_t len)
2693b4c1866Srenato {
2703b4c1866Srenato struct ldp_msg msg;
271c7c5a728Srenato int enable = 0;
272c7c5a728Srenato int caps_rcvd = 0;
2733b4c1866Srenato
2743b4c1866Srenato log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id));
2753b4c1866Srenato
2763b4c1866Srenato memcpy(&msg, buf, sizeof(msg));
2773b4c1866Srenato buf += LDP_MSG_SIZE;
2783b4c1866Srenato len -= LDP_MSG_SIZE;
2793b4c1866Srenato
2803b4c1866Srenato /* Optional Parameters */
2813b4c1866Srenato while (len > 0) {
2823b4c1866Srenato struct tlv tlv;
2833b4c1866Srenato uint16_t tlv_type;
2843b4c1866Srenato uint16_t tlv_len;
285c7c5a728Srenato uint8_t reserved;
2863b4c1866Srenato
2873b4c1866Srenato if (len < sizeof(tlv)) {
2883b4c1866Srenato session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
2893b4c1866Srenato return (-1);
2903b4c1866Srenato }
2913b4c1866Srenato
2923b4c1866Srenato memcpy(&tlv, buf, TLV_HDR_SIZE);
2933b4c1866Srenato tlv_type = ntohs(tlv.type);
2943b4c1866Srenato tlv_len = ntohs(tlv.length);
2953b4c1866Srenato if (tlv_len + TLV_HDR_SIZE > len) {
2963b4c1866Srenato session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
2973b4c1866Srenato return (-1);
2983b4c1866Srenato }
2993b4c1866Srenato buf += TLV_HDR_SIZE;
3003b4c1866Srenato len -= TLV_HDR_SIZE;
3013b4c1866Srenato
3023b4c1866Srenato switch (tlv_type) {
303c7c5a728Srenato case TLV_TYPE_TWCARD_CAP:
304c7c5a728Srenato if (tlv_len != CAP_TLV_TWCARD_LEN) {
305c7c5a728Srenato session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
306c7c5a728Srenato msg.type);
307c7c5a728Srenato return (-1);
308c7c5a728Srenato }
309c7c5a728Srenato
310c7c5a728Srenato if (caps_rcvd & F_CAP_TLV_RCVD_TWCARD) {
311c7c5a728Srenato session_shutdown(nbr, S_BAD_TLV_VAL, msg.id,
312c7c5a728Srenato msg.type);
313c7c5a728Srenato return (-1);
314c7c5a728Srenato }
315c7c5a728Srenato caps_rcvd |= F_CAP_TLV_RCVD_TWCARD;
316c7c5a728Srenato
317c7c5a728Srenato memcpy(&reserved, buf, sizeof(reserved));
318c7c5a728Srenato enable = reserved & STATE_BIT;
319c7c5a728Srenato if (enable)
320c7c5a728Srenato nbr->flags |= F_NBR_CAP_TWCARD;
321c7c5a728Srenato else
322c7c5a728Srenato nbr->flags &= ~F_NBR_CAP_TWCARD;
323c7c5a728Srenato
324c7c5a728Srenato log_debug("%s: lsr-id %s %s the Typed Wildcard FEC "
325c7c5a728Srenato "capability", __func__, inet_ntoa(nbr->id),
326c7c5a728Srenato (enable) ? "announced" : "withdrew");
327c7c5a728Srenato break;
328*9246985aSrenato case TLV_TYPE_UNOTIF_CAP:
329*9246985aSrenato if (tlv_len != CAP_TLV_UNOTIF_LEN) {
330*9246985aSrenato session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
331*9246985aSrenato msg.type);
332*9246985aSrenato return (-1);
333*9246985aSrenato }
334*9246985aSrenato
335*9246985aSrenato if (caps_rcvd & F_CAP_TLV_RCVD_UNOTIF) {
336*9246985aSrenato session_shutdown(nbr, S_BAD_TLV_VAL, msg.id,
337*9246985aSrenato msg.type);
338*9246985aSrenato return (-1);
339*9246985aSrenato }
340*9246985aSrenato caps_rcvd |= F_CAP_TLV_RCVD_UNOTIF;
341*9246985aSrenato
342*9246985aSrenato memcpy(&reserved, buf, sizeof(reserved));
343*9246985aSrenato enable = reserved & STATE_BIT;
344*9246985aSrenato if (enable)
345*9246985aSrenato nbr->flags |= F_NBR_CAP_UNOTIF;
346*9246985aSrenato else
347*9246985aSrenato nbr->flags &= ~F_NBR_CAP_UNOTIF;
348*9246985aSrenato
349*9246985aSrenato log_debug("%s: lsr-id %s %s the Unrecognized "
350*9246985aSrenato "Notification capability", __func__,
351*9246985aSrenato inet_ntoa(nbr->id), (enable) ? "announced" :
352*9246985aSrenato "withdrew");
353*9246985aSrenato break;
3543b4c1866Srenato case TLV_TYPE_DYNAMIC_CAP:
3553b4c1866Srenato /*
3563b4c1866Srenato * RFC 5561 - Section 9:
3573b4c1866Srenato * "An LDP speaker that receives a Capability message
3583b4c1866Srenato * from a peer that includes the Dynamic Capability
3593b4c1866Srenato * Announcement Parameter SHOULD silently ignore the
3603b4c1866Srenato * parameter and process any other Capability Parameters
3613b4c1866Srenato * in the message".
3623b4c1866Srenato */
3633b4c1866Srenato /* FALLTHROUGH */
3643b4c1866Srenato default:
3653b4c1866Srenato if (!(ntohs(tlv.type) & UNKNOWN_FLAG))
3663b4c1866Srenato send_notification_rtlvs(nbr, S_UNSSUPORTDCAP,
3673b4c1866Srenato msg.id, msg.type, tlv_type, tlv_len, buf);
3683b4c1866Srenato /* ignore unknown tlv */
3693b4c1866Srenato break;
3703b4c1866Srenato }
3713b4c1866Srenato buf += tlv_len;
3723b4c1866Srenato len -= tlv_len;
3733b4c1866Srenato }
3743b4c1866Srenato
3753b4c1866Srenato nbr_fsm(nbr, NBR_EVT_PDU_RCVD);
3763b4c1866Srenato
3773b4c1866Srenato return (0);
3783b4c1866Srenato }
3793b4c1866Srenato
380c28a25a1Srenato static int
gen_init_prms_tlv(struct ibuf * buf,struct nbr * nbr)381d3e006a4Srenato gen_init_prms_tlv(struct ibuf *buf, struct nbr *nbr)
382ab0c2486Smichele {
383ab0c2486Smichele struct sess_prms_tlv parms;
384ab0c2486Smichele
3853de94509Srenato memset(&parms, 0, sizeof(parms));
386ab0c2486Smichele parms.type = htons(TLV_TYPE_COMMONSESSION);
38760e1e0e7Srenato parms.length = htons(SESS_PRMS_LEN);
388ab0c2486Smichele parms.proto_version = htons(LDP_VERSION);
389a8c39dc0Srenato parms.keepalive_time = htons(nbr_get_keepalive(nbr->af, nbr->id));
390ab0c2486Smichele parms.reserved = 0;
391ab0c2486Smichele parms.pvlim = 0;
392ab0c2486Smichele parms.max_pdu_len = 0;
393ab0c2486Smichele parms.lsr_id = nbr->id.s_addr;
394ab0c2486Smichele parms.lspace_id = 0;
395ab0c2486Smichele
396e39620e5Snicm return (ibuf_add(buf, &parms, SESS_PRMS_SIZE));
397ab0c2486Smichele }
3983b4c1866Srenato
3993b4c1866Srenato static int
gen_cap_dynamic_tlv(struct ibuf * buf)4003b4c1866Srenato gen_cap_dynamic_tlv(struct ibuf *buf)
4013b4c1866Srenato {
4023b4c1866Srenato struct capability_tlv cap;
4033b4c1866Srenato
4043b4c1866Srenato memset(&cap, 0, sizeof(cap));
4053b4c1866Srenato cap.type = htons(TLV_TYPE_DYNAMIC_CAP);
4063b4c1866Srenato cap.length = htons(CAP_TLV_DYNAMIC_LEN);
4073b4c1866Srenato /* the S-bit is always 1 for the Dynamic Capability Announcement */
4083b4c1866Srenato cap.reserved = STATE_BIT;
4093b4c1866Srenato
4103b4c1866Srenato return (ibuf_add(buf, &cap, CAP_TLV_DYNAMIC_SIZE));
4113b4c1866Srenato }
412c7c5a728Srenato
413c7c5a728Srenato static int
gen_cap_twcard_tlv(struct ibuf * buf,int enable)414c7c5a728Srenato gen_cap_twcard_tlv(struct ibuf *buf, int enable)
415c7c5a728Srenato {
416c7c5a728Srenato struct capability_tlv cap;
417c7c5a728Srenato
418c7c5a728Srenato memset(&cap, 0, sizeof(cap));
419c7c5a728Srenato cap.type = htons(TLV_TYPE_TWCARD_CAP);
420c7c5a728Srenato cap.length = htons(CAP_TLV_TWCARD_LEN);
421c7c5a728Srenato if (enable)
422c7c5a728Srenato cap.reserved = STATE_BIT;
423c7c5a728Srenato
424c7c5a728Srenato return (ibuf_add(buf, &cap, CAP_TLV_TWCARD_SIZE));
425c7c5a728Srenato }
426*9246985aSrenato
427*9246985aSrenato static int
gen_cap_unotif_tlv(struct ibuf * buf,int enable)428*9246985aSrenato gen_cap_unotif_tlv(struct ibuf *buf, int enable)
429*9246985aSrenato {
430*9246985aSrenato struct capability_tlv cap;
431*9246985aSrenato
432*9246985aSrenato memset(&cap, 0, sizeof(cap));
433*9246985aSrenato cap.type = htons(TLV_TYPE_UNOTIF_CAP);
434*9246985aSrenato cap.length = htons(CAP_TLV_UNOTIF_LEN);
435*9246985aSrenato if (enable)
436*9246985aSrenato cap.reserved = STATE_BIT;
437*9246985aSrenato
438*9246985aSrenato return (ibuf_add(buf, &cap, CAP_TLV_UNOTIF_SIZE));
439*9246985aSrenato }
440