2 * Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS
18 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
21 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
24 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 * $FreeBSD: stable/10/usr.sbin/rtadvd/control.c 225519 2011-09-12 23:52:55Z hrs $
30 #include <sys/queue.h>
31 #include <sys/types.h>
32 #include <sys/socket.h>
37 #include <net/if_dl.h>
38 #include <netinet/in.h>
39 #include <netinet/icmp6.h>
54 #include "pathnames.h"
57 #define CM_RECV_TIMEOUT 30
60 cm_recv(int fd
, char *buf
)
63 struct ctrl_msg_hdr
*cm
;
65 struct pollfd pfds
[1];
68 syslog(LOG_DEBUG
, "<%s> enter, fd=%d", __func__
, fd
);
70 memset(buf
, 0, CM_MSG_MAXLEN
);
71 cm
= (struct ctrl_msg_hdr
*)buf
;
72 msg
= (char *)buf
+ sizeof(*cm
);
75 pfds
[0].events
= POLLIN
;
78 i
= poll(pfds
, sizeof(pfds
)/sizeof(pfds
[0]),
85 syslog(LOG_ERR
, "<%s> poll error: %s",
86 __func__
, strerror(errno
));
90 if (pfds
[0].revents
& POLLIN
) {
91 n
= read(fd
, cm
, sizeof(*cm
));
92 if (n
< 0 && errno
== EAGAIN
) {
94 "<%s> waiting...", __func__
);
101 if (n
!= sizeof(*cm
)) {
103 "<%s> received a too small message.", __func__
);
106 if (cm
->cm_len
> CM_MSG_MAXLEN
) {
108 "<%s> received a too large message.", __func__
);
111 if (cm
->cm_version
!= CM_VERSION
) {
113 "<%s> version mismatch", __func__
);
116 if (cm
->cm_type
>= CM_TYPE_MAX
) {
118 "<%s> invalid msg type.", __func__
);
123 "<%s> ctrl msg received: type=%d", __func__
,
126 if (cm
->cm_len
> sizeof(cm
)) {
127 int msglen
= cm
->cm_len
- sizeof(*cm
);
130 "<%s> ctrl msg has payload (len=%d)", __func__
,
134 i
= poll(pfds
, sizeof(pfds
)/sizeof(pfds
[0]),
141 syslog(LOG_ERR
, "<%s> poll error: %s",
142 __func__
, strerror(errno
));
146 if (pfds
[0].revents
& POLLIN
) {
147 n
= read(fd
, msg
, msglen
);
148 if (n
< 0 && errno
== EAGAIN
) {
150 "<%s> waiting...", __func__
);
158 "<%s> payload size mismatch.", __func__
);
161 buf
[CM_MSG_MAXLEN
- 1] = '\0';
172 cm_send(int fd
, char *buf
)
177 ssize_t iov_len_total
;
178 struct ctrl_msg_hdr
*cm
;
181 cm
= (struct ctrl_msg_hdr
*)buf
;
182 msg
= (char *)buf
+ sizeof(*cm
);
185 iov
[0].iov_base
= cm
;
186 iov
[0].iov_len
= sizeof(*cm
);
187 iov_len_total
= iov
[0].iov_len
;
188 if (cm
->cm_len
> sizeof(*cm
)) {
190 iov
[1].iov_base
= msg
;
191 iov
[1].iov_len
= cm
->cm_len
- iov
[0].iov_len
;
192 iov_len_total
+= iov
[1].iov_len
;
196 "<%s> ctrl msg send: type=%d, count=%d, total_len=%zd", __func__
,
197 cm
->cm_type
, iovcnt
, iov_len_total
);
199 len
= writev(fd
, iov
, iovcnt
);
201 "<%s> ctrl msg send: length=%zd", __func__
, len
);
205 "<%s> write failed: (%d)%s", __func__
, errno
,
212 "<%s> write length = %zd (actual)", __func__
, len
);
214 "<%s> write length = %zd (expected)", __func__
, iov_len_total
);
216 if (len
!= iov_len_total
) {
225 csock_accept(struct sockinfo
*s
)
227 struct sockaddr_un sun
;
231 sun
.sun_len
= sizeof(sun
);
232 if ((fd
= accept(s
->si_fd
, (struct sockaddr
*)&sun
,
233 (socklen_t
*)&sun
.sun_len
)) == -1) {
234 if (errno
!= EWOULDBLOCK
&& errno
!= EINTR
)
235 syslog(LOG_WARNING
, "<%s> accept ", __func__
);
236 syslog(LOG_WARNING
, "<%s> Xaccept: %s", __func__
, strerror(errno
));
239 if ((flags
= fcntl(fd
, F_GETFL
, 0)) == -1) {
240 syslog(LOG_WARNING
, "<%s> fcntl F_GETFL", __func__
);
244 if ((flags
= fcntl(fd
, F_SETFL
, flags
| O_NONBLOCK
)) == -1) {
245 syslog(LOG_WARNING
, "<%s> fcntl F_SETFL", __func__
);
248 syslog(LOG_DEBUG
, "<%s> accept connfd=%d, listenfd=%d", __func__
,
255 csock_close(struct sockinfo
*s
)
259 syslog(LOG_DEBUG
, "<%s> remove %s", __func__
, s
->si_name
);
264 csock_listen(struct sockinfo
*s
)
266 if (s
->si_fd
== -1) {
267 syslog(LOG_ERR
, "<%s> listen failed", __func__
);
270 if (listen(s
->si_fd
, SOCK_BACKLOG
) == -1) {
271 syslog(LOG_ERR
, "<%s> listen failed", __func__
);
279 csock_open(struct sockinfo
*s
, mode_t mode
)
282 struct sockaddr_un sun
;
286 syslog(LOG_ERR
, "<%s> internal error.", __func__
);
289 if (s
->si_name
== NULL
)
290 s
->si_name
= _PATH_CTRL_SOCK
;
292 if ((s
->si_fd
= socket(PF_UNIX
, SOCK_STREAM
, 0)) == -1) {
294 "<%s> cannot open control socket", __func__
);
297 memset(&sun
, 0, sizeof(sun
));
298 sun
.sun_family
= AF_UNIX
;
299 sun
.sun_len
= sizeof(sun
);
300 strlcpy(sun
.sun_path
, s
->si_name
, sizeof(sun
.sun_path
));
302 if (unlink(s
->si_name
) == -1)
303 if (errno
!= ENOENT
) {
305 "<%s> unlink %s", __func__
, s
->si_name
);
309 old_umask
= umask(S_IXUSR
|S_IXGRP
|S_IXOTH
);
310 if (bind(s
->si_fd
, (struct sockaddr
*)&sun
, sizeof(sun
)) == -1) {
312 "<%s> bind failed: %s", __func__
, s
->si_name
);
318 if (chmod(s
->si_name
, mode
) == -1) {
320 "<%s> chmod failed: %s", __func__
, s
->si_name
);
323 if ((flags
= fcntl(s
->si_fd
, F_GETFL
, 0)) == -1) {
325 "<%s> fcntl F_GETFL failed: %s", __func__
, s
->si_name
);
328 if ((flags
= fcntl(s
->si_fd
, F_SETFL
, flags
| O_NONBLOCK
)) == -1) {
330 "<%s> fcntl F_SETFL failed: %s", __func__
, s
->si_name
);
343 cm_bin2pl(char *str
, struct ctrl_msg_pl
*cp
)
349 memset(cp
, 0, sizeof(*cp
));
356 syslog(LOG_DEBUG
, "<%s> len(ifname) = %zu", __func__
, len
);
358 cp
->cp_ifname
= malloc(len
+ 1);
359 if (cp
->cp_ifname
== NULL
) {
360 syslog(LOG_ERR
, "<%s> malloc", __func__
);
363 memcpy(cp
->cp_ifname
, p
, len
);
364 cp
->cp_ifname
[len
] = '\0';
371 syslog(LOG_DEBUG
, "<%s> len(key) = %zu", __func__
, len
);
373 cp
->cp_key
= malloc(len
+ 1);
374 if (cp
->cp_key
== NULL
) {
375 syslog(LOG_ERR
, "<%s> malloc", __func__
);
378 memcpy(cp
->cp_key
, p
, len
);
379 cp
->cp_key
[len
] = '\0';
386 syslog(LOG_DEBUG
, "<%s> len(val) = %zu", __func__
, len
);
388 cp
->cp_val
= malloc(len
+ 1);
389 if (cp
->cp_val
== NULL
) {
390 syslog(LOG_ERR
, "<%s> malloc", __func__
);
393 memcpy(cp
->cp_val
, p
, len
);
394 cp
->cp_val
[len
] = '\0';
395 cp
->cp_val_len
= len
;
403 cm_pl2bin(char *str
, struct ctrl_msg_pl
*cp
)
408 struct ctrl_msg_hdr
*cm
;
410 len
= sizeof(size_t);
411 if (cp
->cp_ifname
!= NULL
)
412 len
+= strlen(cp
->cp_ifname
);
413 len
+= sizeof(size_t);
414 if (cp
->cp_key
!= NULL
)
415 len
+= strlen(cp
->cp_key
);
416 len
+= sizeof(size_t);
417 if (cp
->cp_val
!= NULL
&& cp
->cp_val_len
> 0)
418 len
+= cp
->cp_val_len
;
420 if (len
> CM_MSG_MAXLEN
- sizeof(*cm
)) {
421 syslog(LOG_DEBUG
, "<%s> msg too long (len=%zu)",
425 syslog(LOG_DEBUG
, "<%s> msglen=%zu", __func__
, len
);
430 if (cp
->cp_ifname
!= NULL
) {
431 *lenp
++ = strlen(cp
->cp_ifname
);
433 memcpy(p
, cp
->cp_ifname
, strlen(cp
->cp_ifname
));
434 p
+= strlen(cp
->cp_ifname
);
441 if (cp
->cp_key
!= NULL
) {
442 *lenp
++ = strlen(cp
->cp_key
);
444 memcpy(p
, cp
->cp_key
, strlen(cp
->cp_key
));
445 p
+= strlen(cp
->cp_key
);
452 if (cp
->cp_val
!= NULL
&& cp
->cp_val_len
> 0) {
453 *lenp
++ = cp
->cp_val_len
;
455 memcpy(p
, cp
->cp_val
, cp
->cp_val_len
);
466 cm_str2bin(char *bin
, void *str
, size_t len
)
468 struct ctrl_msg_hdr
*cm
;
470 syslog(LOG_DEBUG
, "<%s> enter", __func__
);
472 if (len
> CM_MSG_MAXLEN
- sizeof(*cm
)) {
473 syslog(LOG_DEBUG
, "<%s> msg too long (len=%zu)",
477 syslog(LOG_DEBUG
, "<%s> msglen=%zu", __func__
, len
);
478 memcpy(bin
, (char *)str
, len
);
484 cm_bin2str(char *bin
, void *str
, size_t len
)
487 syslog(LOG_DEBUG
, "<%s> enter", __func__
);
489 memcpy((char *)str
, bin
, len
);