GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: sbin/isakmpd/log.c Lines: 0 265 0.0 %
Date: 2016-12-06 Branches: 0 166 0.0 %

Line Branch Exec Source
1
/* $OpenBSD: log.c,v 1.62 2014/10/25 03:18:13 lteo Exp $	 */
2
/* $EOM: log.c,v 1.30 2000/09/29 08:19:23 niklas Exp $	 */
3
4
/*
5
 * Copyright (c) 1998, 1999, 2001 Niklas Hallqvist.  All rights reserved.
6
 * Copyright (c) 1999, 2000, 2001, 2003 Håkan Olsson.  All rights reserved.
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
 */
28
29
/*
30
 * This code was written under funding by Ericsson Radio Systems.
31
 */
32
33
#include <sys/types.h>
34
#include <sys/time.h>
35
36
#include <sys/socket.h>
37
#include <sys/stat.h>
38
#include <sys/uio.h>
39
#include <netinet/in.h>
40
#include <netinet/ip.h>
41
#include <netinet/ip6.h>
42
#include <netinet/udp.h>
43
#include <arpa/inet.h>
44
45
#include <pcap.h>
46
47
#include <errno.h>
48
#include <stdio.h>
49
#include <stdlib.h>
50
#include <string.h>
51
#include <syslog.h>
52
#include <stdarg.h>
53
#include <unistd.h>
54
55
#include "conf.h"
56
#include "isakmp_num.h"
57
#include "log.h"
58
#include "monitor.h"
59
#include "util.h"
60
61
static void	_log_print(int, int, const char *, va_list, int, int);
62
63
static FILE	*log_output;
64
65
int		verbose_logging = 0;
66
static int	log_level[LOG_ENDCLASS];
67
68
#define TCPDUMP_MAGIC	0xa1b2c3d4
69
#define SNAPLEN		(64 * 1024)
70
71
struct packhdr {
72
	struct pcap_pkthdr pcap;/* pcap file packet header */
73
	u_int32_t sa_family;	/* address family */
74
	union {
75
		struct ip       ip4;	/* IPv4 header (w/o options) */
76
		struct ip6_hdr  ip6;	/* IPv6 header */
77
	} ip;
78
};
79
80
struct isakmp_hdr {
81
	u_int8_t        icookie[8], rcookie[8];
82
	u_int8_t        next, ver, type, flags;
83
	u_int32_t       msgid, len;
84
};
85
86
static char    *pcaplog_file = NULL;
87
static FILE    *packet_log;
88
static u_int8_t *packet_buf = NULL;
89
90
static int      udp_cksum(struct packhdr *, const struct udphdr *,
91
    u_int16_t *);
92
static u_int16_t in_cksum(const u_int16_t *, int);
93
94
void
95
log_init(int debug)
96
{
97
	if (debug)
98
		log_output = stderr;
99
	else
100
		log_to(0);	/* syslog */
101
}
102
103
void
104
log_reinit(void)
105
{
106
	struct conf_list *logging;
107
	struct conf_list_node *logclass;
108
	int		class, level;
109
110
	logging = conf_get_list("General", "Logverbose");
111
	if (logging) {
112
		verbose_logging = 1;
113
		conf_free_list(logging);
114
	}
115
	logging = conf_get_list("General", "Loglevel");
116
	if (!logging)
117
		return;
118
119
	for (logclass = TAILQ_FIRST(&logging->fields); logclass;
120
	    logclass = TAILQ_NEXT(logclass, link)) {
121
		if (sscanf(logclass->field, "%d=%d", &class, &level) != 2) {
122
			if (sscanf(logclass->field, "A=%d", &level) == 1)
123
				for (class = 0; class < LOG_ENDCLASS; class++)
124
					log_debug_cmd(class, level);
125
			else {
126
				log_print("init: invalid logging class or "
127
				    "level: %s", logclass->field);
128
				continue;
129
			}
130
		} else
131
			log_debug_cmd(class, level);
132
	}
133
	conf_free_list(logging);
134
}
135
136
void
137
log_to(FILE *f)
138
{
139
	if (!log_output && f)
140
		closelog();
141
	log_output = f;
142
	if (!f)
143
		openlog("isakmpd", LOG_PID | LOG_CONS, LOG_DAEMON);
144
}
145
146
FILE *
147
log_current(void)
148
{
149
	return log_output;
150
}
151
152
static char *
153
_log_get_class(int error_class)
154
{
155
	/* XXX For test purposes. To be removed later on?  */
156
	static char	*class_text[] = LOG_CLASSES_TEXT;
157
158
	if (error_class < 0)
159
		return "Dflt";
160
	else if (error_class >= LOG_ENDCLASS)
161
		return "Unkn";
162
	else
163
		return class_text[error_class];
164
}
165
166
static void
167
_log_print(int error, int syslog_level, const char *fmt, va_list ap,
168
    int class, int level)
