]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/sd-pppoe.c
shared: add random-util.[ch]
[thirdparty/systemd.git] / src / libsystemd-network / sd-pppoe.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright (C) 2014 Tom Gundersen
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 /* See RFC 2516 */
23
24 #include <sys/ioctl.h>
25 #include <linux/ppp_defs.h>
26 #include <linux/ppp-ioctl.h>
27 #include <net/if.h>
28 #include <netinet/in.h>
29 #include <linux/if_pppox.h>
30
31 #include "sd-pppoe.h"
32
33 #include "event-util.h"
34
35 #include "util.h"
36 #include "random-util.h"
37 #include "socket-util.h"
38 #include "async.h"
39 #include "refcnt.h"
40 #include "utf8.h"
41
42 #define PPPOE_MAX_PACKET_SIZE 1484
43 #define PPPOE_MAX_PADR_RESEND 16
44
45 /* TODO: move this to socket-util.h without getting into
46 * a mess with the includes */
47 union sockaddr_union_pppox {
48 struct sockaddr sa;
49 struct sockaddr_pppox pppox;
50 };
51
52 typedef enum PPPoEState {
53 PPPOE_STATE_INITIALIZING,
54 PPPOE_STATE_REQUESTING,
55 PPPOE_STATE_RUNNING,
56 PPPOE_STATE_STOPPED,
57 _PPPOE_STATE_MAX,
58 _PPPOE_STATE_INVALID = -1,
59 } PPPoEState;
60
61 typedef struct PPPoETags {
62 char *service_name;
63 char *ac_name;
64 uint8_t *host_uniq;
65 size_t host_uniq_len;
66 uint8_t *cookie;
67 size_t cookie_len;
68 } PPPoETags;
69
70 struct sd_pppoe {
71 RefCount n_ref;
72
73 PPPoEState state;
74 uint64_t host_uniq;
75
76 int ifindex;
77 char *ifname;
78
79 sd_event *event;
80 int event_priority;
81 int fd;
82 sd_event_source *io;
83 sd_event_source *timeout;
84 int padr_resend_count;
85
86 char *service_name;
87 struct ether_addr peer_mac;
88 be16_t session_id;
89
90 int pppoe_fd;
91 int channel;
92
93 sd_pppoe_cb_t cb;
94 void *userdata;
95
96 PPPoETags tags;
97 };
98
99 #define PPPOE_PACKET_LENGTH(header) \
100 be16toh((header)->length)
101
102 #define PPPOE_PACKET_TAIL(packet) \
103 (struct pppoe_tag*)((uint8_t*)(packet) + sizeof(struct pppoe_hdr) + PPPOE_PACKET_LENGTH(packet))
104
105 #define PPPOE_TAG_LENGTH(tag) \
106 be16toh((tag)->tag_len)
107
108 #define PPPOE_TAG_TYPE(tag) \
109 (tag)->tag_type
110
111 #define PPPOE_TAG_NEXT(tag) \
112 (struct pppoe_tag *)((uint8_t *)(tag) + sizeof(struct pppoe_tag) + PPPOE_TAG_LENGTH(tag))
113
114 #define PPPOE_TAGS_FOREACH(tag, header) \
115 for (tag = (header)->tag; \
116 ((uint8_t *)(tag) + sizeof(struct pppoe_tag) < (uint8_t*)PPPOE_PACKET_TAIL(header)) && \
117 (PPPOE_TAG_NEXT(tag) <= PPPOE_PACKET_TAIL(header)) && \
118 (tag >= (header)->tag) && \
119 (PPPOE_TAG_TYPE(tag) != PTT_EOL); \
120 tag = PPPOE_TAG_NEXT(tag))
121
122 static void pppoe_tags_clear(PPPoETags *tags) {
123 free(tags->service_name);
124 free(tags->ac_name);
125 free(tags->host_uniq);
126 free(tags->cookie);
127
128 zero(*tags);
129 }
130
131 int sd_pppoe_set_ifindex(sd_pppoe *ppp, int ifindex) {
132 assert_return(ppp, -EINVAL);
133 assert_return(ifindex > 0, -EINVAL);
134
135 ppp->ifindex = ifindex;
136
137 return 0;
138 }
139
140 int sd_pppoe_set_ifname(sd_pppoe *ppp, const char *ifname) {
141 char *name;
142
143 assert_return(ppp, -EINVAL);
144 assert_return(ifname, -EINVAL);
145
146 if (strlen(ifname) > IFNAMSIZ)
147 return -EINVAL;
148
149 name = strdup(ifname);
150 if (!name)
151 return -ENOMEM;
152
153 free(ppp->ifname);
154 ppp->ifname = name;
155
156 return 0;
157 }
158
159 int sd_pppoe_set_service_name(sd_pppoe *ppp, const char *service_name) {
160 _cleanup_free_ char *name = NULL;
161
162 assert_return(ppp, -EINVAL);
163
164 if (service_name) {
165 name = strdup(service_name);
166 if (!name)
167 return -ENOMEM;
168 }
169
170 free(ppp->service_name);
171 ppp->service_name = name;
172 name = NULL;
173
174 return 0;
175 }
176
177 int sd_pppoe_attach_event(sd_pppoe *ppp, sd_event *event, int priority) {
178 int r;
179
180 assert_return(ppp, -EINVAL);
181 assert_return(!ppp->event, -EBUSY);
182
183 if (event)
184 ppp->event = sd_event_ref(event);
185 else {
186 r = sd_event_default(&ppp->event);
187 if (r < 0)
188 return r;
189 }
190
191 ppp->event_priority = priority;
192
193 return 0;
194 }
195
196 int sd_pppoe_detach_event(sd_pppoe *ppp) {
197 assert_return(ppp, -EINVAL);
198
199 ppp->event = sd_event_unref(ppp->event);
200
201 return 0;
202 }
203
204 sd_pppoe *sd_pppoe_ref(sd_pppoe *ppp) {
205 if (ppp)
206 assert_se(REFCNT_INC(ppp->n_ref) >= 2);
207
208 return ppp;
209 }
210
211 sd_pppoe *sd_pppoe_unref(sd_pppoe *ppp) {
212 if (ppp && REFCNT_DEC(ppp->n_ref) <= 0) {
213 pppoe_tags_clear(&ppp->tags);
214 free(ppp->ifname);
215 free(ppp->service_name);
216 sd_pppoe_stop(ppp);
217 sd_pppoe_detach_event(ppp);
218
219 free(ppp);
220 }
221
222 return NULL;
223 }
224
225 int sd_pppoe_new (sd_pppoe **ret) {
226 sd_pppoe *ppp;
227
228 assert_return(ret, -EINVAL);
229
230 ppp = new0(sd_pppoe, 1);
231 if (!ppp)
232 return -ENOMEM;
233
234 ppp->n_ref = REFCNT_INIT;
235 ppp->state = _PPPOE_STATE_INVALID;
236 ppp->ifindex = -1;
237 ppp->fd = -1;
238 ppp->pppoe_fd = -1;
239 ppp->padr_resend_count = PPPOE_MAX_PADR_RESEND;
240
241 *ret = ppp;
242
243 return 0;
244 }
245
246 int sd_pppoe_get_channel(sd_pppoe *ppp, int *channel) {
247 assert_return(ppp, -EINVAL);
248 assert_return(channel, -EINVAL);
249 assert_return(ppp->pppoe_fd != -1, -EUNATCH);
250 assert_return(ppp->state == PPPOE_STATE_RUNNING, -EUNATCH);
251
252 *channel = ppp->channel;
253
254 return 0;
255 }
256
257 int sd_pppoe_set_callback(sd_pppoe *ppp, sd_pppoe_cb_t cb, void *userdata) {
258 assert_return(ppp, -EINVAL);
259
260 ppp->cb = cb;
261 ppp->userdata = userdata;
262
263 return 0;
264 }
265
266 static void pppoe_tag_append(struct pppoe_hdr *packet, size_t packet_size, be16_t tag_type, const void *tag_data, uint16_t tag_len) {
267 struct pppoe_tag *tag;
268
269 assert(packet);
270 assert(sizeof(struct pppoe_hdr) + PPPOE_PACKET_LENGTH(packet) + sizeof(struct pppoe_tag) + tag_len <= packet_size);
271 assert(!(!tag_data ^ !tag_len));
272
273 tag = PPPOE_PACKET_TAIL(packet);
274
275 tag->tag_len = htobe16(tag_len);
276 tag->tag_type = tag_type;
277 if (tag_data)
278 memcpy(tag->tag_data, tag_data, tag_len);
279
280 packet->length = htobe16(PPPOE_PACKET_LENGTH(packet) + sizeof(struct pppoe_tag) + tag_len);
281 }
282
283 static int pppoe_send(sd_pppoe *ppp, uint8_t code) {
284 union sockaddr_union link = {
285 .ll = {
286 .sll_family = AF_PACKET,
287 .sll_protocol = htons(ETH_P_PPP_DISC),
288 .sll_halen = ETH_ALEN,
289 },
290 };
291 _cleanup_free_ struct pppoe_hdr *packet = NULL;
292 int r;
293
294 assert(ppp);
295 assert(ppp->fd != -1);
296 assert(IN_SET(code, PADI_CODE, PADR_CODE, PADT_CODE));
297
298 link.ll.sll_ifindex = ppp->ifindex;
299 if (code == PADI_CODE)
300 memset(&link.ll.sll_addr, 0xff, ETH_ALEN);
301 else
302 memcpy(&link.ll.sll_addr, &ppp->peer_mac, ETH_ALEN);
303
304 packet = malloc0(PPPOE_MAX_PACKET_SIZE);
305 if (!packet)
306 return -ENOMEM;
307
308 packet->ver = 0x1;
309 packet->type = 0x1;
310 packet->code = code;
311 if (code == PADT_CODE)
312 packet->sid = ppp->session_id;
313
314 /* Service-Name */
315 pppoe_tag_append(packet, PPPOE_MAX_PACKET_SIZE, PTT_SRV_NAME,
316 ppp->service_name, ppp->service_name ? strlen(ppp->service_name) : 0);
317
318 /* AC-Cookie */
319 if (code == PADR_CODE && ppp->tags.cookie)
320 pppoe_tag_append(packet, PPPOE_MAX_PACKET_SIZE, PTT_AC_COOKIE,
321 ppp->tags.cookie, ppp->tags.cookie_len);
322
323 /* Host-Uniq */
324 if (code != PADT_CODE) {
325 ppp->host_uniq = random_u64();
326
327 pppoe_tag_append(packet, PPPOE_MAX_PACKET_SIZE, PTT_HOST_UNIQ,
328 &ppp->host_uniq, sizeof(ppp->host_uniq));
329 }
330
331 r = sendto(ppp->fd, packet, sizeof(struct pppoe_hdr) + PPPOE_PACKET_LENGTH(packet),
332 0, &link.sa, sizeof(link.ll));
333 if (r < 0)
334 return -errno;
335
336 return 0;
337 }
338
339 static int pppoe_timeout(sd_event_source *s, uint64_t usec, void *userdata);
340
341 static int pppoe_arm_timeout(sd_pppoe *ppp) {
342 _cleanup_event_source_unref_ sd_event_source *timeout = NULL;
343 usec_t next_timeout = 0;
344 int r;
345
346 assert(ppp);
347
348 r = sd_event_now(ppp->event, clock_boottime_or_monotonic(), &next_timeout);
349 if (r == -ENODATA)
350 next_timeout = now(clock_boottime_or_monotonic());
351 else if (r < 0)
352 return r;
353
354 next_timeout += 500 * USEC_PER_MSEC;
355
356 r = sd_event_add_time(ppp->event, &timeout, clock_boottime_or_monotonic(), next_timeout,
357 10 * USEC_PER_MSEC, pppoe_timeout, ppp);
358 if (r < 0)
359 return r;
360
361 r = sd_event_source_set_priority(timeout, ppp->event_priority);
362 if (r < 0)
363 return r;
364
365 sd_event_source_unref(ppp->timeout);
366 ppp->timeout = timeout;
367 timeout = NULL;
368
369 return 0;
370 }
371
372 static int pppoe_send_initiation(sd_pppoe *ppp) {
373 int r;
374
375 r = pppoe_send(ppp, PADI_CODE);
376 if (r < 0)
377 return r;
378
379 log_debug("PPPoE: sent DISCOVER (Service-Name: %s)",
380 ppp->service_name ? : "");
381
382 pppoe_arm_timeout(ppp);
383
384 return r;
385 }
386
387 static int pppoe_send_request(sd_pppoe *ppp) {
388 int r;
389
390 r = pppoe_send(ppp, PADR_CODE);
391 if (r < 0)
392 return r;
393
394 log_debug("PPPoE: sent REQUEST");
395
396 ppp->padr_resend_count --;
397
398 pppoe_arm_timeout(ppp);
399
400 return 0;
401 }
402
403 static int pppoe_send_terminate(sd_pppoe *ppp) {
404 int r;
405
406 r = pppoe_send(ppp, PADT_CODE);
407 if (r < 0)
408 return r;
409
410 log_debug("PPPoE: sent TERMINATE");
411
412 return 0;
413 }
414
415 static int pppoe_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
416 sd_pppoe *ppp = userdata;
417 int r;
418
419 assert(ppp);
420
421 switch (ppp->state) {
422 case PPPOE_STATE_INITIALIZING:
423 r = pppoe_send_initiation(ppp);
424 if (r < 0)
425 log_warning_errno(r, "PPPoE: sending PADI failed: %m");
426
427 break;
428 case PPPOE_STATE_REQUESTING:
429 if (ppp->padr_resend_count <= 0) {
430 log_debug("PPPoE: PADR timed out, restarting PADI");
431
432 r = pppoe_send_initiation(ppp);
433 if (r < 0)
434 log_warning_errno(r, "PPPoE: sending PADI failed: %m");
435
436 ppp->padr_resend_count = PPPOE_MAX_PADR_RESEND;
437 ppp->state = PPPOE_STATE_INITIALIZING;
438 } else {
439 r = pppoe_send_request(ppp);
440 if (r < 0)
441 log_warning_errno(r, "PPPoE: sending PADR failed: %m");
442 }
443
444 break;
445 default:
446 assert_not_reached("timeout in invalid state");
447 }
448
449 return 0;
450 }
451
452 static int pppoe_tag_parse_binary(struct pppoe_tag *tag, uint8_t **ret, size_t *length) {
453 uint8_t *data;
454
455 assert(ret);
456 assert(length);
457
458 data = memdup(tag->tag_data, PPPOE_TAG_LENGTH(tag));
459 if (!data)
460 return -ENOMEM;
461
462 free(*ret);
463 *ret = data;
464 *length = PPPOE_TAG_LENGTH(tag);
465
466 return 0;
467 }
468
469 static int pppoe_tag_parse_string(struct pppoe_tag *tag, char **ret) {
470 char *string;
471
472 assert(ret);
473
474 string = strndup(tag->tag_data, PPPOE_TAG_LENGTH(tag));
475 if (!string)
476 return -ENOMEM;
477
478 free(*ret);
479 *ret = string;
480
481 return 0;
482 }
483
484 static int pppoe_payload_parse(PPPoETags *tags, struct pppoe_hdr *header) {
485 struct pppoe_tag *tag;
486 int r;
487
488 assert(tags);
489
490 pppoe_tags_clear(tags);
491
492 PPPOE_TAGS_FOREACH(tag, header) {
493 switch (PPPOE_TAG_TYPE(tag)) {
494 case PTT_SRV_NAME:
495 r = pppoe_tag_parse_string(tag, &tags->service_name);
496 if (r < 0)
497 return r;
498
499 break;
500 case PTT_AC_NAME:
501 r = pppoe_tag_parse_string(tag, &tags->ac_name);
502 if (r < 0)
503 return r;
504
505 break;
506 case PTT_HOST_UNIQ:
507 r = pppoe_tag_parse_binary(tag, &tags->host_uniq, &tags->host_uniq_len);
508 if (r < 0)
509 return r;
510
511 break;
512 case PTT_AC_COOKIE:
513 r = pppoe_tag_parse_binary(tag, &tags->cookie, &tags->cookie_len);
514 if (r < 0)
515 return r;
516
517 break;
518 case PTT_SRV_ERR:
519 case PTT_SYS_ERR:
520 case PTT_GEN_ERR:
521 {
522 _cleanup_free_ char *error = NULL;
523
524 /* TODO: do something more sensible with the error messages */
525 r = pppoe_tag_parse_string(tag, &error);
526 if (r < 0)
527 return r;
528
529 if (strlen(error) > 0 && utf8_is_valid(error))
530 log_debug("PPPoE: error - '%s'", error);
531 else
532 log_debug("PPPoE: error");
533
534 break;
535 }
536 default:
537 log_debug("PPPoE: ignoring unknown PPPoE tag type: 0x%.2x", PPPOE_TAG_TYPE(tag));
538 }
539 }
540
541 return 0;
542 }
543
544 static int pppoe_open_pppoe_socket(sd_pppoe *ppp) {
545 int s;
546
547 assert(ppp);
548 assert(ppp->pppoe_fd == -1);
549
550 s = socket(AF_PPPOX, SOCK_STREAM, 0);
551 if (s < 0)
552 return -errno;
553
554 ppp->pppoe_fd = s;
555
556 return 0;
557 }
558
559 static int pppoe_connect_pppoe_socket(sd_pppoe *ppp) {
560 union sockaddr_union_pppox link = {
561 .pppox = {
562 .sa_family = AF_PPPOX,
563 .sa_protocol = PX_PROTO_OE,
564 },
565 };
566 int r, channel;
567
568 assert(ppp);
569 assert(ppp->pppoe_fd != -1);
570 assert(ppp->session_id);
571 assert(ppp->ifname);
572
573 link.pppox.sa_addr.pppoe.sid = ppp->session_id;
574 memcpy(link.pppox.sa_addr.pppoe.dev, ppp->ifname, strlen(ppp->ifname));
575 memcpy(link.pppox.sa_addr.pppoe.remote, &ppp->peer_mac, ETH_ALEN);
576
577 r = connect(ppp->pppoe_fd, &link.sa, sizeof(link.pppox));
578 if (r < 0)
579 return r;
580
581 r = ioctl(ppp->pppoe_fd, PPPIOCGCHAN, &channel);
582 if (r < 0)
583 return -errno;
584
585 ppp->channel = channel;
586
587 return 0;
588 }
589
590 static int pppoe_handle_message(sd_pppoe *ppp, struct pppoe_hdr *packet, struct ether_addr *mac) {
591 int r;
592
593 assert(packet);
594
595 if (packet->ver != 0x1 || packet->type != 0x1)
596 return 0;
597
598 r = pppoe_payload_parse(&ppp->tags, packet);
599 if (r < 0)
600 return 0;
601
602 switch (ppp->state) {
603 case PPPOE_STATE_INITIALIZING:
604 if (packet->code != PADO_CODE)
605 return 0;
606
607 if (ppp->tags.host_uniq_len != sizeof(ppp->host_uniq) ||
608 memcmp(ppp->tags.host_uniq, &ppp->host_uniq, sizeof(ppp->host_uniq)) != 0)
609 return 0;
610
611 log_debug("PPPoE: got OFFER (Peer: "
612 "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx; "
613 "Service-Name: '%s'; AC-Name: '%s')",
614 mac->ether_addr_octet[0],
615 mac->ether_addr_octet[1],
616 mac->ether_addr_octet[2],
617 mac->ether_addr_octet[3],
618 mac->ether_addr_octet[4],
619 mac->ether_addr_octet[5],
620 ppp->tags.service_name ? : "",
621 ppp->tags.ac_name ? : "");
622
623 memcpy(&ppp->peer_mac, mac, ETH_ALEN);
624
625 r = pppoe_open_pppoe_socket(ppp);
626 if (r < 0) {
627 log_warning("PPPoE: could not open socket");
628 return r;
629 }
630
631 r = pppoe_send_request(ppp);
632 if (r < 0)
633 return 0;
634
635 ppp->state = PPPOE_STATE_REQUESTING;
636
637 break;
638 case PPPOE_STATE_REQUESTING:
639 if (packet->code != PADS_CODE)
640 return 0;
641
642 if (ppp->tags.host_uniq_len != sizeof(ppp->host_uniq) ||
643 memcmp(ppp->tags.host_uniq, &ppp->host_uniq,
644 sizeof(ppp->host_uniq)) != 0)
645 return 0;
646
647 if (memcmp(&ppp->peer_mac, mac, ETH_ALEN) != 0)
648 return 0;
649
650 ppp->session_id = packet->sid;
651
652 log_debug("PPPoE: got CONFIRMATION (Session ID: %"PRIu16")",
653 be16toh(ppp->session_id));
654
655 r = pppoe_connect_pppoe_socket(ppp);
656 if (r < 0) {
657 log_warning("PPPoE: could not connect socket");
658 return r;
659 }
660
661 ppp->state = PPPOE_STATE_RUNNING;
662
663 ppp->timeout = sd_event_source_unref(ppp->timeout);
664 assert(ppp->cb);
665 ppp->cb(ppp, PPPOE_EVENT_RUNNING, ppp->userdata);
666
667 break;
668 case PPPOE_STATE_RUNNING:
669 if (packet->code != PADT_CODE)
670 return 0;
671
672 if (memcmp(&ppp->peer_mac, mac, ETH_ALEN) != 0)
673 return 0;
674
675 if (ppp->session_id != packet->sid)
676 return 0;
677
678 log_debug("PPPoE: got TERMINATE");
679
680 ppp->state = PPPOE_STATE_STOPPED;
681
682 assert(ppp->cb);
683 ppp->cb(ppp, PPPOE_EVENT_STOPPED, ppp->userdata);
684
685 break;
686 case PPPOE_STATE_STOPPED:
687 break;
688 default:
689 assert_not_reached("PPPoE: invalid state when receiving message");
690 }
691
692 return 0;
693 }
694
695 static int pppoe_receive_message(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
696 sd_pppoe *ppp = userdata;
697 _cleanup_free_ struct pppoe_hdr *packet = NULL;
698 union sockaddr_union link = {};
699 socklen_t addrlen = sizeof(link);
700 int buflen = 0, len, r;
701
702 assert(ppp);
703 assert(fd != -1);
704
705 r = ioctl(fd, FIONREAD, &buflen);
706 if (r < 0)
707 return r;
708
709 if (buflen < 0)
710 /* this can't be right */
711 return -EIO;
712
713 packet = malloc0(buflen);
714 if (!packet)
715 return -ENOMEM;
716
717 len = recvfrom(fd, packet, buflen, 0, &link.sa, &addrlen);
718 if (len < 0) {
719 log_warning_errno(r, "PPPoE: could not receive message from raw socket: %m");
720 return 0;
721 } else if ((size_t)len < sizeof(struct pppoe_hdr))
722 return 0;
723 else if ((size_t)len != sizeof(struct pppoe_hdr) + PPPOE_PACKET_LENGTH(packet))
724 return 0;
725
726 if (link.ll.sll_halen != ETH_ALEN)
727 /* not ethernet? */
728 return 0;
729
730 r = pppoe_handle_message(ppp, packet, (struct ether_addr*)&link.ll.sll_addr);
731 if (r < 0)
732 return r;
733
734 return 1;
735 }
736
737 int sd_pppoe_start(sd_pppoe *ppp) {
738 union sockaddr_union link = {
739 .ll = {
740 .sll_family = AF_PACKET,
741 .sll_protocol = htons(ETH_P_PPP_DISC),
742 },
743 };
744 _cleanup_close_ int s = -1;
745 _cleanup_event_source_unref_ sd_event_source *io = NULL;
746 int r;
747
748 assert_return(ppp, -EINVAL);
749 assert_return(ppp->fd == -1, -EBUSY);
750 assert_return(!ppp->io, -EBUSY);
751 assert_return(ppp->ifindex > 0, -EUNATCH);
752 assert_return(ppp->ifname, -EUNATCH);
753 assert_return(ppp->event, -EUNATCH);
754 assert_return(ppp->cb, -EUNATCH);
755
756 s = socket(AF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
757 if (s < 0)
758 return -errno;
759
760 link.ll.sll_ifindex = ppp->ifindex;
761
762 r = bind(s, &link.sa, sizeof(link.ll));
763 if (r < 0)
764 return r;
765
766 r = sd_event_add_io(ppp->event, &io,
767 s, EPOLLIN, pppoe_receive_message,
768 ppp);
769 if (r < 0)
770 return r;
771
772 r = sd_event_source_set_priority(io, ppp->event_priority);
773 if (r < 0)
774 return r;
775
776 ppp->fd = s;
777 s = -1;
778 ppp->io = io;
779 io = NULL;
780
781 r = pppoe_send_initiation(ppp);
782 if (r < 0)
783 return r;
784
785 ppp->state = PPPOE_STATE_INITIALIZING;
786
787 return 0;
788 }
789
790 int sd_pppoe_stop(sd_pppoe *ppp) {
791 assert_return(ppp, -EINVAL);
792
793 if (ppp->state == PPPOE_STATE_RUNNING)
794 pppoe_send_terminate(ppp);
795
796 ppp->io = sd_event_source_unref(ppp->io);
797 ppp->timeout = sd_event_source_unref(ppp->timeout);
798 ppp->fd = asynchronous_close(ppp->fd);
799 ppp->pppoe_fd = asynchronous_close(ppp->pppoe_fd);
800
801 return 0;
802 }