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