169
{
170
	char		buffer[LOG_SIZE], nbuf[LOG_SIZE + 32];
171
	static const char fallback_msg[] =
172
	    "write to log file failed (errno %d), redirecting to syslog";
173
	int		len;
174
	struct tm      *tm;
175
	struct timeval  now;
176
	time_t          t;
177
178
	len = vsnprintf(buffer, sizeof buffer, fmt, ap);
179
	if (len > 0 && len < (int) sizeof buffer - 1 && error)
180
		snprintf(buffer + len, sizeof buffer - len, ": %s",
181
		    strerror(errno));
182
	if (log_output) {
183
		gettimeofday(&now, 0);
184
		t = now.tv_sec;
185
		tm = localtime(&t);
186
		if (class >= 0)
187
			snprintf(nbuf, sizeof nbuf,
188
			    "%02d%02d%02d.%06ld %s %02d ",
189
			    tm->tm_hour, tm->tm_min, tm->tm_sec, now.tv_usec,
190
			    _log_get_class(class), level);
191
		else /* LOG_PRINT (-1) or LOG_REPORT (-2) */
192
			snprintf(nbuf, sizeof nbuf, "%02d%02d%02d.%06ld %s ",
193
			    tm->tm_hour, tm->tm_min, tm->tm_sec, now.tv_usec,
194
			    class == LOG_PRINT ? "Default" : "Report>");
195
		strlcat(nbuf, buffer, sizeof nbuf);
196
		strlcat(nbuf, getuid() ? "" : " [priv]", LOG_SIZE + 32);
197
		strlcat(nbuf, "\n", sizeof nbuf);
198
199
		if (fwrite(nbuf, strlen(nbuf), 1, log_output) == 0) {
200
			/* Report fallback.  */
201
			syslog(LOG_ALERT, fallback_msg, errno);
202
			fprintf(log_output, fallback_msg, errno);
203
204
			/*
205
			 * Close log_output to prevent isakmpd from locking
206
			 * the file.  We may need to explicitly close stdout
207
			 * to do this properly.
208
			 * XXX - Figure out how to match two FILE *'s and
209
			 * rewrite.
210
			 */
211
			if (fileno(log_output) != -1 &&
212
			    fileno(stdout) == fileno(log_output))
213
				fclose(stdout);
214
			fclose(log_output);
215
216
			/* Fallback to syslog.  */
217
			log_to(0);
218
219
			/* (Re)send current message to syslog().  */
220
			syslog(class == LOG_REPORT ? LOG_ALERT :
221
			    syslog_level, "%s", buffer);
222
		}
223
	} else
224
		syslog(class == LOG_REPORT ? LOG_ALERT : syslog_level, "%s",
225
		    buffer);
226
}
227
228
void
229
log_debug(int cls, int level, const char *fmt, ...)
230
{
231
	va_list         ap;
232
233
	/*
234
	 * If we are not debugging this class, or the level is too low, just
235
	 * return.
236
         */
237
	if (cls >= 0 && (log_level[cls] == 0 || level > log_level[cls]))
238
		return;
239
	va_start(ap, fmt);
240
	_log_print(0, LOG_INFO, fmt, ap, cls, level);
241
	va_end(ap);
242
}
243
244
void
245
log_debug_buf(int cls, int level, const char *header, const u_int8_t *buf,
246
    size_t sz)
