1*9f20bfa6SDavid van Moolenbroek #include <sys/cdefs.h>
2*9f20bfa6SDavid van Moolenbroek __RCSID("$NetBSD: common.c,v 1.14 2015/07/09 10:15:34 roy Exp $");
3*9f20bfa6SDavid van Moolenbroek
4*9f20bfa6SDavid van Moolenbroek /*
5*9f20bfa6SDavid van Moolenbroek * dhcpcd - DHCP client daemon
6*9f20bfa6SDavid van Moolenbroek * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
7*9f20bfa6SDavid van Moolenbroek * All rights reserved
8*9f20bfa6SDavid van Moolenbroek
9*9f20bfa6SDavid van Moolenbroek * Redistribution and use in source and binary forms, with or without
10*9f20bfa6SDavid van Moolenbroek * modification, are permitted provided that the following conditions
11*9f20bfa6SDavid van Moolenbroek * are met:
12*9f20bfa6SDavid van Moolenbroek * 1. Redistributions of source code must retain the above copyright
13*9f20bfa6SDavid van Moolenbroek * notice, this list of conditions and the following disclaimer.
14*9f20bfa6SDavid van Moolenbroek * 2. Redistributions in binary form must reproduce the above copyright
15*9f20bfa6SDavid van Moolenbroek * notice, this list of conditions and the following disclaimer in the
16*9f20bfa6SDavid van Moolenbroek * documentation and/or other materials provided with the distribution.
17*9f20bfa6SDavid van Moolenbroek *
18*9f20bfa6SDavid van Moolenbroek * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19*9f20bfa6SDavid van Moolenbroek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20*9f20bfa6SDavid van Moolenbroek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21*9f20bfa6SDavid van Moolenbroek * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22*9f20bfa6SDavid van Moolenbroek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23*9f20bfa6SDavid van Moolenbroek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24*9f20bfa6SDavid van Moolenbroek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25*9f20bfa6SDavid van Moolenbroek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26*9f20bfa6SDavid van Moolenbroek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27*9f20bfa6SDavid van Moolenbroek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28*9f20bfa6SDavid van Moolenbroek * SUCH DAMAGE.
29*9f20bfa6SDavid van Moolenbroek */
30*9f20bfa6SDavid van Moolenbroek
31*9f20bfa6SDavid van Moolenbroek #include <sys/param.h>
32*9f20bfa6SDavid van Moolenbroek #include <sys/time.h>
33*9f20bfa6SDavid van Moolenbroek
34*9f20bfa6SDavid van Moolenbroek #include <ctype.h>
35*9f20bfa6SDavid van Moolenbroek #include <err.h>
36*9f20bfa6SDavid van Moolenbroek #include <errno.h>
37*9f20bfa6SDavid van Moolenbroek #include <fcntl.h>
38*9f20bfa6SDavid van Moolenbroek #include <limits.h>
39*9f20bfa6SDavid van Moolenbroek #ifdef BSD
40*9f20bfa6SDavid van Moolenbroek # include <paths.h>
41*9f20bfa6SDavid van Moolenbroek #endif
42*9f20bfa6SDavid van Moolenbroek #include <stdarg.h>
43*9f20bfa6SDavid van Moolenbroek #include <stdint.h>
44*9f20bfa6SDavid van Moolenbroek #include <stdio.h>
45*9f20bfa6SDavid van Moolenbroek #include <stdlib.h>
46*9f20bfa6SDavid van Moolenbroek #include <string.h>
47*9f20bfa6SDavid van Moolenbroek #include <syslog.h>
48*9f20bfa6SDavid van Moolenbroek #include <time.h>
49*9f20bfa6SDavid van Moolenbroek #include <unistd.h>
50*9f20bfa6SDavid van Moolenbroek
51*9f20bfa6SDavid van Moolenbroek #include "common.h"
52*9f20bfa6SDavid van Moolenbroek #include "dhcpcd.h"
53*9f20bfa6SDavid van Moolenbroek #include "if-options.h"
54*9f20bfa6SDavid van Moolenbroek
55*9f20bfa6SDavid van Moolenbroek #ifndef _PATH_DEVNULL
56*9f20bfa6SDavid van Moolenbroek # define _PATH_DEVNULL "/dev/null"
57*9f20bfa6SDavid van Moolenbroek #endif
58*9f20bfa6SDavid van Moolenbroek
59*9f20bfa6SDavid van Moolenbroek const char *
get_hostname(char * buf,size_t buflen,int short_hostname)60*9f20bfa6SDavid van Moolenbroek get_hostname(char *buf, size_t buflen, int short_hostname)
61*9f20bfa6SDavid van Moolenbroek {
62*9f20bfa6SDavid van Moolenbroek char *p;
63*9f20bfa6SDavid van Moolenbroek
64*9f20bfa6SDavid van Moolenbroek if (gethostname(buf, buflen) != 0)
65*9f20bfa6SDavid van Moolenbroek return NULL;
66*9f20bfa6SDavid van Moolenbroek buf[buflen - 1] = '\0';
67*9f20bfa6SDavid van Moolenbroek if (strcmp(buf, "(none)") == 0 ||
68*9f20bfa6SDavid van Moolenbroek strcmp(buf, "localhost") == 0 ||
69*9f20bfa6SDavid van Moolenbroek strncmp(buf, "localhost.", strlen("localhost.")) == 0 ||
70*9f20bfa6SDavid van Moolenbroek buf[0] == '.')
71*9f20bfa6SDavid van Moolenbroek return NULL;
72*9f20bfa6SDavid van Moolenbroek
73*9f20bfa6SDavid van Moolenbroek if (short_hostname) {
74*9f20bfa6SDavid van Moolenbroek p = strchr(buf, '.');
75*9f20bfa6SDavid van Moolenbroek if (p)
76*9f20bfa6SDavid van Moolenbroek *p = '\0';
77*9f20bfa6SDavid van Moolenbroek }
78*9f20bfa6SDavid van Moolenbroek
79*9f20bfa6SDavid van Moolenbroek return buf;
80*9f20bfa6SDavid van Moolenbroek }
81*9f20bfa6SDavid van Moolenbroek
82*9f20bfa6SDavid van Moolenbroek #if USE_LOGFILE
83*9f20bfa6SDavid van Moolenbroek void
logger_open(struct dhcpcd_ctx * ctx)84*9f20bfa6SDavid van Moolenbroek logger_open(struct dhcpcd_ctx *ctx)
85*9f20bfa6SDavid van Moolenbroek {
86*9f20bfa6SDavid van Moolenbroek
87*9f20bfa6SDavid van Moolenbroek if (ctx->logfile) {
88*9f20bfa6SDavid van Moolenbroek int f = O_CREAT | O_APPEND | O_TRUNC;
89*9f20bfa6SDavid van Moolenbroek
90*9f20bfa6SDavid van Moolenbroek #ifdef O_CLOEXEC
91*9f20bfa6SDavid van Moolenbroek f |= O_CLOEXEC;
92*9f20bfa6SDavid van Moolenbroek #endif
93*9f20bfa6SDavid van Moolenbroek ctx->log_fd = open(ctx->logfile, O_WRONLY | f, 0644);
94*9f20bfa6SDavid van Moolenbroek if (ctx->log_fd == -1)
95*9f20bfa6SDavid van Moolenbroek warn("open: %s", ctx->logfile);
96*9f20bfa6SDavid van Moolenbroek #ifndef O_CLOEXEC
97*9f20bfa6SDavid van Moolenbroek else {
98*9f20bfa6SDavid van Moolenbroek if (fcntl(ctx->log_fd, F_GETFD, &f) == -1 ||
99*9f20bfa6SDavid van Moolenbroek fcntl(ctx->log_fd, F_SETFD, f | FD_CLOEXEC) == -1)
100*9f20bfa6SDavid van Moolenbroek warn("fcntl: %s", ctx->logfile);
101*9f20bfa6SDavid van Moolenbroek }
102*9f20bfa6SDavid van Moolenbroek #endif
103*9f20bfa6SDavid van Moolenbroek } else
104*9f20bfa6SDavid van Moolenbroek openlog(PACKAGE, LOG_PID, LOG_DAEMON);
105*9f20bfa6SDavid van Moolenbroek }
106*9f20bfa6SDavid van Moolenbroek
107*9f20bfa6SDavid van Moolenbroek void
logger_close(struct dhcpcd_ctx * ctx)108*9f20bfa6SDavid van Moolenbroek logger_close(struct dhcpcd_ctx *ctx)
109*9f20bfa6SDavid van Moolenbroek {
110*9f20bfa6SDavid van Moolenbroek
111*9f20bfa6SDavid van Moolenbroek if (ctx->log_fd != -1) {
112*9f20bfa6SDavid van Moolenbroek close(ctx->log_fd);
113*9f20bfa6SDavid van Moolenbroek ctx->log_fd = -1;
114*9f20bfa6SDavid van Moolenbroek }
115*9f20bfa6SDavid van Moolenbroek closelog();
116*9f20bfa6SDavid van Moolenbroek }
117*9f20bfa6SDavid van Moolenbroek
118*9f20bfa6SDavid van Moolenbroek void
logger(struct dhcpcd_ctx * ctx,int pri,const char * fmt,...)119*9f20bfa6SDavid van Moolenbroek logger(struct dhcpcd_ctx *ctx, int pri, const char *fmt, ...)
120*9f20bfa6SDavid van Moolenbroek {
121*9f20bfa6SDavid van Moolenbroek va_list va;
122*9f20bfa6SDavid van Moolenbroek int serrno;
123*9f20bfa6SDavid van Moolenbroek #ifndef HAVE_PRINTF_M
124*9f20bfa6SDavid van Moolenbroek char fmt_cpy[1024];
125*9f20bfa6SDavid van Moolenbroek #endif
126*9f20bfa6SDavid van Moolenbroek
127*9f20bfa6SDavid van Moolenbroek if (pri >= LOG_DEBUG && ctx && !(ctx->options & DHCPCD_DEBUG))
128*9f20bfa6SDavid van Moolenbroek return;
129*9f20bfa6SDavid van Moolenbroek
130*9f20bfa6SDavid van Moolenbroek serrno = errno;
131*9f20bfa6SDavid van Moolenbroek va_start(va, fmt);
132*9f20bfa6SDavid van Moolenbroek
133*9f20bfa6SDavid van Moolenbroek #ifndef HAVE_PRINTF_M
134*9f20bfa6SDavid van Moolenbroek /* Print strerrno(errno) in place of %m */
135*9f20bfa6SDavid van Moolenbroek if (ctx == NULL || !(ctx->options & DHCPCD_QUIET) || ctx->log_fd != -1)
136*9f20bfa6SDavid van Moolenbroek {
137*9f20bfa6SDavid van Moolenbroek const char *p;
138*9f20bfa6SDavid van Moolenbroek char *fp = fmt_cpy, *serr = NULL;
139*9f20bfa6SDavid van Moolenbroek size_t fmt_left = sizeof(fmt_cpy) - 1, fmt_wrote;
140*9f20bfa6SDavid van Moolenbroek
141*9f20bfa6SDavid van Moolenbroek for (p = fmt; *p != '\0'; p++) {
142*9f20bfa6SDavid van Moolenbroek if (p[0] == '%' && p[1] == '%') {
143*9f20bfa6SDavid van Moolenbroek if (fmt_left < 2)
144*9f20bfa6SDavid van Moolenbroek break;
145*9f20bfa6SDavid van Moolenbroek *fp++ = '%';
146*9f20bfa6SDavid van Moolenbroek *fp++ = '%';
147*9f20bfa6SDavid van Moolenbroek fmt_left -= 2;
148*9f20bfa6SDavid van Moolenbroek p++;
149*9f20bfa6SDavid van Moolenbroek } else if (p[0] == '%' && p[1] == 'm') {
150*9f20bfa6SDavid van Moolenbroek if (serr == NULL)
151*9f20bfa6SDavid van Moolenbroek serr = strerror(serrno);
152*9f20bfa6SDavid van Moolenbroek fmt_wrote = strlcpy(fp, serr, fmt_left);
153*9f20bfa6SDavid van Moolenbroek if (fmt_wrote > fmt_left)
154*9f20bfa6SDavid van Moolenbroek break;
155*9f20bfa6SDavid van Moolenbroek fp += fmt_wrote;
156*9f20bfa6SDavid van Moolenbroek fmt_left -= fmt_wrote;
157*9f20bfa6SDavid van Moolenbroek p++;
158*9f20bfa6SDavid van Moolenbroek } else {
159*9f20bfa6SDavid van Moolenbroek *fp++ = *p;
160*9f20bfa6SDavid van Moolenbroek --fmt_left;
161*9f20bfa6SDavid van Moolenbroek }
162*9f20bfa6SDavid van Moolenbroek if (fmt_left == 0)
163*9f20bfa6SDavid van Moolenbroek break;
164*9f20bfa6SDavid van Moolenbroek }
165*9f20bfa6SDavid van Moolenbroek *fp++ = '\0';
166*9f20bfa6SDavid van Moolenbroek fmt = fmt_cpy;
167*9f20bfa6SDavid van Moolenbroek }
168*9f20bfa6SDavid van Moolenbroek
169*9f20bfa6SDavid van Moolenbroek #endif
170*9f20bfa6SDavid van Moolenbroek
171*9f20bfa6SDavid van Moolenbroek if (ctx == NULL || !(ctx->options & DHCPCD_QUIET)) {
172*9f20bfa6SDavid van Moolenbroek va_list vac;
173*9f20bfa6SDavid van Moolenbroek
174*9f20bfa6SDavid van Moolenbroek va_copy(vac, va);
175*9f20bfa6SDavid van Moolenbroek vfprintf(pri <= LOG_ERR ? stderr : stdout, fmt, vac);
176*9f20bfa6SDavid van Moolenbroek fputc('\n', pri <= LOG_ERR ? stderr : stdout);
177*9f20bfa6SDavid van Moolenbroek va_end(vac);
178*9f20bfa6SDavid van Moolenbroek }
179*9f20bfa6SDavid van Moolenbroek
180*9f20bfa6SDavid van Moolenbroek #ifdef HAVE_PRINTF_M
181*9f20bfa6SDavid van Moolenbroek errno = serrno;
182*9f20bfa6SDavid van Moolenbroek #endif
183*9f20bfa6SDavid van Moolenbroek if (ctx && ctx->log_fd != -1) {
184*9f20bfa6SDavid van Moolenbroek struct timeval tv;
185*9f20bfa6SDavid van Moolenbroek char buf[32];
186*9f20bfa6SDavid van Moolenbroek
187*9f20bfa6SDavid van Moolenbroek /* Write the time, syslog style. month day time - */
188*9f20bfa6SDavid van Moolenbroek if (gettimeofday(&tv, NULL) != -1) {
189*9f20bfa6SDavid van Moolenbroek time_t now;
190*9f20bfa6SDavid van Moolenbroek struct tm tmnow;
191*9f20bfa6SDavid van Moolenbroek
192*9f20bfa6SDavid van Moolenbroek tzset();
193*9f20bfa6SDavid van Moolenbroek now = tv.tv_sec;
194*9f20bfa6SDavid van Moolenbroek localtime_r(&now, &tmnow);
195*9f20bfa6SDavid van Moolenbroek strftime(buf, sizeof(buf), "%b %d %T ", &tmnow);
196*9f20bfa6SDavid van Moolenbroek dprintf(ctx->log_fd, "%s", buf);
197*9f20bfa6SDavid van Moolenbroek }
198*9f20bfa6SDavid van Moolenbroek
199*9f20bfa6SDavid van Moolenbroek vdprintf(ctx->log_fd, fmt, va);
200*9f20bfa6SDavid van Moolenbroek dprintf(ctx->log_fd, "\n");
201*9f20bfa6SDavid van Moolenbroek } else
202*9f20bfa6SDavid van Moolenbroek vsyslog(pri, fmt, va);
203*9f20bfa6SDavid van Moolenbroek va_end(va);
204*9f20bfa6SDavid van Moolenbroek }
205*9f20bfa6SDavid van Moolenbroek #endif
206*9f20bfa6SDavid van Moolenbroek
207*9f20bfa6SDavid van Moolenbroek ssize_t
setvar(struct dhcpcd_ctx * ctx,char ** e,const char * prefix,const char * var,const char * value)208*9f20bfa6SDavid van Moolenbroek setvar(struct dhcpcd_ctx *ctx,
209*9f20bfa6SDavid van Moolenbroek char **e, const char *prefix, const char *var, const char *value)
210*9f20bfa6SDavid van Moolenbroek {
211*9f20bfa6SDavid van Moolenbroek size_t len = strlen(var) + strlen(value) + 3;
212*9f20bfa6SDavid van Moolenbroek
213*9f20bfa6SDavid van Moolenbroek if (prefix)
214*9f20bfa6SDavid van Moolenbroek len += strlen(prefix) + 1;
215*9f20bfa6SDavid van Moolenbroek *e = malloc(len);
216*9f20bfa6SDavid van Moolenbroek if (*e == NULL) {
217*9f20bfa6SDavid van Moolenbroek logger(ctx, LOG_ERR, "%s: %m", __func__);
218*9f20bfa6SDavid van Moolenbroek return -1;
219*9f20bfa6SDavid van Moolenbroek }
220*9f20bfa6SDavid van Moolenbroek if (prefix)
221*9f20bfa6SDavid van Moolenbroek snprintf(*e, len, "%s_%s=%s", prefix, var, value);
222*9f20bfa6SDavid van Moolenbroek else
223*9f20bfa6SDavid van Moolenbroek snprintf(*e, len, "%s=%s", var, value);
224*9f20bfa6SDavid van Moolenbroek return (ssize_t)len;
225*9f20bfa6SDavid van Moolenbroek }
226*9f20bfa6SDavid van Moolenbroek
227*9f20bfa6SDavid van Moolenbroek ssize_t
setvard(struct dhcpcd_ctx * ctx,char ** e,const char * prefix,const char * var,size_t value)228*9f20bfa6SDavid van Moolenbroek setvard(struct dhcpcd_ctx *ctx,
229*9f20bfa6SDavid van Moolenbroek char **e, const char *prefix, const char *var, size_t value)
230*9f20bfa6SDavid van Moolenbroek {
231*9f20bfa6SDavid van Moolenbroek
232*9f20bfa6SDavid van Moolenbroek char buffer[32];
233*9f20bfa6SDavid van Moolenbroek
234*9f20bfa6SDavid van Moolenbroek snprintf(buffer, sizeof(buffer), "%zu", value);
235*9f20bfa6SDavid van Moolenbroek return setvar(ctx, e, prefix, var, buffer);
236*9f20bfa6SDavid van Moolenbroek }
237*9f20bfa6SDavid van Moolenbroek
238*9f20bfa6SDavid van Moolenbroek ssize_t
addvar(struct dhcpcd_ctx * ctx,char *** e,const char * prefix,const char * var,const char * value)239*9f20bfa6SDavid van Moolenbroek addvar(struct dhcpcd_ctx *ctx,
240*9f20bfa6SDavid van Moolenbroek char ***e, const char *prefix, const char *var, const char *value)
241*9f20bfa6SDavid van Moolenbroek {
242*9f20bfa6SDavid van Moolenbroek ssize_t len;
243*9f20bfa6SDavid van Moolenbroek
244*9f20bfa6SDavid van Moolenbroek len = setvar(ctx, *e, prefix, var, value);
245*9f20bfa6SDavid van Moolenbroek if (len != -1)
246*9f20bfa6SDavid van Moolenbroek (*e)++;
247*9f20bfa6SDavid van Moolenbroek return (ssize_t)len;
248*9f20bfa6SDavid van Moolenbroek }
249*9f20bfa6SDavid van Moolenbroek
250*9f20bfa6SDavid van Moolenbroek ssize_t
addvard(struct dhcpcd_ctx * ctx,char *** e,const char * prefix,const char * var,size_t value)251*9f20bfa6SDavid van Moolenbroek addvard(struct dhcpcd_ctx *ctx,
252*9f20bfa6SDavid van Moolenbroek char ***e, const char *prefix, const char *var, size_t value)
253*9f20bfa6SDavid van Moolenbroek {
254*9f20bfa6SDavid van Moolenbroek char buffer[32];
255*9f20bfa6SDavid van Moolenbroek
256*9f20bfa6SDavid van Moolenbroek snprintf(buffer, sizeof(buffer), "%zu", value);
257*9f20bfa6SDavid van Moolenbroek return addvar(ctx, e, prefix, var, buffer);
258*9f20bfa6SDavid van Moolenbroek }
259*9f20bfa6SDavid van Moolenbroek
260*9f20bfa6SDavid van Moolenbroek char *
hwaddr_ntoa(const unsigned char * hwaddr,size_t hwlen,char * buf,size_t buflen)261*9f20bfa6SDavid van Moolenbroek hwaddr_ntoa(const unsigned char *hwaddr, size_t hwlen, char *buf, size_t buflen)
262*9f20bfa6SDavid van Moolenbroek {
263*9f20bfa6SDavid van Moolenbroek char *p;
264*9f20bfa6SDavid van Moolenbroek size_t i;
265*9f20bfa6SDavid van Moolenbroek
266*9f20bfa6SDavid van Moolenbroek if (buf == NULL) {
267*9f20bfa6SDavid van Moolenbroek return NULL;
268*9f20bfa6SDavid van Moolenbroek }
269*9f20bfa6SDavid van Moolenbroek
270*9f20bfa6SDavid van Moolenbroek if (hwlen * 3 > buflen) {
271*9f20bfa6SDavid van Moolenbroek errno = ENOBUFS;
272*9f20bfa6SDavid van Moolenbroek return 0;
273*9f20bfa6SDavid van Moolenbroek }
274*9f20bfa6SDavid van Moolenbroek
275*9f20bfa6SDavid van Moolenbroek p = buf;
276*9f20bfa6SDavid van Moolenbroek for (i = 0; i < hwlen; i++) {
277*9f20bfa6SDavid van Moolenbroek if (i > 0)
278*9f20bfa6SDavid van Moolenbroek *p ++= ':';
279*9f20bfa6SDavid van Moolenbroek p += snprintf(p, 3, "%.2x", hwaddr[i]);
280*9f20bfa6SDavid van Moolenbroek }
281*9f20bfa6SDavid van Moolenbroek *p ++= '\0';
282*9f20bfa6SDavid van Moolenbroek return buf;
283*9f20bfa6SDavid van Moolenbroek }
284*9f20bfa6SDavid van Moolenbroek
285*9f20bfa6SDavid van Moolenbroek size_t
hwaddr_aton(unsigned char * buffer,const char * addr)286*9f20bfa6SDavid van Moolenbroek hwaddr_aton(unsigned char *buffer, const char *addr)
287*9f20bfa6SDavid van Moolenbroek {
288*9f20bfa6SDavid van Moolenbroek char c[3];
289*9f20bfa6SDavid van Moolenbroek const char *p = addr;
290*9f20bfa6SDavid van Moolenbroek unsigned char *bp = buffer;
291*9f20bfa6SDavid van Moolenbroek size_t len = 0;
292*9f20bfa6SDavid van Moolenbroek
293*9f20bfa6SDavid van Moolenbroek c[2] = '\0';
294*9f20bfa6SDavid van Moolenbroek while (*p) {
295*9f20bfa6SDavid van Moolenbroek c[0] = *p++;
296*9f20bfa6SDavid van Moolenbroek c[1] = *p++;
297*9f20bfa6SDavid van Moolenbroek /* Ensure that digits are hex */
298*9f20bfa6SDavid van Moolenbroek if (isxdigit((unsigned char)c[0]) == 0 ||
299*9f20bfa6SDavid van Moolenbroek isxdigit((unsigned char)c[1]) == 0)
300*9f20bfa6SDavid van Moolenbroek {
301*9f20bfa6SDavid van Moolenbroek errno = EINVAL;
302*9f20bfa6SDavid van Moolenbroek return 0;
303*9f20bfa6SDavid van Moolenbroek }
304*9f20bfa6SDavid van Moolenbroek /* We should have at least two entries 00:01 */
305*9f20bfa6SDavid van Moolenbroek if (len == 0 && *p == '\0') {
306*9f20bfa6SDavid van Moolenbroek errno = EINVAL;
307*9f20bfa6SDavid van Moolenbroek return 0;
308*9f20bfa6SDavid van Moolenbroek }
309*9f20bfa6SDavid van Moolenbroek /* Ensure that next data is EOL or a seperator with data */
310*9f20bfa6SDavid van Moolenbroek if (!(*p == '\0' || (*p == ':' && *(p + 1) != '\0'))) {
311*9f20bfa6SDavid van Moolenbroek errno = EINVAL;
312*9f20bfa6SDavid van Moolenbroek return 0;
313*9f20bfa6SDavid van Moolenbroek }
314*9f20bfa6SDavid van Moolenbroek if (*p)
315*9f20bfa6SDavid van Moolenbroek p++;
316*9f20bfa6SDavid van Moolenbroek if (bp)
317*9f20bfa6SDavid van Moolenbroek *bp++ = (unsigned char)strtol(c, NULL, 16);
318*9f20bfa6SDavid van Moolenbroek len++;
319*9f20bfa6SDavid van Moolenbroek }
320*9f20bfa6SDavid van Moolenbroek return len;
321*9f20bfa6SDavid van Moolenbroek }
322