summaryrefslogtreecommitdiff
path: root/jni/src/common.c (plain)
blob: 36f644aeee95bfa44128351ff9bf83175b81975a
1/***********************************************************************
2*
3* common.c
4*
5* Implementation of user-space PPPoE redirector for Linux.
6*
7* Common functions used by PPPoE client and server
8*
9* Copyright (C) 2000 by Roaring Penguin Software Inc.
10*
11* This program may be distributed according to the terms of the GNU
12* General Public License, version 2 or (at your option) any later version.
13*
14* LIC: GPL
15*
16***********************************************************************/
17
18static char const RCSID[] =
19"$Id$";
20/* For vsnprintf prototype */
21#define _ISOC99_SOURCE 1
22
23/* For seteuid prototype */
24#define _BSD_SOURCE 1
25
26#include "pppoe.h"
27
28
29#ifdef HAVE_SYSLOG_H
30#include <syslog.h>
31#include <android/log.h>
32#define syslog(prio, fmt...) \
33 __android_log_print(prio, "PPPOE", fmt)
34#endif
35
36#include <string.h>
37#include <errno.h>
38#include <stdlib.h>
39#include <stdarg.h>
40
41#ifdef HAVE_UNISTD_H
42#include <unistd.h>
43#endif
44
45#include <sys/types.h>
46#include <pwd.h>
47
48#include "../../ppp/pppd/pathnames.h"
49/* Are we running SUID or SGID? */
50int IsSetID = 0;
51
52static uid_t saved_uid = -2;
53static uid_t saved_gid = -2;
54
55/**********************************************************************
56*%FUNCTION: parsePacket
57*%ARGUMENTS:
58* packet -- the PPPoE discovery packet to parse
59* func -- function called for each tag in the packet
60* extra -- an opaque data pointer supplied to parsing function
61*%RETURNS:
62* 0 if everything went well; -1 if there was an error
63*%DESCRIPTION:
64* Parses a PPPoE discovery packet, calling "func" for each tag in the packet.
65* "func" is passed the additional argument "extra".
66***********************************************************************/
67int
68parsePacket(PPPoEPacket *packet, ParseFunc *func, void *extra)
69{
70 UINT16_t len = ntohs(packet->length);
71 unsigned char *curTag;
72 UINT16_t tagType, tagLen;
73
74 if (packet->ver != 1) {
75 syslog(LOG_ERR, "Invalid PPPoE version (%d)", (int) packet->ver);
76 return -1;
77 }
78 if (packet->type != 1) {
79 syslog(LOG_ERR, "Invalid PPPoE type (%d)", (int) packet->type);
80 return -1;
81 }
82
83 /* Do some sanity checks on packet */
84 if (len > ETH_DATA_LEN - 6) { /* 6-byte overhead for PPPoE header */
85 syslog(LOG_ERR, "Invalid PPPoE packet length (%u)", len);
86 return -1;
87 }
88
89 /* Step through the tags */
90 curTag = packet->payload;
91 while(curTag - packet->payload < len) {
92 /* Alignment is not guaranteed, so do this by hand... */
93 tagType = (((UINT16_t) curTag[0]) << 8) +
94 (UINT16_t) curTag[1];
95 tagLen = (((UINT16_t) curTag[2]) << 8) +
96 (UINT16_t) curTag[3];
97 if (tagType == TAG_END_OF_LIST) {
98 return 0;
99 }
100 if ((curTag - packet->payload) + tagLen + TAG_HDR_SIZE > len) {
101 syslog(LOG_ERR, "Invalid PPPoE tag length (%u)", tagLen);
102 return -1;
103 }
104 func(tagType, tagLen, curTag+TAG_HDR_SIZE, extra);
105 curTag = curTag + TAG_HDR_SIZE + tagLen;
106 }
107 return 0;
108}
109
110/**********************************************************************
111*%FUNCTION: findTag
112*%ARGUMENTS:
113* packet -- the PPPoE discovery packet to parse
114* type -- the type of the tag to look for
115* tag -- will be filled in with tag contents
116*%RETURNS:
117* A pointer to the tag if one of the specified type is found; NULL
118* otherwise.
119*%DESCRIPTION:
120* Looks for a specific tag type.
121***********************************************************************/
122unsigned char *
123findTag(PPPoEPacket *packet, UINT16_t type, PPPoETag *tag)
124{
125 UINT16_t len = ntohs(packet->length);
126 unsigned char *curTag;
127 UINT16_t tagType, tagLen;
128
129 if (packet->ver != 1) {
130 syslog(LOG_ERR, "Invalid PPPoE version (%d)", (int) packet->ver);
131 return NULL;
132 }
133 if (packet->type != 1) {
134 syslog(LOG_ERR, "Invalid PPPoE type (%d)", (int) packet->type);
135 return NULL;
136 }
137
138 /* Do some sanity checks on packet */
139 if (len > ETH_DATA_LEN - 6) { /* 6-byte overhead for PPPoE header */
140 syslog(LOG_ERR, "Invalid PPPoE packet length (%u)", len);
141 return NULL;
142 }
143
144 /* Step through the tags */
145 curTag = packet->payload;
146 while(curTag - packet->payload < len) {
147 /* Alignment is not guaranteed, so do this by hand... */
148 tagType = (((UINT16_t) curTag[0]) << 8) +
149 (UINT16_t) curTag[1];
150 tagLen = (((UINT16_t) curTag[2]) << 8) +
151 (UINT16_t) curTag[3];
152 if (tagType == TAG_END_OF_LIST) {
153 return NULL;
154 }
155 if ((curTag - packet->payload) + tagLen + TAG_HDR_SIZE > len) {
156 syslog(LOG_ERR, "Invalid PPPoE tag length (%u)", tagLen);
157 return NULL;
158 }
159 if (tagType == type) {
160 memcpy(tag, curTag, tagLen + TAG_HDR_SIZE);
161 return curTag;
162 }
163 curTag = curTag + TAG_HDR_SIZE + tagLen;
164 }
165 return NULL;
166}
167
168/**********************************************************************
169*%FUNCTION: switchToRealID
170*%ARGUMENTS:
171* None
172*%RETURNS:
173* Nothing
174*%DESCRIPTION:
175* Sets effective user-ID and group-ID to real ones. Aborts on failure
176***********************************************************************/
177void
178switchToRealID (void) {
179 if (IsSetID) {
180 if ((int)saved_uid < 0) saved_uid = geteuid();
181 if ((int)saved_gid < 0) saved_gid = getegid();
182 if (setegid(getgid()) < 0) {
183 printErr("setgid failed");
184 exit(EXIT_FAILURE);
185 }
186 if (seteuid(getuid()) < 0) {
187 printErr("seteuid failed");
188 exit(EXIT_FAILURE);
189 }
190 }
191}
192
193/**********************************************************************
194*%FUNCTION: switchToEffectiveID
195*%ARGUMENTS:
196* None
197*%RETURNS:
198* Nothing
199*%DESCRIPTION:
200* Sets effective user-ID and group-ID back to saved gid/uid
201***********************************************************************/
202void
203switchToEffectiveID (void) {
204 if (IsSetID) {
205 if (setegid(saved_gid) < 0) {
206 printErr("setgid failed");
207 exit(EXIT_FAILURE);
208 }
209 if (seteuid(saved_uid) < 0) {
210 printErr("seteuid failed");
211 exit(EXIT_FAILURE);
212 }
213 }
214}
215
216/**********************************************************************
217*%FUNCTION: dropPrivs
218*%ARGUMENTS:
219* None
220*%RETURNS:
221* Nothing
222*%DESCRIPTION:
223* If effective ID is root, try to become "nobody". If that fails and
224* we're SUID, switch to real user-ID
225***********************************************************************/
226void
227dropPrivs(void)
228{
229 struct passwd *pw = NULL;
230 int ok = 0;
231 if (geteuid() == 0) {
232 pw = getpwnam("nobody");
233 if (pw) {
234 if (setgid(pw->pw_gid) < 0) ok++;
235 if (setuid(pw->pw_uid) < 0) ok++;
236 }
237 }
238 if (ok < 2 && IsSetID) {
239 setegid(getgid());
240 seteuid(getuid());
241 }
242}
243
244/**********************************************************************
245*%FUNCTION: printErr
246*%ARGUMENTS:
247* str -- error message
248*%RETURNS:
249* Nothing
250*%DESCRIPTION:
251* Prints a message to stderr and syslog.
252***********************************************************************/
253void
254printErr(char const *str)
255{
256 fprintf(stderr, "pppoe: %s\n", str);
257 syslog(LOG_ERR, "%s", str);
258}
259
260
261/**********************************************************************
262*%FUNCTION: strDup
263*%ARGUMENTS:
264* str -- string to copy
265*%RETURNS:
266* A malloc'd copy of str. Exits if malloc fails.
267***********************************************************************/
268char *
269strDup(char const *str)
270{
271 char *copy = malloc(strlen(str)+1);
272 if (!copy) {
273 rp_fatal("strdup failed");
274 }
275 strcpy(copy, str);
276 return copy;
277}
278
279/**********************************************************************
280*%FUNCTION: computeTCPChecksum
281*%ARGUMENTS:
282* ipHdr -- pointer to IP header
283* tcpHdr -- pointer to TCP header
284*%RETURNS:
285* The computed TCP checksum
286***********************************************************************/
287UINT16_t
288computeTCPChecksum(unsigned char *ipHdr, unsigned char *tcpHdr)
289{
290 UINT32_t sum = 0;
291 UINT16_t count = ipHdr[2] * 256 + ipHdr[3];
292 UINT16_t tmp;
293
294 unsigned char *addr = tcpHdr;
295 unsigned char pseudoHeader[12];
296
297 /* Count number of bytes in TCP header and data */
298 count -= (ipHdr[0] & 0x0F) * 4;
299
300 memcpy(pseudoHeader, ipHdr+12, 8);
301 pseudoHeader[8] = 0;
302 pseudoHeader[9] = ipHdr[9];
303 pseudoHeader[10] = (count >> 8) & 0xFF;
304 pseudoHeader[11] = (count & 0xFF);
305
306 /* Checksum the pseudo-header */
307 sum += * (UINT16_t *) pseudoHeader;
308 sum += * ((UINT16_t *) (pseudoHeader+2));
309 sum += * ((UINT16_t *) (pseudoHeader+4));
310 sum += * ((UINT16_t *) (pseudoHeader+6));
311 sum += * ((UINT16_t *) (pseudoHeader+8));
312 sum += * ((UINT16_t *) (pseudoHeader+10));
313
314 /* Checksum the TCP header and data */
315 while (count > 1) {
316 memcpy(&tmp, addr, sizeof(tmp));
317 sum += (UINT32_t) tmp;
318 addr += sizeof(tmp);
319 count -= sizeof(tmp);
320 }
321 if (count > 0) {
322 sum += (unsigned char) *addr;
323 }
324
325 while(sum >> 16) {
326 sum = (sum & 0xffff) + (sum >> 16);
327 }
328 return (UINT16_t) ((~sum) & 0xFFFF);
329}
330
331/**********************************************************************
332*%FUNCTION: clampMSS
333*%ARGUMENTS:
334* packet -- PPPoE session packet
335* dir -- either "incoming" or "outgoing"
336* clampMss -- clamp value
337*%RETURNS:
338* Nothing
339*%DESCRIPTION:
340* Clamps MSS option if TCP SYN flag is set.
341***********************************************************************/
342void
343clampMSS(PPPoEPacket *packet, char const *dir, int clampMss)
344{
345 unsigned char *tcpHdr;
346 unsigned char *ipHdr;
347 unsigned char *opt;
348 unsigned char *endHdr;
349 unsigned char *mssopt = NULL;
350 UINT16_t csum;
351
352 int len, minlen;
353
354 /* check PPP protocol type */
355 if (packet->payload[0] & 0x01) {
356 /* 8 bit protocol type */
357
358 /* Is it IPv4? */
359 if (packet->payload[0] != 0x21) {
360 /* Nope, ignore it */
361 return;
362 }
363
364 ipHdr = packet->payload + 1;
365 minlen = 41;
366 } else {
367 /* 16 bit protocol type */
368
369 /* Is it IPv4? */
370 if (packet->payload[0] != 0x00 ||
371 packet->payload[1] != 0x21) {
372 /* Nope, ignore it */
373 return;
374 }
375
376 ipHdr = packet->payload + 2;
377 minlen = 42;
378 }
379
380 /* Is it too short? */
381 len = (int) ntohs(packet->length);
382 if (len < minlen) {
383 /* 20 byte IP header; 20 byte TCP header; at least 1 or 2 byte PPP protocol */
384 return;
385 }
386
387 /* Verify once more that it's IPv4 */
388 if ((ipHdr[0] & 0xF0) != 0x40) {
389 return;
390 }
391
392 /* Is it a fragment that's not at the beginning of the packet? */
393 if ((ipHdr[6] & 0x1F) || ipHdr[7]) {
394 /* Yup, don't touch! */
395 return;
396 }
397 /* Is it TCP? */
398 if (ipHdr[9] != 0x06) {
399 return;
400 }
401
402 /* Get start of TCP header */
403 tcpHdr = ipHdr + (ipHdr[0] & 0x0F) * 4;
404
405 /* Is SYN set? */
406 if (!(tcpHdr[13] & 0x02)) {
407 return;
408 }
409
410 /* Compute and verify TCP checksum -- do not touch a packet with a bad
411 checksum */
412 csum = computeTCPChecksum(ipHdr, tcpHdr);
413 if (csum) {
414 syslog(LOG_ERR, "Bad TCP checksum %x", (unsigned int) csum);
415
416 /* Upper layers will drop it */
417 return;
418 }
419
420 /* Look for existing MSS option */
421 endHdr = tcpHdr + ((tcpHdr[12] & 0xF0) >> 2);
422 opt = tcpHdr + 20;
423 while (opt < endHdr) {
424 if (!*opt) break; /* End of options */
425 switch(*opt) {
426 case 1:
427 opt++;
428 break;
429
430 case 2:
431 if (opt[1] != 4) {
432 /* Something fishy about MSS option length. */
433 syslog(LOG_ERR,
434 "Bogus length for MSS option (%u) from %u.%u.%u.%u",
435 (unsigned int) opt[1],
436 (unsigned int) ipHdr[12],
437 (unsigned int) ipHdr[13],
438 (unsigned int) ipHdr[14],
439 (unsigned int) ipHdr[15]);
440 return;
441 }
442 mssopt = opt;
443 break;
444 default:
445 if (opt[1] < 2) {
446 /* Someone's trying to attack us? */
447 syslog(LOG_ERR,
448 "Bogus TCP option length (%u) from %u.%u.%u.%u",
449 (unsigned int) opt[1],
450 (unsigned int) ipHdr[12],
451 (unsigned int) ipHdr[13],
452 (unsigned int) ipHdr[14],
453 (unsigned int) ipHdr[15]);
454 return;
455 }
456 opt += (opt[1]);
457 break;
458 }
459 /* Found existing MSS option? */
460 if (mssopt) break;
461 }
462
463 /* If MSS exists and it's low enough, do nothing */
464 if (mssopt) {
465 unsigned mss = mssopt[2] * 256 + mssopt[3];
466 if (mss <= (unsigned int)clampMss) {
467 return;
468 }
469
470 mssopt[2] = (((unsigned) clampMss) >> 8) & 0xFF;
471 mssopt[3] = ((unsigned) clampMss) & 0xFF;
472 } else {
473 /* No MSS option. Don't add one; we'll have to use 536. */
474 return;
475 }
476
477 /* Recompute TCP checksum */
478 tcpHdr[16] = 0;
479 tcpHdr[17] = 0;
480 csum = computeTCPChecksum(ipHdr, tcpHdr);
481 (* (UINT16_t *) (tcpHdr+16)) = csum;
482}
483
484/***********************************************************************
485*%FUNCTION: sendPADT
486*%ARGUMENTS:
487* conn -- PPPoE connection
488* msg -- if non-NULL, extra error message to include in PADT packet.
489*%RETURNS:
490* Nothing
491*%DESCRIPTION:
492* Sends a PADT packet
493***********************************************************************/
494void
495sendPADT(PPPoEConnection *conn, char const *msg)
496{
497 PPPoEPacket packet;
498 unsigned char *cursor = packet.payload;
499
500 UINT16_t plen = 0;
501
502 /* Do nothing if no session established yet */
503 if (!conn->session) return;
504
505 /* Do nothing if no discovery socket */
506 if (conn->discoverySocket < 0) return;
507
508 memcpy(packet.ethHdr.h_dest, conn->peerEth, ETH_ALEN);
509 memcpy(packet.ethHdr.h_source, conn->myEth, ETH_ALEN);
510
511 packet.ethHdr.h_proto = htons(Eth_PPPOE_Discovery);
512 packet.ver = 1;
513 packet.type = 1;
514 packet.code = CODE_PADT;
515 packet.session = conn->session;
516
517 /* Reset Session to zero so there is no possibility of
518 recursive calls to this function by any signal handler */
519 conn->session = 0;
520
521 /* If we're using Host-Uniq, copy it over */
522 if (conn->useHostUniq) {
523 PPPoETag hostUniq;
524 pid_t pid = getpid();
525 hostUniq.type = htons(TAG_HOST_UNIQ);
526 hostUniq.length = htons(sizeof(pid));
527 memcpy(hostUniq.payload, &pid, sizeof(pid));
528 memcpy(cursor, &hostUniq, sizeof(pid) + TAG_HDR_SIZE);
529 cursor += sizeof(pid) + TAG_HDR_SIZE;
530 plen += sizeof(pid) + TAG_HDR_SIZE;
531 }
532
533 /* Copy error message */
534 if (msg) {
535 PPPoETag err;
536 size_t elen = strlen(msg);
537 err.type = htons(TAG_GENERIC_ERROR);
538 err.length = htons(elen);
539 strcpy((char *) err.payload, msg);
540 memcpy(cursor, &err, elen + TAG_HDR_SIZE);
541 cursor += elen + TAG_HDR_SIZE;
542 plen += elen + TAG_HDR_SIZE;
543 }
544
545 /* Copy cookie and relay-ID if needed */
546 if (conn->cookie.type) {
547 CHECK_ROOM(cursor, packet.payload,
548 ntohs(conn->cookie.length) + TAG_HDR_SIZE);
549 memcpy(cursor, &conn->cookie, ntohs(conn->cookie.length) + TAG_HDR_SIZE);
550 cursor += ntohs(conn->cookie.length) + TAG_HDR_SIZE;
551 plen += ntohs(conn->cookie.length) + TAG_HDR_SIZE;
552 }
553
554 if (conn->relayId.type) {
555 CHECK_ROOM(cursor, packet.payload,
556 ntohs(conn->relayId.length) + TAG_HDR_SIZE);
557 memcpy(cursor, &conn->relayId, ntohs(conn->relayId.length) + TAG_HDR_SIZE);
558 cursor += ntohs(conn->relayId.length) + TAG_HDR_SIZE;
559 plen += ntohs(conn->relayId.length) + TAG_HDR_SIZE;
560 }
561
562 packet.length = htons(plen);
563 sendPacket(conn, conn->discoverySocket, &packet, (int) (plen + HDR_SIZE));
564#ifdef DEBUGGING_ENABLED
565 if (conn->debugFile) {
566 dumpPacket(conn->debugFile, &packet, "SENT");
567 fprintf(conn->debugFile, "\n");
568 fflush(conn->debugFile);
569 }
570#endif
571 syslog(LOG_INFO,"Sent PADT");
572}
573
574
575int
576getRawSocket(char const *ifname)
577{
578 int ret;
579 int optval=1;
580 int fd;
581 struct ifreq ifr;
582 int domain, stype;
583
584 struct sockaddr_ll sa;
585
586 memset(&sa, 0, sizeof(sa));
587
588 domain = PF_PACKET;
589 stype = SOCK_RAW;
590
591 fd = socket(domain, stype, htons(ETH_PPPOE_DISCOVERY));
592 if (fd < 0) {
593 syslog(LOG_INFO,"failed to create raw socket");
594 return -1;
595 }
596
597 ret = setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval));
598 if (ret < 0) {
599 syslog(LOG_INFO,"failed to setsockopt");
600 return -1;
601 }
602
603
604 /* Get interface index */
605 sa.sll_family = AF_PACKET;
606 sa.sll_protocol = htons(ETH_PPPOE_DISCOVERY);
607
608 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
609 ret = ioctl(fd, SIOCGIFINDEX, &ifr);
610 if (ret < 0) {
611 syslog(LOG_INFO,"failed to ioctl");
612 return -1;
613 }
614 sa.sll_ifindex = ifr.ifr_ifindex;
615
616 /* We're only interested in packets on specified interface */
617 ret = bind(fd, (struct sockaddr *) &sa, sizeof(sa));
618 if (ret < 0) {
619 syslog(LOG_INFO,"failed to bind");
620 return -1;
621 }
622
623 return fd;
624}
625
626
627void
628sendSavedPADT(char *padt_file)
629{
630 FILE *file_fd = NULL;
631 char *packet;
632 long len;
633 int fd;
634
635 file_fd = fopen(padt_file, "r");
636 if (!file_fd) {
637 syslog(LOG_INFO,"failed to read padt");
638 return;
639 }
640
641 fseek(file_fd, 0, SEEK_END);
642 len = ftell(file_fd);
643 if (len < 0) {
644 goto free_file_fd;
645 }
646
647 packet = malloc(len);
648 if (!packet){
649 syslog(LOG_INFO, "sendSavedPADT: failed to malloc");
650 goto free_file_fd;
651 }
652
653 fseek(file_fd, 0, SEEK_SET);
654 fread(packet, 1, len, file_fd);
655
656 fd = getRawSocket("eth0");
657 if ( fd < 0){
658 syslog(LOG_INFO, "sendSavedPADT: failed to getRawSocket");
659 goto free_packet;
660
661 }
662 send( fd, packet, len, 0);
663 syslog(LOG_INFO, "Send SavedPADT(fd = %d) by eth0", fd);
664
665 close(fd);
666
667free_packet:
668 free(packet);
669
670free_file_fd:
671 fclose(file_fd);
672 }
673
674
675void
676savePADT(PPPoEConnection *conn, char const *msg)
677{
678 FILE *padt_file_bin = NULL;
679 PPPoEPacket packet;
680 unsigned char *cursor = packet.payload;
681
682 UINT16_t plen = 0;
683
684 memcpy(packet.ethHdr.h_dest, conn->peerEth, ETH_ALEN);
685 memcpy(packet.ethHdr.h_source, conn->myEth, ETH_ALEN);
686
687 packet.ethHdr.h_proto = htons(Eth_PPPOE_Discovery);
688 packet.ver = 1;
689 packet.type = 1;
690 packet.code = CODE_PADT;
691 packet.session = conn->session;
692
693 /* Reset Session to zero so there is no possibility of
694 recursive calls to this function by any signal handler */
695 //conn->session = 0;
696
697 /* If we're using Host-Uniq, copy it over */
698 if (conn->useHostUniq) {
699 PPPoETag hostUniq;
700 pid_t pid = getpid();
701 hostUniq.type = htons(TAG_HOST_UNIQ);
702 hostUniq.length = htons(sizeof(pid));
703 memcpy(hostUniq.payload, &pid, sizeof(pid));
704 memcpy(cursor, &hostUniq, sizeof(pid) + TAG_HDR_SIZE);
705 cursor += sizeof(pid) + TAG_HDR_SIZE;
706 plen += sizeof(pid) + TAG_HDR_SIZE;
707 }
708
709 /* Copy error message */
710 if (msg) {
711 PPPoETag err;
712 size_t elen = strlen(msg);
713 err.type = htons(TAG_GENERIC_ERROR);
714 err.length = htons(elen);
715 strcpy((char *) err.payload, msg);
716 memcpy(cursor, &err, elen + TAG_HDR_SIZE);
717 cursor += elen + TAG_HDR_SIZE;
718 plen += elen + TAG_HDR_SIZE;
719 }
720
721 packet.length = htons(plen);
722
723 padt_file_bin = fopen(_ROOT_PATH "/etc/ppp/padt_bin", "w");
724 if (!padt_file_bin) {
725 syslog(LOG_INFO,"failed to save padt_bin");
726 }
727 fwrite(&packet, (int) (plen + HDR_SIZE), 1, padt_file_bin);
728 fflush(padt_file_bin);
729 fclose(padt_file_bin);
730}
731
732/***********************************************************************
733*%FUNCTION: sendPADTf
734*%ARGUMENTS:
735* conn -- PPPoE connection
736* msg -- printf-style format string
737* args -- arguments for msg
738*%RETURNS:
739* Nothing
740*%DESCRIPTION:
741* Sends a PADT packet with a formatted message
742***********************************************************************/
743void
744sendPADTf(PPPoEConnection *conn, char const *fmt, ...)
745{
746 char msg[512];
747 va_list ap;
748
749 va_start(ap, fmt);
750 vsnprintf(msg, sizeof(msg), fmt, ap);
751 va_end(ap);
752 msg[511] = 0;
753
754 sendPADT(conn, msg);
755}
756
757/**********************************************************************
758*%FUNCTION: pktLogErrs
759*%ARGUMENTS:
760* pkt -- packet type (a string)
761* type -- tag type
762* len -- tag length
763* data -- tag data
764* extra -- extra user data
765*%RETURNS:
766* Nothing
767*%DESCRIPTION:
768* Logs error tags
769***********************************************************************/
770void
771pktLogErrs(char const *pkt,
772 UINT16_t type, UINT16_t len, unsigned char *data,
773 void *extra)
774{
775 char const *str;
776 char const *fmt = "%s: %s: %.*s";
777 switch(type) {
778 case TAG_SERVICE_NAME_ERROR:
779 str = "Service-Name-Error";
780 break;
781 case TAG_AC_SYSTEM_ERROR:
782 str = "System-Error";
783 break;
784 default:
785 str = "Generic-Error";
786 }
787
788 syslog(LOG_ERR, fmt, pkt, str, (int) len, data);
789 fprintf(stderr, fmt, pkt, str, (int) len, data);
790 fprintf(stderr, "\n");
791}
792
793/**********************************************************************
794*%FUNCTION: parseLogErrs
795*%ARGUMENTS:
796* type -- tag type
797* len -- tag length
798* data -- tag data
799* extra -- extra user data
800*%RETURNS:
801* Nothing
802*%DESCRIPTION:
803* Picks error tags out of a packet and logs them.
804***********************************************************************/
805void
806parseLogErrs(UINT16_t type, UINT16_t len, unsigned char *data,
807 void *extra)
808{
809 pktLogErrs("PADT", type, len, data, extra);
810}
811