247
{
248
	size_t	i, j;
249
	char	s[73];
250
251
	/*
252
	 * If we are not debugging this class, or the level is too low, just
253
	 * return.
254
         */
255
	if (cls >= 0 && (log_level[cls] == 0 || level > log_level[cls]))
256
		return;
257
258
	log_debug(cls, level, "%s:", header);
259
	for (i = j = 0; i < sz;) {
260
		snprintf(s + j, sizeof s - j, "%02x", buf[i++]);
261
		j += strlen(s + j);
262
		if (i % 4 == 0) {
263
			if (i % 32 == 0) {
264
				s[j] = '\0';
265
				log_debug(cls, level, "%s", s);
266
				j = 0;
267
			} else
268
				s[j++] = ' ';
269
		}
270
	}
271
	if (j) {
272
		s[j] = '\0';
273
		log_debug(cls, level, "%s", s);
274
	}
275
}
276
277
void
278
log_debug_cmd(int cls, int level)
279
{
280
	if (cls < 0 || cls >= LOG_ENDCLASS) {
281
		log_print("log_debug_cmd: invalid debugging class %d", cls);
282
		return;
283
	}
284
	if (level < 0) {
285
		log_print("log_debug_cmd: invalid debugging level %d for "
286
		    "class %d", level, cls);
287
		return;
288
	}
289
	if (level == log_level[cls])
290
		log_print("log_debug_cmd: log level unchanged for class %d",
291
		    cls);
292
	else {
293
		log_print("log_debug_cmd: log level changed from %d to %d "
294
		    "for class %d", log_level[cls], level, cls);
295
		log_level[cls] = level;
296
	}
297
}
298
299
void
300
log_debug_toggle(void)
301
{
302
	static int	log_level_copy[LOG_ENDCLASS], toggle = 0;
303
304
	if (!toggle) {
305
		LOG_DBG((LOG_MISC, 50, "log_debug_toggle: "
306
		    "debug levels cleared"));
307
		memcpy(&log_level_copy, &log_level, sizeof log_level);
308
		bzero(&log_level, sizeof log_level);
309
	} else {
310
		memcpy(&log_level, &log_level_copy, sizeof log_level);
311
		LOG_DBG((LOG_MISC, 50, "log_debug_toggle: "
312
		    "debug levels restored"));
313
	}
314
	toggle = !toggle;
315
}
316
317
void
318
log_print(const char *fmt, ...)
319
{
320
	va_list	ap;
321
322
	va_start(ap, fmt);
323
	_log_print(0, LOG_NOTICE, fmt, ap, LOG_PRINT, 0);
324
	va_end(ap);
325
}
326
327
void
328
log_verbose(const char *fmt, ...)
329
{
330
	va_list	ap;
331
332
	if (verbose_logging == 0)
333
		return;
334
335
	va_start(ap, fmt);
336
	_log_print(0, LOG_NOTICE, fmt, ap, LOG_PRINT, 0);
337
	va_end(ap);
338
}
339
340
void
341
log_error(const char *fmt, ...)
342
{
343
	va_list	ap;
344
345
	va_start(ap, fmt);
346
	_log_print(1, LOG_ERR, fmt, ap, LOG_PRINT, 0);
347
	va_end(ap);
348
}
349
350
void
351
log_errorx(const char *fmt, ...)
352
{
353
	va_list ap;
354
355
	va_start(ap, fmt);
356
	_log_print(0, LOG_ERR, fmt, ap, LOG_PRINT, 0);
357
	va_end(ap);
358
}
359
360
void
361
log_fatal(const char *fmt, ...)
362
{
363
	va_list	ap;
364
365
	va_start(ap, fmt);
366
	_log_print(1, LOG_CRIT, fmt, ap, LOG_PRINT, 0);
367
	va_end(ap);
368
	monitor_exit(1);
369
}
370
371
void
372
log_fatalx(const char *fmt, ...)
373
{
374
	va_list	ap;
375
376
	va_start(ap, fmt);
377
	_log_print(0, LOG_CRIT, fmt, ap, LOG_PRINT, 0);
378
	va_end(ap);
379
	monitor_exit(1);
380
}
381
382
void
383
log_packet_init(char *newname)
384
{
385
	struct pcap_file_header sf_hdr;
386
	struct stat     st;
387
	mode_t          old_umask;
388
	char           *mode;
389
390
	/* Allocate packet buffer first time through.  */
391
	if (!packet_buf)
392
		packet_buf = malloc(SNAPLEN);
393
394
	if (!packet_buf) {
395
		log_error("log_packet_init: malloc (%d) failed", SNAPLEN);
396
		return;
397
	}
398
	if (pcaplog_file && strcmp(pcaplog_file, PCAP_FILE_DEFAULT) != 0)
399
		free(pcaplog_file);
400
401
	pcaplog_file = strdup(newname);
402
	if (!pcaplog_file) {
403
		log_error("log_packet_init: strdup (\"%s\") failed", newname);
404
		return;
405
	}
406
	/* Does the file already exist?  XXX lstat() or stat()?  */
407
	/* XXX This is a fstat! */
408
	if (monitor_stat(pcaplog_file, &st) == 0) {
409
		/* Sanity checks.  */
410
		if (!S_ISREG(st.st_mode)) {
411
			log_print("log_packet_init: existing capture file is "
412
			    "not a regular file");
413
			return;
414
		}
415
		if ((st.st_mode & (S_IRWXG | S_IRWXO)) != 0) {
416
			log_print("log_packet_init: existing capture "
417
			    "file has bad modes");
418
			return;
419
		}
420
		/*
421
		 * XXX It would be nice to check if it actually is a pcap
422
		 * file...
423
		 */
424
425
		mode = "a";
426
	} else
427
		mode = "w";
428
429
	old_umask = umask(S_IRWXG | S_IRWXO);
430
	packet_log = monitor_fopen(pcaplog_file, mode);
431
	umask(old_umask);
432
433
	if (!packet_log) {
434
		log_error("log_packet_init: fopen (\"%s\", \"%s\") failed",
435
		    pcaplog_file, mode);
436
		return;
437
	}
438
	log_print("log_packet_init: "
439
	    "starting IKE packet capture to file \"%s\"", pcaplog_file);
440
441
	/* If this is a new file, we need to write a PCAP header to it.  */
442
	if (*mode == 'w') {
443
		sf_hdr.magic = TCPDUMP_MAGIC;
444
		sf_hdr.version_major = PCAP_VERSION_MAJOR;
445
		sf_hdr.version_minor = PCAP_VERSION_MINOR;
446
		sf_hdr.thiszone = 0;
447
		sf_hdr.snaplen = SNAPLEN;
448
		sf_hdr.sigfigs = 0;
449
		sf_hdr.linktype = DLT_LOOP;
450
451
		fwrite((char *) &sf_hdr, sizeof sf_hdr, 1, packet_log);
452
		fflush(packet_log);
453
	}
454
}
455
456
void
457
log_packet_restart(char *newname)
458
{
459
	if (packet_log) {
460
		log_print("log_packet_restart: capture already active on "
461
		    "file \"%s\"", pcaplog_file);
462
		return;
463
	}
464
	if (newname)
465
		log_packet_init(newname);
466
	else if (!pcaplog_file)
467
		log_packet_init(PCAP_FILE_DEFAULT);
468
	else
469
		log_packet_init(pcaplog_file);
470
}
471
472
void
473
log_packet_stop(void)
474
{
475
	/* Stop capture.  */
476
	if (packet_log) {
477
		fclose(packet_log);
478
		log_print("log_packet_stop: stopped capture");
479
	}
480
	packet_log = 0;
481
}
482
483
void
484
log_packet_iov(struct sockaddr *src, struct sockaddr *dst, struct iovec *iov,
485
    int iovcnt)
