1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright (C) 2014 Tom Gundersen
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.
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.
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/>.
25 #include <netinet/in.h>
26 #include <sys/ioctl.h>
27 #include <linux/if_pppox.h>
28 #include <linux/ppp-ioctl.h>
29 #include <linux/ppp_defs.h>
34 #include "event-util.h"
35 #include "random-util.h"
36 #include "socket-util.h"
37 #include "sparse-endian.h"
38 #include "string-util.h"
42 #define PPPOE_MAX_PACKET_SIZE 1484
43 #define PPPOE_MAX_PADR_RESEND 16
45 /* TODO: move this to socket-util.h without getting into
46 * a mess with the includes */
47 union sockaddr_union_pppox
{
49 struct sockaddr_pppox pppox
;
52 typedef enum PPPoEState
{
53 PPPOE_STATE_INITIALIZING
,
54 PPPOE_STATE_REQUESTING
,
58 _PPPOE_STATE_INVALID
= -1,
61 typedef struct PPPoETags
{
83 sd_event_source
*timeout
;
84 int padr_resend_count
;
87 struct ether_addr peer_mac
;
99 #define PPPOE_PACKET_LENGTH(header) \
100 be16toh((header)->length)
102 #define PPPOE_PACKET_TAIL(packet) \
103 (struct pppoe_tag*)((uint8_t*)(packet) + sizeof(struct pppoe_hdr) + PPPOE_PACKET_LENGTH(packet))
105 #define PPPOE_TAG_LENGTH(tag) \
106 be16toh((tag)->tag_len)
108 #define PPPOE_TAG_TYPE(tag) \
111 #define PPPOE_TAG_NEXT(tag) \
112 (struct pppoe_tag *)((uint8_t *)(tag) + sizeof(struct pppoe_tag) + PPPOE_TAG_LENGTH(tag))
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))
122 static void pppoe_tags_clear(PPPoETags
*tags
) {
123 free(tags
->service_name
);
125 free(tags
->host_uniq
);
131 int sd_pppoe_set_ifindex(sd_pppoe
*ppp
, int ifindex
) {
132 assert_return(ppp
, -EINVAL
);
133 assert_return(ifindex
> 0, -EINVAL
);
135 ppp
->ifindex
= ifindex
;
140 int sd_pppoe_set_ifname(sd_pppoe
*ppp
, const char *ifname
) {
143 assert_return(ppp
, -EINVAL
);
144 assert_return(ifname
, -EINVAL
);
146 if (strlen(ifname
) > IFNAMSIZ
)
149 name
= strdup(ifname
);
159 int sd_pppoe_set_service_name(sd_pppoe
*ppp
, const char *service_name
) {
160 _cleanup_free_
char *name
= NULL
;
162 assert_return(ppp
, -EINVAL
);
165 name
= strdup(service_name
);
170 free(ppp
->service_name
);
171 ppp
->service_name
= name
;
177 int sd_pppoe_attach_event(sd_pppoe
*ppp
, sd_event
*event
, int priority
) {
180 assert_return(ppp
, -EINVAL
);
181 assert_return(!ppp
->event
, -EBUSY
);
184 ppp
->event
= sd_event_ref(event
);
186 r
= sd_event_default(&ppp
->event
);
191 ppp
->event_priority
= priority
;
196 int sd_pppoe_detach_event(sd_pppoe
*ppp
) {
197 assert_return(ppp
, -EINVAL
);
199 ppp
->event
= sd_event_unref(ppp
->event
);
204 sd_pppoe
*sd_pppoe_ref(sd_pppoe
*ppp
) {
209 assert(ppp
->n_ref
> 0);
215 sd_pppoe
*sd_pppoe_unref(sd_pppoe
*ppp
) {
220 assert(ppp
->n_ref
> 0);
226 pppoe_tags_clear(&ppp
->tags
);
228 free(ppp
->service_name
);
230 sd_pppoe_detach_event(ppp
);
236 int sd_pppoe_new (sd_pppoe
**ret
) {
239 assert_return(ret
, -EINVAL
);
241 ppp
= new0(sd_pppoe
, 1);
246 ppp
->state
= _PPPOE_STATE_INVALID
;
250 ppp
->padr_resend_count
= PPPOE_MAX_PADR_RESEND
;
257 int sd_pppoe_get_channel(sd_pppoe
*ppp
, int *channel
) {
258 assert_return(ppp
, -EINVAL
);
259 assert_return(channel
, -EINVAL
);
260 assert_return(ppp
->pppoe_fd
!= -1, -EUNATCH
);
261 assert_return(ppp
->state
== PPPOE_STATE_RUNNING
, -EUNATCH
);
263 *channel
= ppp
->channel
;
268 int sd_pppoe_set_callback(sd_pppoe
*ppp
, sd_pppoe_cb_t cb
, void *userdata
) {
269 assert_return(ppp
, -EINVAL
);
272 ppp
->userdata
= userdata
;
277 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
) {
278 struct pppoe_tag
*tag
;
281 assert(sizeof(struct pppoe_hdr
) + PPPOE_PACKET_LENGTH(packet
) + sizeof(struct pppoe_tag
) + tag_len
<= packet_size
);
282 assert(!(!tag_data
^ !tag_len
));
284 tag
= PPPOE_PACKET_TAIL(packet
);
286 tag
->tag_len
= htobe16(tag_len
);
287 tag
->tag_type
= tag_type
;
289 memcpy(tag
->tag_data
, tag_data
, tag_len
);
291 packet
->length
= htobe16(PPPOE_PACKET_LENGTH(packet
) + sizeof(struct pppoe_tag
) + tag_len
);
294 static int pppoe_send(sd_pppoe
*ppp
, uint8_t code
) {
295 union sockaddr_union link
= {
297 .sll_family
= AF_PACKET
,
298 .sll_protocol
= htons(ETH_P_PPP_DISC
),
299 .sll_halen
= ETH_ALEN
,
302 _cleanup_free_
struct pppoe_hdr
*packet
= NULL
;
306 assert(ppp
->fd
!= -1);
307 assert(IN_SET(code
, PADI_CODE
, PADR_CODE
, PADT_CODE
));
309 link
.ll
.sll_ifindex
= ppp
->ifindex
;
310 if (code
== PADI_CODE
)
311 memset(&link
.ll
.sll_addr
, 0xff, ETH_ALEN
);
313 memcpy(&link
.ll
.sll_addr
, &ppp
->peer_mac
, ETH_ALEN
);
315 packet
= malloc0(PPPOE_MAX_PACKET_SIZE
);
322 if (code
== PADT_CODE
)
323 packet
->sid
= ppp
->session_id
;
326 pppoe_tag_append(packet
, PPPOE_MAX_PACKET_SIZE
, PTT_SRV_NAME
,
327 ppp
->service_name
, ppp
->service_name
? strlen(ppp
->service_name
) : 0);
330 if (code
== PADR_CODE
&& ppp
->tags
.cookie
)
331 pppoe_tag_append(packet
, PPPOE_MAX_PACKET_SIZE
, PTT_AC_COOKIE
,
332 ppp
->tags
.cookie
, ppp
->tags
.cookie_len
);
335 if (code
!= PADT_CODE
) {
336 ppp
->host_uniq
= random_u64();
338 pppoe_tag_append(packet
, PPPOE_MAX_PACKET_SIZE
, PTT_HOST_UNIQ
,
339 &ppp
->host_uniq
, sizeof(ppp
->host_uniq
));
342 r
= sendto(ppp
->fd
, packet
, sizeof(struct pppoe_hdr
) + PPPOE_PACKET_LENGTH(packet
),
343 0, &link
.sa
, sizeof(link
.ll
));
350 static int pppoe_timeout(sd_event_source
*s
, uint64_t usec
, void *userdata
);
352 static int pppoe_arm_timeout(sd_pppoe
*ppp
) {
353 _cleanup_event_source_unref_ sd_event_source
*timeout
= NULL
;
354 usec_t next_timeout
= 0;
359 r
= sd_event_now(ppp
->event
, clock_boottime_or_monotonic(), &next_timeout
);
363 next_timeout
+= 500 * USEC_PER_MSEC
;
365 r
= sd_event_add_time(ppp
->event
, &timeout
, clock_boottime_or_monotonic(), next_timeout
,
366 10 * USEC_PER_MSEC
, pppoe_timeout
, ppp
);
370 r
= sd_event_source_set_priority(timeout
, ppp
->event_priority
);
374 sd_event_source_unref(ppp
->timeout
);
375 ppp
->timeout
= timeout
;
381 static int pppoe_send_initiation(sd_pppoe
*ppp
) {
384 r
= pppoe_send(ppp
, PADI_CODE
);
388 log_debug("PPPoE: sent DISCOVER (Service-Name: %s)",
389 strna(ppp
->service_name
));
391 pppoe_arm_timeout(ppp
);
396 static int pppoe_send_request(sd_pppoe
*ppp
) {
399 r
= pppoe_send(ppp
, PADR_CODE
);
403 log_debug("PPPoE: sent REQUEST");
405 ppp
->padr_resend_count
--;
407 pppoe_arm_timeout(ppp
);
412 static int pppoe_send_terminate(sd_pppoe
*ppp
) {
415 r
= pppoe_send(ppp
, PADT_CODE
);
419 log_debug("PPPoE: sent TERMINATE");
424 static int pppoe_timeout(sd_event_source
*s
, uint64_t usec
, void *userdata
) {
425 sd_pppoe
*ppp
= userdata
;
430 switch (ppp
->state
) {
431 case PPPOE_STATE_INITIALIZING
:
432 r
= pppoe_send_initiation(ppp
);
434 log_warning_errno(r
, "PPPoE: sending PADI failed: %m");
437 case PPPOE_STATE_REQUESTING
:
438 if (ppp
->padr_resend_count
<= 0) {
439 log_debug("PPPoE: PADR timed out, restarting PADI");
441 r
= pppoe_send_initiation(ppp
);
443 log_warning_errno(r
, "PPPoE: sending PADI failed: %m");
445 ppp
->padr_resend_count
= PPPOE_MAX_PADR_RESEND
;
446 ppp
->state
= PPPOE_STATE_INITIALIZING
;
448 r
= pppoe_send_request(ppp
);
450 log_warning_errno(r
, "PPPoE: sending PADR failed: %m");
455 assert_not_reached("timeout in invalid state");
461 static int pppoe_tag_parse_binary(struct pppoe_tag
*tag
, uint8_t **ret
, size_t *length
) {
467 data
= memdup(tag
->tag_data
, PPPOE_TAG_LENGTH(tag
));
473 *length
= PPPOE_TAG_LENGTH(tag
);
478 static int pppoe_tag_parse_string(struct pppoe_tag
*tag
, char **ret
) {
483 string
= strndup(tag
->tag_data
, PPPOE_TAG_LENGTH(tag
));
493 static int pppoe_payload_parse(PPPoETags
*tags
, struct pppoe_hdr
*header
) {
494 struct pppoe_tag
*tag
;
499 pppoe_tags_clear(tags
);
501 PPPOE_TAGS_FOREACH(tag
, header
) {
502 switch (PPPOE_TAG_TYPE(tag
)) {
504 r
= pppoe_tag_parse_string(tag
, &tags
->service_name
);
510 r
= pppoe_tag_parse_string(tag
, &tags
->ac_name
);
516 r
= pppoe_tag_parse_binary(tag
, &tags
->host_uniq
, &tags
->host_uniq_len
);
522 r
= pppoe_tag_parse_binary(tag
, &tags
->cookie
, &tags
->cookie_len
);
531 _cleanup_free_
char *error
= NULL
;
533 /* TODO: do something more sensible with the error messages */
534 r
= pppoe_tag_parse_string(tag
, &error
);
538 if (strlen(error
) > 0 && utf8_is_valid(error
))
539 log_debug("PPPoE: error - '%s'", error
);
541 log_debug("PPPoE: error");
546 log_debug("PPPoE: ignoring unknown PPPoE tag type: 0x%.2x", PPPOE_TAG_TYPE(tag
));
553 static int pppoe_open_pppoe_socket(sd_pppoe
*ppp
) {
557 assert(ppp
->pppoe_fd
== -1);
559 s
= socket(AF_PPPOX
, SOCK_STREAM
, 0);
568 static int pppoe_connect_pppoe_socket(sd_pppoe
*ppp
) {
569 union sockaddr_union_pppox link
= {
571 .sa_family
= AF_PPPOX
,
572 .sa_protocol
= PX_PROTO_OE
,
578 assert(ppp
->pppoe_fd
!= -1);
579 assert(ppp
->session_id
);
582 link
.pppox
.sa_addr
.pppoe
.sid
= ppp
->session_id
;
583 memcpy(link
.pppox
.sa_addr
.pppoe
.dev
, ppp
->ifname
, strlen(ppp
->ifname
));
584 memcpy(link
.pppox
.sa_addr
.pppoe
.remote
, &ppp
->peer_mac
, ETH_ALEN
);
586 r
= connect(ppp
->pppoe_fd
, &link
.sa
, sizeof(link
.pppox
));
590 r
= ioctl(ppp
->pppoe_fd
, PPPIOCGCHAN
, &channel
);
594 ppp
->channel
= channel
;
599 static int pppoe_handle_message(sd_pppoe
*ppp
, struct pppoe_hdr
*packet
, struct ether_addr
*mac
) {
604 if (packet
->ver
!= 0x1 || packet
->type
!= 0x1)
607 r
= pppoe_payload_parse(&ppp
->tags
, packet
);
611 switch (ppp
->state
) {
612 case PPPOE_STATE_INITIALIZING
:
613 if (packet
->code
!= PADO_CODE
)
616 if (ppp
->tags
.host_uniq_len
!= sizeof(ppp
->host_uniq
) ||
617 memcmp(ppp
->tags
.host_uniq
, &ppp
->host_uniq
, sizeof(ppp
->host_uniq
)) != 0)
620 log_debug("PPPoE: got OFFER (Peer: "
621 "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx; "
622 "Service-Name: '%s'; AC-Name: '%s')",
623 mac
->ether_addr_octet
[0],
624 mac
->ether_addr_octet
[1],
625 mac
->ether_addr_octet
[2],
626 mac
->ether_addr_octet
[3],
627 mac
->ether_addr_octet
[4],
628 mac
->ether_addr_octet
[5],
629 strempty(ppp
->tags
.service_name
),
630 strempty(ppp
->tags
.ac_name
));
632 memcpy(&ppp
->peer_mac
, mac
, ETH_ALEN
);
634 r
= pppoe_open_pppoe_socket(ppp
);
636 log_warning("PPPoE: could not open socket");
640 r
= pppoe_send_request(ppp
);
644 ppp
->state
= PPPOE_STATE_REQUESTING
;
647 case PPPOE_STATE_REQUESTING
:
648 if (packet
->code
!= PADS_CODE
)
651 if (ppp
->tags
.host_uniq_len
!= sizeof(ppp
->host_uniq
) ||
652 memcmp(ppp
->tags
.host_uniq
, &ppp
->host_uniq
,
653 sizeof(ppp
->host_uniq
)) != 0)
656 if (memcmp(&ppp
->peer_mac
, mac
, ETH_ALEN
) != 0)
659 ppp
->session_id
= packet
->sid
;
661 log_debug("PPPoE: got CONFIRMATION (Session ID: %"PRIu16
")",
662 be16toh(ppp
->session_id
));
664 r
= pppoe_connect_pppoe_socket(ppp
);
666 log_warning("PPPoE: could not connect socket");
670 ppp
->state
= PPPOE_STATE_RUNNING
;
672 ppp
->timeout
= sd_event_source_unref(ppp
->timeout
);
674 ppp
->cb(ppp
, SD_PPPOE_EVENT_RUNNING
, ppp
->userdata
);
677 case PPPOE_STATE_RUNNING
:
678 if (packet
->code
!= PADT_CODE
)
681 if (memcmp(&ppp
->peer_mac
, mac
, ETH_ALEN
) != 0)
684 if (ppp
->session_id
!= packet
->sid
)
687 log_debug("PPPoE: got TERMINATE");
689 ppp
->state
= PPPOE_STATE_STOPPED
;
692 ppp
->cb(ppp
, SD_PPPOE_EVENT_STOPPED
, ppp
->userdata
);
695 case PPPOE_STATE_STOPPED
:
698 assert_not_reached("PPPoE: invalid state when receiving message");
704 static int pppoe_receive_message(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
705 sd_pppoe
*ppp
= userdata
;
706 _cleanup_free_
struct pppoe_hdr
*packet
= NULL
;
707 union sockaddr_union link
= {};
708 socklen_t addrlen
= sizeof(link
);
709 int buflen
= 0, len
, r
;
714 r
= ioctl(fd
, FIONREAD
, &buflen
);
719 /* this can't be right */
722 packet
= malloc0(buflen
);
726 len
= recvfrom(fd
, packet
, buflen
, 0, &link
.sa
, &addrlen
);
728 log_warning_errno(r
, "PPPoE: could not receive message from raw socket: %m");
730 } else if ((size_t)len
< sizeof(struct pppoe_hdr
))
732 else if ((size_t)len
!= sizeof(struct pppoe_hdr
) + PPPOE_PACKET_LENGTH(packet
))
735 if (link
.ll
.sll_halen
!= ETH_ALEN
)
739 r
= pppoe_handle_message(ppp
, packet
, (struct ether_addr
*)&link
.ll
.sll_addr
);
746 int sd_pppoe_start(sd_pppoe
*ppp
) {
747 union sockaddr_union link
= {
749 .sll_family
= AF_PACKET
,
750 .sll_protocol
= htons(ETH_P_PPP_DISC
),
753 _cleanup_close_
int s
= -1;
754 _cleanup_event_source_unref_ sd_event_source
*io
= NULL
;
757 assert_return(ppp
, -EINVAL
);
758 assert_return(ppp
->fd
== -1, -EBUSY
);
759 assert_return(!ppp
->io
, -EBUSY
);
760 assert_return(ppp
->ifindex
> 0, -EUNATCH
);
761 assert_return(ppp
->ifname
, -EUNATCH
);
762 assert_return(ppp
->event
, -EUNATCH
);
763 assert_return(ppp
->cb
, -EUNATCH
);
765 s
= socket(AF_PACKET
, SOCK_DGRAM
| SOCK_CLOEXEC
| SOCK_NONBLOCK
, 0);
769 link
.ll
.sll_ifindex
= ppp
->ifindex
;
771 r
= bind(s
, &link
.sa
, sizeof(link
.ll
));
775 r
= sd_event_add_io(ppp
->event
, &io
,
776 s
, EPOLLIN
, pppoe_receive_message
,
781 r
= sd_event_source_set_priority(io
, ppp
->event_priority
);
790 r
= pppoe_send_initiation(ppp
);
794 ppp
->state
= PPPOE_STATE_INITIALIZING
;
799 int sd_pppoe_stop(sd_pppoe
*ppp
) {
800 assert_return(ppp
, -EINVAL
);
802 if (ppp
->state
== PPPOE_STATE_RUNNING
)
803 pppoe_send_terminate(ppp
);
805 ppp
->io
= sd_event_source_unref(ppp
->io
);
806 ppp
->timeout
= sd_event_source_unref(ppp
->timeout
);
807 ppp
->fd
= asynchronous_close(ppp
->fd
);
808 ppp
->pppoe_fd
= asynchronous_close(ppp
->pppoe_fd
);