xref: /openbsd/usr.sbin/ldpd/init.c (revision cecf84d4)
1 /*	$OpenBSD: init.c,v 1.15 2014/10/25 03:23:49 lteo 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 
39 extern struct ldpd_conf        *leconf;
40 
41 int	gen_init_prms_tlv(struct ibuf *, struct nbr *, u_int16_t);
42 int	tlv_decode_opt_init_prms(char *, u_int16_t);
43 
44 void
45 send_init(struct nbr *nbr)
46 {
47 	struct ibuf		*buf;
48 	u_int16_t		 size;
49 
50 	log_debug("send_init: neighbor ID %s", inet_ntoa(nbr->id));
51 
52 	if ((buf = ibuf_open(LDP_MAX_LEN)) == NULL)
53 		fatal("send_init");
54 
55 	size = LDP_HDR_SIZE + sizeof(struct ldp_msg) + SESS_PRMS_SIZE;
56 
57 	gen_ldp_hdr(buf, size);
58 
59 	size -= LDP_HDR_SIZE;
60 
61 	gen_msg_tlv(buf, MSG_TYPE_INIT, size);
62 
63 	size -= sizeof(struct ldp_msg);
64 
65 	gen_init_prms_tlv(buf, nbr, size);
66 
67 	evbuf_enqueue(&nbr->tcp->wbuf, buf);
68 }
69 
70 int
71 recv_init(struct nbr *nbr, char *buf, u_int16_t len)
72 {
73 	struct ldp_msg		init;
74 	struct sess_prms_tlv	sess;
75 
76 	log_debug("recv_init: neighbor ID %s", inet_ntoa(nbr->id));
77 
78 	bcopy(buf, &init, sizeof(init));
79 
80 	buf += sizeof(struct ldp_msg);
81 	len -= sizeof(struct ldp_msg);
82 
83 	if (len < SESS_PRMS_SIZE) {
84 		session_shutdown(nbr, S_BAD_MSG_LEN, init.msgid, init.type);
85 		return (-1);
86 	}
87 	bcopy(buf, &sess, sizeof(sess));
88 
89 	if (ntohs(sess.length) != SESS_PRMS_SIZE - TLV_HDR_LEN ||
90 	    ntohs(sess.length) > len - TLV_HDR_LEN) {
91 		session_shutdown(nbr, S_BAD_TLV_LEN, init.msgid, init.type);
92 		return (-1);
93 	}
94 
95 	if (ntohs(sess.proto_version) != LDP_VERSION) {
96 		session_shutdown(nbr, S_BAD_PROTO_VER, init.msgid, init.type);
97 		return (-1);
98 	}
99 
100 	buf += SESS_PRMS_SIZE;
101 	len -= SESS_PRMS_SIZE;
102 
103 	/* just ignore all optional TLVs for now */
104 	if (tlv_decode_opt_init_prms(buf, len) == -1) {
105 		session_shutdown(nbr, S_BAD_TLV_VAL, init.msgid, init.type);
106 		return (-1);
107 	}
108 
109 	nbr->keepalive = min(leconf->keepalive, ntohs(sess.keepalive_time));
110 
111 	if (!nbr_pending_idtimer(nbr))
112 		nbr_fsm(nbr, NBR_EVT_INIT_RCVD);
113 
114 	return (ntohs(init.length));
115 }
116 
117 int
118 gen_init_prms_tlv(struct ibuf *buf, struct nbr *nbr, u_int16_t size)
119 {
120 	struct sess_prms_tlv	parms;
121 
122 	/* We want just the size of the value */
123 	size -= TLV_HDR_LEN;
124 
125 	bzero(&parms, sizeof(parms));
126 	parms.type = htons(TLV_TYPE_COMMONSESSION);
127 	parms.length = htons(size);
128 	parms.proto_version = htons(LDP_VERSION);
129 	parms.keepalive_time = htons(leconf->keepalive);
130 	parms.reserved = 0;
131 	parms.pvlim = 0;
132 	parms.max_pdu_len = 0;
133 	parms.lsr_id = nbr->id.s_addr;
134 	parms.lspace_id = 0;
135 
136 	return (ibuf_add(buf, &parms, SESS_PRMS_SIZE));
137 }
138 
139 int
140 tlv_decode_opt_init_prms(char *buf, u_int16_t len)
141 {
142 	struct tlv	tlv;
143 	int		cons = 0;
144 	u_int16_t	tlv_len;
145 
146 	 while (len >= sizeof(tlv)) {
147 		bcopy(buf, &tlv, sizeof(tlv));
148 		tlv_len = ntohs(tlv.length);
149 		switch (ntohs(tlv.type)) {
150 		case TLV_TYPE_ATMSESSIONPAR:
151 			log_warnx("ATM session parameter present");
152 			return (-1);
153 		case TLV_TYPE_FRSESSION:
154 			log_warnx("FR session parameter present");
155 			return (-1);
156 		default:
157 			/* if unknown flag set, ignore TLV */
158 			if (!(ntohs(tlv.type) & UNKNOWN_FLAG))
159 				return (-1);
160 			break;
161 		}
162 		buf += TLV_HDR_LEN + tlv_len;
163 		len -= TLV_HDR_LEN + tlv_len;
164 		cons += TLV_HDR_LEN + tlv_len;
165 	}
166 
167 	return (cons);
168 }
169