init.c revision 1.21
1/*	$OpenBSD: init.c,v 1.21 2016/05/23 16:04:04 renato Exp $ */
2
3/*
4 * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#include <sys/types.h>
20#include <sys/socket.h>
21#include <sys/uio.h>
22
23#include <netinet/in.h>
24#include <netinet/ip.h>
25#include <arpa/inet.h>
26#include <net/if_dl.h>
27#include <unistd.h>
28
29#include <errno.h>
30#include <event.h>
31#include <stdlib.h>
32#include <string.h>
33
34#include "ldpd.h"
35#include "ldp.h"
36#include "log.h"
37#include "ldpe.h"
38
39extern struct ldpd_conf        *leconf;
40
41int	gen_init_prms_tlv(struct ibuf *, struct nbr *, u_int16_t);
42int	tlv_decode_opt_init_prms(char *, u_int16_t);
43
44void
45send_init(struct nbr *nbr)
46{
47	struct ibuf		*buf;
48	u_int16_t		 size;
49
50	log_debug("%s: neighbor ID %s", __func__, inet_ntoa(nbr->id));
51
52	size = LDP_HDR_SIZE + LDP_MSG_SIZE + SESS_PRMS_SIZE;
53	if ((buf = ibuf_open(size)) == NULL)
54		fatal(__func__);
55
56	gen_ldp_hdr(buf, size);
57	size -= LDP_HDR_SIZE;
58	gen_msg_hdr(buf, MSG_TYPE_INIT, size);
59	size -= LDP_MSG_SIZE;
60	gen_init_prms_tlv(buf, nbr, size);
61
62	evbuf_enqueue(&nbr->tcp->wbuf, buf);
63}
64
65int
66recv_init(struct nbr *nbr, char *buf, u_int16_t len)
67{
68	struct ldp_msg		init;
69	struct sess_prms_tlv	sess;
70	uint16_t		max_pdu_len;
71
72	log_debug("%s: neighbor ID %s", __func__, inet_ntoa(nbr->id));
73
74	bcopy(buf, &init, sizeof(init));
75
76	buf += sizeof(struct ldp_msg);
77	len -= sizeof(struct ldp_msg);
78
79	if (len < SESS_PRMS_SIZE) {
80		session_shutdown(nbr, S_BAD_MSG_LEN, init.msgid, init.type);
81		return (-1);
82	}
83	bcopy(buf, &sess, sizeof(sess));
84
85	if (ntohs(sess.length) != SESS_PRMS_SIZE - TLV_HDR_LEN) {
86		session_shutdown(nbr, S_BAD_TLV_LEN, init.msgid, init.type);
87		return (-1);
88	}
89
90	if (ntohs(sess.proto_version) != LDP_VERSION) {
91		session_shutdown(nbr, S_BAD_PROTO_VER, init.msgid, init.type);
92		return (-1);
93	}
94
95	buf += SESS_PRMS_SIZE;
96	len -= SESS_PRMS_SIZE;
97
98	/* just ignore all optional TLVs for now */
99	if (tlv_decode_opt_init_prms(buf, len) == -1) {
100		session_shutdown(nbr, S_BAD_TLV_VAL, init.msgid, init.type);
101		return (-1);
102	}
103
104	nbr->keepalive = min(nbr_get_keepalive(nbr->raddr),
105	    ntohs(sess.keepalive_time));
106
107	max_pdu_len = ntohs(sess.max_pdu_len);
108	/*
109	 * RFC 5036 - Section 3.5.3:
110	 * "A value of 255 or less specifies the default maximum length of
111	 * 4096 octets".
112	 */
113	if (max_pdu_len <= 255)
114		max_pdu_len = LDP_MAX_LEN;
115	nbr->max_pdu_len = min(max_pdu_len, LDP_MAX_LEN);
116
117	nbr_fsm(nbr, NBR_EVT_INIT_RCVD);
118
119	return (0);
120}
121
122int
123gen_init_prms_tlv(struct ibuf *buf, struct nbr *nbr, u_int16_t size)
124{
125	struct sess_prms_tlv	parms;
126
127	/* We want just the size of the value */
128	size -= TLV_HDR_LEN;
129
130	bzero(&parms, sizeof(parms));
131	parms.type = htons(TLV_TYPE_COMMONSESSION);
132	parms.length = htons(size);
133	parms.proto_version = htons(LDP_VERSION);
134	parms.keepalive_time = htons(nbr_get_keepalive(nbr->raddr));
135	parms.reserved = 0;
136	parms.pvlim = 0;
137	parms.max_pdu_len = 0;
138	parms.lsr_id = nbr->id.s_addr;
139	parms.lspace_id = 0;
140
141	return (ibuf_add(buf, &parms, SESS_PRMS_SIZE));
142}
143
144int
145tlv_decode_opt_init_prms(char *buf, u_int16_t len)
146{
147	struct tlv	tlv;
148	int		cons = 0;
149	u_int16_t	tlv_len;
150
151	 while (len >= sizeof(tlv)) {
152		bcopy(buf, &tlv, sizeof(tlv));
153		tlv_len = ntohs(tlv.length);
154		switch (ntohs(tlv.type)) {
155		case TLV_TYPE_ATMSESSIONPAR:
156			log_warnx("ATM session parameter present");
157			return (-1);
158		case TLV_TYPE_FRSESSION:
159			log_warnx("FR session parameter present");
160			return (-1);
161		default:
162			/* if unknown flag set, ignore TLV */
163			if (!(ntohs(tlv.type) & UNKNOWN_FLAG))
164				return (-1);
165			break;
166		}
167		buf += TLV_HDR_LEN + tlv_len;
168		len -= TLV_HDR_LEN + tlv_len;
169		cons += TLV_HDR_LEN + tlv_len;
170	}
171
172	return (cons);
173}
174