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