1 /*
2  * Copyright (c) 2019 Intel Corporation.
3  * Copyright (c) 2020 Endian Technologies AB
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #include <zephyr/logging/log.h>
9 LOG_MODULE_DECLARE(net_l2_ppp, CONFIG_NET_L2_PPP_LOG_LEVEL);
10 
11 #include <zephyr/net/net_core.h>
12 #include <zephyr/net/net_pkt.h>
13 
14 #include <zephyr/net/ppp.h>
15 #include <zephyr/net/dns_resolve.h>
16 
17 #include "net_private.h"
18 
19 #include "ppp_internal.h"
20 
ipcp_handle(struct ppp_context * ctx,struct net_if * iface,struct net_pkt * pkt)21 static enum net_verdict ipcp_handle(struct ppp_context *ctx,
22 				    struct net_if *iface,
23 				    struct net_pkt *pkt)
24 {
25 	return ppp_fsm_input(&ctx->ipcp.fsm, PPP_IPCP, pkt);
26 }
27 
28 /* Length is (6): code + id + IPv4 address length. RFC 1332 and also
29  * DNS in RFC 1877.
30  */
31 #define IP_ADDRESS_OPTION_LEN (1 + 1 + 4)
32 
ipcp_add_address(struct ppp_context * ctx,struct net_pkt * pkt,struct in_addr * addr)33 static int ipcp_add_address(struct ppp_context *ctx, struct net_pkt *pkt,
34 			    struct in_addr *addr)
35 {
36 	net_pkt_write_u8(pkt, 1 + 1 + sizeof(addr->s_addr));
37 	return net_pkt_write(pkt, &addr->s_addr, sizeof(addr->s_addr));
38 }
39 
ipcp_add_ip_address(struct ppp_context * ctx,struct net_pkt * pkt)40 static int ipcp_add_ip_address(struct ppp_context *ctx, struct net_pkt *pkt)
41 {
42 	return ipcp_add_address(ctx, pkt, &ctx->ipcp.my_options.address);
43 }
44 
ipcp_add_dns1(struct ppp_context * ctx,struct net_pkt * pkt)45 static int ipcp_add_dns1(struct ppp_context *ctx, struct net_pkt *pkt)
46 {
47 	return ipcp_add_address(ctx, pkt, &ctx->ipcp.my_options.dns1_address);
48 }
49 
ipcp_add_dns2(struct ppp_context * ctx,struct net_pkt * pkt)50 static int ipcp_add_dns2(struct ppp_context *ctx, struct net_pkt *pkt)
51 {
52 	return ipcp_add_address(ctx, pkt, &ctx->ipcp.my_options.dns2_address);
53 }
54 
ipcp_ack_check_address(struct net_pkt * pkt,size_t oplen,struct in_addr * addr)55 static int ipcp_ack_check_address(struct net_pkt *pkt, size_t oplen,
56 				  struct in_addr *addr)
57 {
58 	struct in_addr ack_addr;
59 	int ret;
60 
61 	if (oplen != sizeof(ack_addr)) {
62 		return -EINVAL;
63 	}
64 
65 	ret = net_pkt_read(pkt, &ack_addr, sizeof(ack_addr));
66 	if (ret) {
67 		return ret;
68 	}
69 
70 	if (memcmp(&ack_addr, addr, sizeof(ack_addr)) != 0) {
71 		return -EINVAL;
72 	}
73 
74 	return 0;
75 }
76 
ipcp_ack_ip_address(struct ppp_context * ctx,struct net_pkt * pkt,uint8_t oplen)77 static int ipcp_ack_ip_address(struct ppp_context *ctx, struct net_pkt *pkt,
78 			       uint8_t oplen)
79 {
80 	return ipcp_ack_check_address(pkt, oplen,
81 				      &ctx->ipcp.my_options.address);
82 }
83 
ipcp_ack_dns1(struct ppp_context * ctx,struct net_pkt * pkt,uint8_t oplen)84 static int ipcp_ack_dns1(struct ppp_context *ctx, struct net_pkt *pkt,
85 			 uint8_t oplen)
86 {
87 	return ipcp_ack_check_address(pkt, oplen,
88 				      &ctx->ipcp.my_options.dns1_address);
89 }
90 
ipcp_ack_dns2(struct ppp_context * ctx,struct net_pkt * pkt,uint8_t oplen)91 static int ipcp_ack_dns2(struct ppp_context *ctx, struct net_pkt *pkt,
92 			 uint8_t oplen)
93 {
94 	return ipcp_ack_check_address(pkt, oplen,
95 				      &ctx->ipcp.my_options.dns2_address);
96 }
97 
ipcp_nak_override_address(struct net_pkt * pkt,size_t oplen,struct in_addr * addr)98 static int ipcp_nak_override_address(struct net_pkt *pkt, size_t oplen,
99 				     struct in_addr *addr)
100 {
101 	if (oplen != sizeof(*addr)) {
102 		return -EINVAL;
103 	}
104 
105 	return net_pkt_read(pkt, addr, sizeof(*addr));
106 }
107 
ipcp_nak_ip_address(struct ppp_context * ctx,struct net_pkt * pkt,uint8_t oplen)108 static int ipcp_nak_ip_address(struct ppp_context *ctx, struct net_pkt *pkt,
109 			       uint8_t oplen)
110 {
111 	return ipcp_nak_override_address(pkt, oplen,
112 					 &ctx->ipcp.my_options.address);
113 }
114 
ipcp_nak_dns1(struct ppp_context * ctx,struct net_pkt * pkt,uint8_t oplen)115 static int ipcp_nak_dns1(struct ppp_context *ctx, struct net_pkt *pkt,
116 			 uint8_t oplen)
117 {
118 	return ipcp_nak_override_address(pkt, oplen,
119 					 &ctx->ipcp.my_options.dns1_address);
120 }
121 
ipcp_nak_dns2(struct ppp_context * ctx,struct net_pkt * pkt,uint8_t oplen)122 static int ipcp_nak_dns2(struct ppp_context *ctx, struct net_pkt *pkt,
123 			 uint8_t oplen)
124 {
125 	return ipcp_nak_override_address(pkt, oplen,
126 					 &ctx->ipcp.my_options.dns2_address);
127 }
128 
129 static const struct ppp_my_option_info ipcp_my_options[] = {
130 	PPP_MY_OPTION(IPCP_OPTION_IP_ADDRESS, ipcp_add_ip_address,
131 		      ipcp_ack_ip_address, ipcp_nak_ip_address),
132 	PPP_MY_OPTION(IPCP_OPTION_DNS1, ipcp_add_dns1,
133 		      ipcp_ack_dns1, ipcp_nak_dns1),
134 	PPP_MY_OPTION(IPCP_OPTION_DNS2, ipcp_add_dns2,
135 		      ipcp_ack_dns2, ipcp_nak_dns2),
136 };
137 
138 BUILD_ASSERT(ARRAY_SIZE(ipcp_my_options) == IPCP_NUM_MY_OPTIONS);
139 
ipcp_config_info_add(struct ppp_fsm * fsm)140 static struct net_pkt *ipcp_config_info_add(struct ppp_fsm *fsm)
141 {
142 	return ppp_my_options_add(fsm, 3 * IP_ADDRESS_OPTION_LEN);
143 }
144 
145 struct ipcp_peer_option_data {
146 	bool addr_present;
147 	struct in_addr addr;
148 };
149 
150 #if defined(CONFIG_NET_L2_PPP_OPTION_SERVE_DNS)
ipcp_dns_address_parse(struct ppp_fsm * fsm,struct net_pkt * pkt,void * user_data)151 static int ipcp_dns_address_parse(struct ppp_fsm *fsm, struct net_pkt *pkt,
152 				  void *user_data)
153 {
154 	struct ipcp_peer_option_data *data = user_data;
155 	int ret;
156 
157 	ret = net_pkt_read(pkt, &data->addr, sizeof(data->addr));
158 	if (ret < 0) {
159 		/* Should not happen, is the pkt corrupt? */
160 		return -EMSGSIZE;
161 	}
162 
163 	/* Request is zeros? Give our dns address in ConfNak */
164 	if (data->addr.s_addr == INADDR_ANY) {
165 		NET_DBG("[IPCP] zeroes rcvd as %s addr, sending NAK with our %s addr",
166 			"DNS", "DNS");
167 		return -EINVAL;
168 	}
169 
170 	data->addr_present = true;
171 
172 	return 0;
173 }
174 #endif
175 
ipcp_ip_address_parse(struct ppp_fsm * fsm,struct net_pkt * pkt,void * user_data)176 static int ipcp_ip_address_parse(struct ppp_fsm *fsm, struct net_pkt *pkt,
177 				 void *user_data)
178 {
179 	struct ipcp_peer_option_data *data = user_data;
180 	int ret;
181 
182 	ret = net_pkt_read(pkt, &data->addr, sizeof(data->addr));
183 	if (ret < 0) {
184 		/* Should not happen, is the pkt corrupt? */
185 		return -EMSGSIZE;
186 	}
187 
188 #if defined(CONFIG_NET_L2_PPP_OPTION_SERVE_IP)
189 	/* Request is zeros? Give our IP address in ConfNak */
190 	if (data->addr.s_addr == INADDR_ANY) {
191 		NET_DBG("[IPCP] zeroes rcvd as %s addr, sending NAK with our %s addr",
192 			"IP", "IP");
193 		return -EINVAL;
194 	}
195 #endif
196 	if (CONFIG_NET_L2_PPP_LOG_LEVEL >= LOG_LEVEL_DBG) {
197 		char dst[INET_ADDRSTRLEN];
198 		char *addr_str;
199 
200 		addr_str = net_addr_ntop(AF_INET, &data->addr, dst,
201 					 sizeof(dst));
202 
203 		NET_DBG("[IPCP] Received peer address %s",
204 			addr_str);
205 	}
206 
207 	data->addr_present = true;
208 
209 	return 0;
210 }
211 
212 #if defined(CONFIG_NET_L2_PPP_OPTION_SERVE_IP)
ipcp_server_nak_ip_address(struct ppp_fsm * fsm,struct net_pkt * ret_pkt,void * user_data)213 static int ipcp_server_nak_ip_address(struct ppp_fsm *fsm,
214 				      struct net_pkt *ret_pkt, void *user_data)
215 {
216 	struct ppp_context *ctx =
217 		CONTAINER_OF(fsm, struct ppp_context, ipcp.fsm);
218 
219 	(void)net_pkt_write_u8(ret_pkt, IPCP_OPTION_IP_ADDRESS);
220 	ipcp_add_ip_address(ctx, ret_pkt);
221 
222 	return 0;
223 }
224 #endif
225 
226 #if defined(CONFIG_NET_L2_PPP_OPTION_SERVE_DNS)
ipcp_server_nak_dns1_address(struct ppp_fsm * fsm,struct net_pkt * ret_pkt,void * user_data)227 static int ipcp_server_nak_dns1_address(struct ppp_fsm *fsm,
228 					struct net_pkt *ret_pkt,
229 					void *user_data)
230 {
231 	struct ppp_context *ctx =
232 		CONTAINER_OF(fsm, struct ppp_context, ipcp.fsm);
233 
234 	(void)net_pkt_write_u8(ret_pkt, IPCP_OPTION_DNS1);
235 	ipcp_add_dns1(ctx, ret_pkt);
236 
237 	return 0;
238 }
239 
ipcp_server_nak_dns2_address(struct ppp_fsm * fsm,struct net_pkt * ret_pkt,void * user_data)240 static int ipcp_server_nak_dns2_address(struct ppp_fsm *fsm,
241 					struct net_pkt *ret_pkt,
242 					void *user_data)
243 {
244 	struct ppp_context *ctx =
245 		CONTAINER_OF(fsm, struct ppp_context, ipcp.fsm);
246 
247 	(void)net_pkt_write_u8(ret_pkt, IPCP_OPTION_DNS2);
248 	ipcp_add_dns2(ctx, ret_pkt);
249 
250 	return 0;
251 }
252 #endif
253 
254 static const struct ppp_peer_option_info ipcp_peer_options[] = {
255 #if defined(CONFIG_NET_L2_PPP_OPTION_SERVE_IP)
256 	PPP_PEER_OPTION(IPCP_OPTION_IP_ADDRESS, ipcp_ip_address_parse,
257 			ipcp_server_nak_ip_address),
258 #else
259 	PPP_PEER_OPTION(IPCP_OPTION_IP_ADDRESS, ipcp_ip_address_parse, NULL),
260 #endif
261 #if defined(CONFIG_NET_L2_PPP_OPTION_SERVE_DNS)
262 	PPP_PEER_OPTION(IPCP_OPTION_DNS1, ipcp_dns_address_parse,
263 			ipcp_server_nak_dns1_address),
264 	PPP_PEER_OPTION(IPCP_OPTION_DNS2, ipcp_dns_address_parse,
265 			ipcp_server_nak_dns2_address),
266 #endif
267 };
268 
ipcp_config_info_req(struct ppp_fsm * fsm,struct net_pkt * pkt,uint16_t length,struct net_pkt * ret_pkt)269 static int ipcp_config_info_req(struct ppp_fsm *fsm,
270 				struct net_pkt *pkt,
271 				uint16_t length,
272 				struct net_pkt *ret_pkt)
273 {
274 	struct ppp_context *ctx =
275 		CONTAINER_OF(fsm, struct ppp_context, ipcp.fsm);
276 	struct ipcp_peer_option_data data = {
277 		.addr_present = false,
278 	};
279 	int ret;
280 
281 	ret = ppp_config_info_req(fsm, pkt, length, ret_pkt, PPP_IPCP,
282 				  ipcp_peer_options,
283 				  ARRAY_SIZE(ipcp_peer_options),
284 				  &data);
285 	if (ret != PPP_CONFIGURE_ACK) {
286 		/* There are some issues with configuration still */
287 		return ret;
288 	}
289 
290 	if (!data.addr_present) {
291 		NET_DBG("[%s/%p] No %saddress provided",
292 			fsm->name, fsm, "peer ");
293 		return PPP_CONFIGURE_ACK;
294 	}
295 
296 	/* The address is the remote address, we then need
297 	 * to figure out what our address should be.
298 	 *
299 	 * TODO:
300 	 *   - check that the IP address can be accepted
301 	 */
302 
303 	memcpy(&ctx->ipcp.peer_options.address, &data.addr, sizeof(data.addr));
304 
305 	return PPP_CONFIGURE_ACK;
306 }
307 
ipcp_set_dns_servers(struct ppp_fsm * fsm)308 static void ipcp_set_dns_servers(struct ppp_fsm *fsm)
309 {
310 #if defined(CONFIG_NET_L2_PPP_OPTION_DNS_USE)
311 	struct ppp_context *ctx = CONTAINER_OF(fsm, struct ppp_context,
312 					       ipcp.fsm);
313 
314 	struct dns_resolve_context *dnsctx;
315 	struct sockaddr_in dns1 = {
316 		.sin_family = AF_INET,
317 		.sin_port = htons(53),
318 		.sin_addr = ctx->ipcp.my_options.dns1_address
319 	};
320 	struct sockaddr_in dns2 = {
321 		.sin_family = AF_INET,
322 		.sin_port = htons(53),
323 		.sin_addr = ctx->ipcp.my_options.dns2_address
324 	};
325 	const struct sockaddr *dns_servers[] = {
326 		(struct sockaddr *) &dns1,
327 		(struct sockaddr *) &dns2,
328 		NULL
329 	};
330 	int ret;
331 
332 	if (!dns1.sin_addr.s_addr) {
333 		return;
334 	}
335 
336 	if (!dns2.sin_addr.s_addr) {
337 		dns_servers[1] = NULL;
338 	}
339 
340 	dnsctx = dns_resolve_get_default();
341 	ret = dns_resolve_reconfigure(dnsctx, NULL, dns_servers);
342 	if (ret < 0) {
343 		NET_ERR("Could not set DNS servers");
344 		return;
345 	}
346 #endif
347 }
348 
ipcp_config_info_nack(struct ppp_fsm * fsm,struct net_pkt * pkt,uint16_t length,bool rejected)349 static int ipcp_config_info_nack(struct ppp_fsm *fsm,
350 				 struct net_pkt *pkt,
351 				 uint16_t length,
352 				 bool rejected)
353 {
354 	struct ppp_context *ctx = CONTAINER_OF(fsm, struct ppp_context,
355 					       ipcp.fsm);
356 	int ret;
357 
358 	ret = ppp_my_options_parse_conf_nak(fsm, pkt, length);
359 	if (ret) {
360 		return ret;
361 	}
362 
363 	if (!ctx->ipcp.my_options.address.s_addr) {
364 		return -EINVAL;
365 	}
366 
367 	ipcp_set_dns_servers(fsm);
368 
369 	return 0;
370 }
371 
ipcp_lower_down(struct ppp_context * ctx)372 static void ipcp_lower_down(struct ppp_context *ctx)
373 {
374 	ppp_fsm_lower_down(&ctx->ipcp.fsm);
375 }
376 
ipcp_lower_up(struct ppp_context * ctx)377 static void ipcp_lower_up(struct ppp_context *ctx)
378 {
379 	ppp_fsm_lower_up(&ctx->ipcp.fsm);
380 }
381 
ipcp_open(struct ppp_context * ctx)382 static void ipcp_open(struct ppp_context *ctx)
383 {
384 	ppp_fsm_open(&ctx->ipcp.fsm);
385 }
386 
ipcp_close(struct ppp_context * ctx,const uint8_t * reason)387 static void ipcp_close(struct ppp_context *ctx, const uint8_t *reason)
388 {
389 	ppp_fsm_close(&ctx->ipcp.fsm, reason);
390 }
391 
ipcp_up(struct ppp_fsm * fsm)392 static void ipcp_up(struct ppp_fsm *fsm)
393 {
394 	struct ppp_context *ctx = CONTAINER_OF(fsm, struct ppp_context,
395 					       ipcp.fsm);
396 	struct net_if_addr *addr;
397 	char dst[INET_ADDRSTRLEN];
398 	char *addr_str;
399 
400 	if (ctx->is_ipcp_up) {
401 		return;
402 	}
403 
404 	addr_str = net_addr_ntop(AF_INET, &ctx->ipcp.my_options.address,
405 				 dst, sizeof(dst));
406 
407 	addr = net_if_ipv4_addr_add(ctx->iface,
408 				    &ctx->ipcp.my_options.address,
409 				    NET_ADDR_MANUAL,
410 				    0);
411 	if (addr == NULL) {
412 		NET_ERR("Could not set IP address %s", addr_str);
413 		return;
414 	}
415 
416 	NET_DBG("PPP up with address %s", addr_str);
417 	ppp_network_up(ctx, PPP_IP);
418 
419 	ctx->is_ipcp_up = true;
420 
421 	NET_DBG("[%s/%p] Current state %s (%d)", fsm->name, fsm,
422 		ppp_state_str(fsm->state), fsm->state);
423 }
424 
ipcp_down(struct ppp_fsm * fsm)425 static void ipcp_down(struct ppp_fsm *fsm)
426 {
427 	struct ppp_context *ctx = CONTAINER_OF(fsm, struct ppp_context,
428 					       ipcp.fsm);
429 
430 	/* Ensure address is always removed if it exists */
431 	if (ctx->ipcp.my_options.address.s_addr) {
432 		(void)net_if_ipv4_addr_rm(
433 			ctx->iface, &ctx->ipcp.my_options.address);
434 	}
435 	memset(&ctx->ipcp.my_options.address, 0,
436 	       sizeof(ctx->ipcp.my_options.address));
437 	memset(&ctx->ipcp.my_options.dns1_address, 0,
438 	       sizeof(ctx->ipcp.my_options.dns1_address));
439 	memset(&ctx->ipcp.my_options.dns2_address, 0,
440 	       sizeof(ctx->ipcp.my_options.dns2_address));
441 
442 	if (!ctx->is_ipcp_up) {
443 		return;
444 	}
445 
446 	ctx->is_ipcp_up = false;
447 
448 	ppp_network_down(ctx, PPP_IP);
449 }
450 
ipcp_finished(struct ppp_fsm * fsm)451 static void ipcp_finished(struct ppp_fsm *fsm)
452 {
453 	struct ppp_context *ctx = CONTAINER_OF(fsm, struct ppp_context,
454 					       ipcp.fsm);
455 
456 	if (!ctx->is_ipcp_open) {
457 		return;
458 	}
459 
460 	ctx->is_ipcp_open = false;
461 
462 	ppp_network_done(ctx, PPP_IP);
463 }
464 
ipcp_proto_reject(struct ppp_fsm * fsm)465 static void ipcp_proto_reject(struct ppp_fsm *fsm)
466 {
467 	ppp_fsm_lower_down(fsm);
468 }
469 
ipcp_init(struct ppp_context * ctx)470 static void ipcp_init(struct ppp_context *ctx)
471 {
472 	NET_DBG("proto %s (0x%04x) fsm %p", ppp_proto2str(PPP_IPCP), PPP_IPCP,
473 		&ctx->ipcp.fsm);
474 
475 	memset(&ctx->ipcp.fsm, 0, sizeof(ctx->ipcp.fsm));
476 
477 	ppp_fsm_init(&ctx->ipcp.fsm, PPP_IPCP);
478 
479 	ppp_fsm_name_set(&ctx->ipcp.fsm, ppp_proto2str(PPP_IPCP));
480 
481 	ctx->ipcp.fsm.my_options.info = ipcp_my_options;
482 	ctx->ipcp.fsm.my_options.data = ctx->ipcp.my_options_data;
483 	ctx->ipcp.fsm.my_options.count = ARRAY_SIZE(ipcp_my_options);
484 
485 	ctx->ipcp.fsm.cb.up = ipcp_up;
486 	ctx->ipcp.fsm.cb.down = ipcp_down;
487 	ctx->ipcp.fsm.cb.finished = ipcp_finished;
488 	ctx->ipcp.fsm.cb.proto_reject = ipcp_proto_reject;
489 	ctx->ipcp.fsm.cb.config_info_add = ipcp_config_info_add;
490 	ctx->ipcp.fsm.cb.config_info_req = ipcp_config_info_req;
491 	ctx->ipcp.fsm.cb.config_info_nack = ipcp_config_info_nack;
492 	ctx->ipcp.fsm.cb.config_info_rej = ppp_my_options_parse_conf_rej;
493 }
494 
495 PPP_PROTOCOL_REGISTER(IPCP, PPP_IPCP,
496 		      ipcp_init, ipcp_handle,
497 		      ipcp_lower_up, ipcp_lower_down,
498 		      ipcp_open, ipcp_close);
499