486
{
487
	struct isakmp_hdr *isakmphdr;
488
	struct packhdr  hdr;
489
	struct udphdr   udp;
490
	struct timeval  tv;
491
	int             off, datalen, hdrlen, i, add_espmarker = 0;
492
	const u_int32_t	espmarker = 0;
493
494
	for (i = 0, datalen = 0; i < iovcnt; i++)
495
		datalen += iov[i].iov_len;
496
497
	if (!packet_log || datalen > SNAPLEN)
498
		return;
499
500
	/* copy packet into buffer */
501
	for (i = 0, off = 0; i < iovcnt; i++) {
502
		memcpy(packet_buf + off, iov[i].iov_base, iov[i].iov_len);
503
		off += iov[i].iov_len;
504
	}
505
506
	bzero(&hdr, sizeof hdr);
507
	bzero(&udp, sizeof udp);
508
509
	/* isakmp - turn off the encryption bit in the isakmp hdr */
510
	isakmphdr = (struct isakmp_hdr *) packet_buf;
511
	isakmphdr->flags &= ~(ISAKMP_FLAGS_ENC);
512
513
	/* udp */
514
	udp.uh_sport = sockaddr_port(src);
515
	udp.uh_dport = sockaddr_port(dst);
516
	datalen += sizeof udp;
517
	if (ntohs(udp.uh_sport) == 4500 ||
518
	    ntohs(udp.uh_dport) == 4500) { /* XXX Quick and dirty */
519
		add_espmarker = 1;
520
		datalen += sizeof espmarker;
521
	}
522
	udp.uh_ulen = htons(datalen);
523
524
	/* ip */
525
	hdr.sa_family = htonl(src->sa_family);
526
	switch (src->sa_family) {
527
	default:
528
		/* Assume IPv4. XXX Can 'default' ever happen here?  */
529
		hdr.sa_family = htonl(AF_INET);
530
		hdr.ip.ip4.ip_src.s_addr = 0x02020202;
531
		hdr.ip.ip4.ip_dst.s_addr = 0x01010101;
532
		/* The rest of the setup is common to AF_INET.  */
533
		goto setup_ip4;
534
535
	case AF_INET:
536
		hdr.ip.ip4.ip_src.s_addr =
537
		    ((struct sockaddr_in *)src)->sin_addr.s_addr;
538
		hdr.ip.ip4.ip_dst.s_addr =
539
		    ((struct sockaddr_in *)dst)->sin_addr.s_addr;
540
541
setup_ip4:
542
		hdrlen = sizeof hdr.ip.ip4;
543
		hdr.ip.ip4.ip_v = 0x4;
544
		hdr.ip.ip4.ip_hl = 0x5;
545
		hdr.ip.ip4.ip_p = IPPROTO_UDP;
546
		hdr.ip.ip4.ip_len = htons(datalen + hdrlen);
547
		/* Let's use the IP ID as a "packet counter".  */
548
		i = ntohs(hdr.ip.ip4.ip_id) + 1;
549
		hdr.ip.ip4.ip_id = htons(i);
550
		/* Calculate IP header checksum. */
551
		hdr.ip.ip4.ip_sum = in_cksum((u_int16_t *) & hdr.ip.ip4,
552
		    hdr.ip.ip4.ip_hl << 2);
553
		break;
554
555
	case AF_INET6:
556
		hdrlen = sizeof(hdr.ip.ip6);
557
		hdr.ip.ip6.ip6_vfc = IPV6_VERSION;
558
		hdr.ip.ip6.ip6_nxt = IPPROTO_UDP;
559
		hdr.ip.ip6.ip6_plen = udp.uh_ulen;
560
		memcpy(&hdr.ip.ip6.ip6_src,
561
		    &((struct sockaddr_in6 *)src)->sin6_addr,
562
		    sizeof hdr.ip.ip6.ip6_src);
563
		memcpy(&hdr.ip.ip6.ip6_dst,
564
		    &((struct sockaddr_in6 *)dst)->sin6_addr,
565
		    sizeof hdr.ip.ip6.ip6_dst);
566
		break;
567
	}
568
569
	/* Calculate UDP checksum.  */
570
	udp.uh_sum = udp_cksum(&hdr, &udp, (u_int16_t *) packet_buf);
571
	hdrlen += sizeof hdr.sa_family;
572
573
	/* pcap file packet header */
574
	gettimeofday(&tv, 0);
575
	hdr.pcap.ts.tv_sec = tv.tv_sec;
576
	hdr.pcap.ts.tv_usec = tv.tv_usec;
577
	hdr.pcap.caplen = datalen + hdrlen;
578
	hdr.pcap.len = datalen + hdrlen;
579
580
	hdrlen += sizeof(struct pcap_pkthdr);
581
	datalen -= sizeof(struct udphdr);
582
583
	/* Write to pcap file.  */
584
	fwrite(&hdr, hdrlen, 1, packet_log);	/* pcap + IP */
585
	fwrite(&udp, sizeof(struct udphdr), 1, packet_log);	/* UDP */
586
	if (add_espmarker) {
587
		fwrite(&espmarker, sizeof espmarker, 1, packet_log);
588
		datalen -= sizeof espmarker;
589
	}
590
	fwrite(packet_buf, datalen, 1, packet_log);	/* IKE-data */
591
	fflush(packet_log);
592
}
593
594
/* Copied from tcpdump/print-udp.c, mostly rewritten.  */
595
static int
596
udp_cksum(struct packhdr *hdr, const struct udphdr *u, u_int16_t *d)
597
{
598
	struct ip	*ip4;
599
	struct ip6_hdr	*ip6;
600
	int	i, hdrlen, tlen = ntohs(u->uh_ulen) - sizeof(struct udphdr);
601
602
	union phu {
603
		struct ip4pseudo {
604
			struct in_addr  src;
605
			struct in_addr  dst;
606
			u_int8_t        z;
607
			u_int8_t        proto;
608
			u_int16_t       len;
609
		} ip4p;
610
		struct ip6pseudo {
611
			struct in6_addr src;
612
			struct in6_addr dst;
613
			u_int32_t       plen;
614
			u_int16_t       z0;
615
			u_int8_t        z1;
616
			u_int8_t        nxt;
617
		} ip6p;
618
		u_int16_t       pa[20];
619
	} phu;
620
	const u_int16_t *sp;
621
	u_int32_t       sum;
622
623
	/* Setup pseudoheader.  */
624
	bzero(phu.pa, sizeof phu);
625
	switch (ntohl(hdr->sa_family)) {
626
	case AF_INET:
627
		ip4 = &hdr->ip.ip4;
628
		memcpy(&phu.ip4p.src, &ip4->ip_src, sizeof(struct in_addr));
629
		memcpy(&phu.ip4p.dst, &ip4->ip_dst, sizeof(struct in_addr));
630
		phu.ip4p.proto = ip4->ip_p;
631
		phu.ip4p.len = u->uh_ulen;
632
		hdrlen = sizeof phu.ip4p;
633
		break;
634
635
	case AF_INET6:
636
		ip6 = &hdr->ip.ip6;
637
		memcpy(&phu.ip6p.src, &ip6->ip6_src, sizeof(phu.ip6p.src));
638
		memcpy(&phu.ip6p.dst, &ip6->ip6_dst, sizeof(phu.ip6p.dst));
639
		phu.ip6p.plen = u->uh_ulen;
640
		phu.ip6p.nxt = ip6->ip6_nxt;
641
		hdrlen = sizeof phu.ip6p;
642
		break;
643
644
	default:
645
		return 0;
646
	}
647
648
	/* IPv6 wants a 0xFFFF checksum "on error", not 0x0.  */
649
	if (tlen < 0)
650
		return (ntohl(hdr->sa_family) == AF_INET ? 0 : 0xFFFF);
651
652
	sum = 0;
653
	for (i = 0; i < hdrlen; i += 2)
654
		sum += phu.pa[i / 2];
655
656
	sp = (const u_int16_t *)u;
657
	for (i = 0; i < (int)sizeof(struct udphdr); i += 2)
658
		sum += *sp++;
659
660
	sp = d;
661
	for (i = 0; i < (tlen & ~1); i += 2)
662
		sum += *sp++;
663
664
	if (tlen & 1)
665
		sum += htons((*(const char *)sp) << 8);
666
667
	while (sum > 0xffff)
668
		sum = (sum & 0xffff) + (sum >> 16);
669
	sum = ~sum & 0xffff;
670
671
	return sum;
672
}
673
674
/* Copied from tcpdump/print-ip.c, modified.  */
675
static u_int16_t
676
in_cksum(const u_int16_t *w, int len)
677
{
678
	int		nleft = len, sum = 0;
679
	u_int16_t       answer;
680
681
	while (nleft > 1) {
682
		sum += *w++;
683
		nleft -= 2;
684
	}
685
	if (nleft == 1)
686
		sum += htons(*(const u_char *)w << 8);
687
688
	sum = (sum >> 16) + (sum & 0xffff);	/* add hi 16 to low 16 */
689
	sum += (sum >> 16);	/* add carry */
690
	answer = ~sum;		/* truncate to 16 bits */
691
	return answer;
692
}