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