Annotation of embedaddon/quagga/lib/sockunion.c, revision 1.1.1.1
1.1 misho 1: /* Socket union related function.
2: * Copyright (c) 1997, 98 Kunihiro Ishiguro
3: *
4: * This file is part of GNU Zebra.
5: *
6: * GNU Zebra is free software; you can redistribute it and/or modify it
7: * under the terms of the GNU General Public License as published by the
8: * Free Software Foundation; either version 2, or (at your option) any
9: * later version.
10: *
11: * GNU Zebra is distributed in the hope that it will be useful, but
12: * WITHOUT ANY WARRANTY; without even the implied warranty of
13: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14: * General Public License for more details.
15: *
16: * You should have received a copy of the GNU General Public License
17: * along with GNU Zebra; see the file COPYING. If not, write to the Free
18: * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19: * 02111-1307, USA.
20: */
21:
22: #include <zebra.h>
23:
24: #include "prefix.h"
25: #include "vty.h"
26: #include "sockunion.h"
27: #include "memory.h"
28: #include "str.h"
29: #include "log.h"
30:
31: #ifndef HAVE_INET_ATON
32: int
33: inet_aton (const char *cp, struct in_addr *inaddr)
34: {
35: int dots = 0;
36: register u_long addr = 0;
37: register u_long val = 0, base = 10;
38:
39: do
40: {
41: register char c = *cp;
42:
43: switch (c)
44: {
45: case '0': case '1': case '2': case '3': case '4': case '5':
46: case '6': case '7': case '8': case '9':
47: val = (val * base) + (c - '0');
48: break;
49: case '.':
50: if (++dots > 3)
51: return 0;
52: case '\0':
53: if (val > 255)
54: return 0;
55: addr = addr << 8 | val;
56: val = 0;
57: break;
58: default:
59: return 0;
60: }
61: } while (*cp++) ;
62:
63: if (dots < 3)
64: addr <<= 8 * (3 - dots);
65: if (inaddr)
66: inaddr->s_addr = htonl (addr);
67: return 1;
68: }
69: #endif /* ! HAVE_INET_ATON */
70:
71:
72: #ifndef HAVE_INET_PTON
73: int
74: inet_pton (int family, const char *strptr, void *addrptr)
75: {
76: if (family == AF_INET)
77: {
78: struct in_addr in_val;
79:
80: if (inet_aton (strptr, &in_val))
81: {
82: memcpy (addrptr, &in_val, sizeof (struct in_addr));
83: return 1;
84: }
85: return 0;
86: }
87: errno = EAFNOSUPPORT;
88: return -1;
89: }
90: #endif /* ! HAVE_INET_PTON */
91:
92: #ifndef HAVE_INET_NTOP
93: const char *
94: inet_ntop (int family, const void *addrptr, char *strptr, size_t len)
95: {
96: unsigned char *p = (unsigned char *) addrptr;
97:
98: if (family == AF_INET)
99: {
100: char temp[INET_ADDRSTRLEN];
101:
102: snprintf(temp, sizeof(temp), "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
103:
104: if (strlen(temp) >= len)
105: {
106: errno = ENOSPC;
107: return NULL;
108: }
109: strcpy(strptr, temp);
110: return strptr;
111: }
112:
113: errno = EAFNOSUPPORT;
114: return NULL;
115: }
116: #endif /* ! HAVE_INET_NTOP */
117:
118: const char *
119: inet_sutop (union sockunion *su, char *str)
120: {
121: switch (su->sa.sa_family)
122: {
123: case AF_INET:
124: inet_ntop (AF_INET, &su->sin.sin_addr, str, INET_ADDRSTRLEN);
125: break;
126: #ifdef HAVE_IPV6
127: case AF_INET6:
128: inet_ntop (AF_INET6, &su->sin6.sin6_addr, str, INET6_ADDRSTRLEN);
129: break;
130: #endif /* HAVE_IPV6 */
131: }
132: return str;
133: }
134:
135: int
136: str2sockunion (const char *str, union sockunion *su)
137: {
138: int ret;
139:
140: memset (su, 0, sizeof (union sockunion));
141:
142: ret = inet_pton (AF_INET, str, &su->sin.sin_addr);
143: if (ret > 0) /* Valid IPv4 address format. */
144: {
145: su->sin.sin_family = AF_INET;
146: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
147: su->sin.sin_len = sizeof(struct sockaddr_in);
148: #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
149: return 0;
150: }
151: #ifdef HAVE_IPV6
152: ret = inet_pton (AF_INET6, str, &su->sin6.sin6_addr);
153: if (ret > 0) /* Valid IPv6 address format. */
154: {
155: su->sin6.sin6_family = AF_INET6;
156: #ifdef SIN6_LEN
157: su->sin6.sin6_len = sizeof(struct sockaddr_in6);
158: #endif /* SIN6_LEN */
159: return 0;
160: }
161: #endif /* HAVE_IPV6 */
162: return -1;
163: }
164:
165: const char *
166: sockunion2str (union sockunion *su, char *buf, size_t len)
167: {
168: if (su->sa.sa_family == AF_INET)
169: return inet_ntop (AF_INET, &su->sin.sin_addr, buf, len);
170: #ifdef HAVE_IPV6
171: else if (su->sa.sa_family == AF_INET6)
172: return inet_ntop (AF_INET6, &su->sin6.sin6_addr, buf, len);
173: #endif /* HAVE_IPV6 */
174: return NULL;
175: }
176:
177: union sockunion *
178: sockunion_str2su (const char *str)
179: {
180: int ret;
181: union sockunion *su;
182:
183: su = XCALLOC (MTYPE_SOCKUNION, sizeof (union sockunion));
184:
185: ret = inet_pton (AF_INET, str, &su->sin.sin_addr);
186: if (ret > 0) /* Valid IPv4 address format. */
187: {
188: su->sin.sin_family = AF_INET;
189: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
190: su->sin.sin_len = sizeof(struct sockaddr_in);
191: #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
192: return su;
193: }
194: #ifdef HAVE_IPV6
195: ret = inet_pton (AF_INET6, str, &su->sin6.sin6_addr);
196: if (ret > 0) /* Valid IPv6 address format. */
197: {
198: su->sin6.sin6_family = AF_INET6;
199: #ifdef SIN6_LEN
200: su->sin6.sin6_len = sizeof(struct sockaddr_in6);
201: #endif /* SIN6_LEN */
202: return su;
203: }
204: #endif /* HAVE_IPV6 */
205:
206: XFREE (MTYPE_SOCKUNION, su);
207: return NULL;
208: }
209:
210: char *
211: sockunion_su2str (union sockunion *su)
212: {
213: char str[SU_ADDRSTRLEN];
214:
215: switch (su->sa.sa_family)
216: {
217: case AF_INET:
218: inet_ntop (AF_INET, &su->sin.sin_addr, str, sizeof (str));
219: break;
220: #ifdef HAVE_IPV6
221: case AF_INET6:
222: inet_ntop (AF_INET6, &su->sin6.sin6_addr, str, sizeof (str));
223: break;
224: #endif /* HAVE_IPV6 */
225: }
226: return XSTRDUP (MTYPE_TMP, str);
227: }
228:
229: /* Convert IPv4 compatible IPv6 address to IPv4 address. */
230: static void
231: sockunion_normalise_mapped (union sockunion *su)
232: {
233: struct sockaddr_in sin;
234:
235: #ifdef HAVE_IPV6
236: if (su->sa.sa_family == AF_INET6
237: && IN6_IS_ADDR_V4MAPPED (&su->sin6.sin6_addr))
238: {
239: memset (&sin, 0, sizeof (struct sockaddr_in));
240: sin.sin_family = AF_INET;
241: sin.sin_port = su->sin6.sin6_port;
242: memcpy (&sin.sin_addr, ((char *)&su->sin6.sin6_addr) + 12, 4);
243: memcpy (su, &sin, sizeof (struct sockaddr_in));
244: }
245: #endif /* HAVE_IPV6 */
246: }
247:
248: /* Return socket of sockunion. */
249: int
250: sockunion_socket (union sockunion *su)
251: {
252: int sock;
253:
254: sock = socket (su->sa.sa_family, SOCK_STREAM, 0);
255: if (sock < 0)
256: {
257: zlog (NULL, LOG_WARNING, "Can't make socket : %s", safe_strerror (errno));
258: return -1;
259: }
260:
261: return sock;
262: }
263:
264: /* Return accepted new socket file descriptor. */
265: int
266: sockunion_accept (int sock, union sockunion *su)
267: {
268: socklen_t len;
269: int client_sock;
270:
271: len = sizeof (union sockunion);
272: client_sock = accept (sock, (struct sockaddr *) su, &len);
273:
274: sockunion_normalise_mapped (su);
275: return client_sock;
276: }
277:
278: /* Return sizeof union sockunion. */
279: static int
280: sockunion_sizeof (union sockunion *su)
281: {
282: int ret;
283:
284: ret = 0;
285: switch (su->sa.sa_family)
286: {
287: case AF_INET:
288: ret = sizeof (struct sockaddr_in);
289: break;
290: #ifdef HAVE_IPV6
291: case AF_INET6:
292: ret = sizeof (struct sockaddr_in6);
293: break;
294: #endif /* AF_INET6 */
295: }
296: return ret;
297: }
298:
299: /* return sockunion structure : this function should be revised. */
300: static char *
301: sockunion_log (union sockunion *su)
302: {
303: static char buf[SU_ADDRSTRLEN];
304:
305: switch (su->sa.sa_family)
306: {
307: case AF_INET:
308: snprintf (buf, SU_ADDRSTRLEN, "%s", inet_ntoa (su->sin.sin_addr));
309: break;
310: #ifdef HAVE_IPV6
311: case AF_INET6:
312: snprintf (buf, SU_ADDRSTRLEN, "%s",
313: inet_ntop (AF_INET6, &(su->sin6.sin6_addr), buf, SU_ADDRSTRLEN));
314: break;
315: #endif /* HAVE_IPV6 */
316: default:
317: snprintf (buf, SU_ADDRSTRLEN, "af_unknown %d ", su->sa.sa_family);
318: break;
319: }
320: return (XSTRDUP (MTYPE_TMP, buf));
321: }
322:
323: /* sockunion_connect returns
324: -1 : error occured
325: 0 : connect success
326: 1 : connect is in progress */
327: enum connect_result
328: sockunion_connect (int fd, union sockunion *peersu, unsigned short port,
329: unsigned int ifindex)
330: {
331: int ret;
332: int val;
333: union sockunion su;
334:
335: memcpy (&su, peersu, sizeof (union sockunion));
336:
337: switch (su.sa.sa_family)
338: {
339: case AF_INET:
340: su.sin.sin_port = port;
341: break;
342: #ifdef HAVE_IPV6
343: case AF_INET6:
344: su.sin6.sin6_port = port;
345: #ifdef KAME
346: if (IN6_IS_ADDR_LINKLOCAL(&su.sin6.sin6_addr) && ifindex)
347: {
348: #ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
349: /* su.sin6.sin6_scope_id = ifindex; */
350: #ifdef MUSICA
351: su.sin6.sin6_scope_id = ifindex;
352: #endif
353: #endif /* HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID */
354: #ifndef MUSICA
355: SET_IN6_LINKLOCAL_IFINDEX (su.sin6.sin6_addr, ifindex);
356: #endif
357: }
358: #endif /* KAME */
359: break;
360: #endif /* HAVE_IPV6 */
361: }
362:
363: /* Make socket non-block. */
364: val = fcntl (fd, F_GETFL, 0);
365: fcntl (fd, F_SETFL, val|O_NONBLOCK);
366:
367: /* Call connect function. */
368: ret = connect (fd, (struct sockaddr *) &su, sockunion_sizeof (&su));
369:
370: /* Immediate success */
371: if (ret == 0)
372: {
373: fcntl (fd, F_SETFL, val);
374: return connect_success;
375: }
376:
377: /* If connect is in progress then return 1 else it's real error. */
378: if (ret < 0)
379: {
380: if (errno != EINPROGRESS)
381: {
382: zlog_info ("can't connect to %s fd %d : %s",
383: sockunion_log (&su), fd, safe_strerror (errno));
384: return connect_error;
385: }
386: }
387:
388: fcntl (fd, F_SETFL, val);
389:
390: return connect_in_progress;
391: }
392:
393: /* Make socket from sockunion union. */
394: int
395: sockunion_stream_socket (union sockunion *su)
396: {
397: int sock;
398:
399: if (su->sa.sa_family == 0)
400: su->sa.sa_family = AF_INET_UNION;
401:
402: sock = socket (su->sa.sa_family, SOCK_STREAM, 0);
403:
404: if (sock < 0)
405: zlog (NULL, LOG_WARNING, "can't make socket sockunion_stream_socket");
406:
407: return sock;
408: }
409:
410: /* Bind socket to specified address. */
411: int
412: sockunion_bind (int sock, union sockunion *su, unsigned short port,
413: union sockunion *su_addr)
414: {
415: int size = 0;
416: int ret;
417:
418: if (su->sa.sa_family == AF_INET)
419: {
420: size = sizeof (struct sockaddr_in);
421: su->sin.sin_port = htons (port);
422: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
423: su->sin.sin_len = size;
424: #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
425: if (su_addr == NULL)
426: su->sin.sin_addr.s_addr = htonl (INADDR_ANY);
427: }
428: #ifdef HAVE_IPV6
429: else if (su->sa.sa_family == AF_INET6)
430: {
431: size = sizeof (struct sockaddr_in6);
432: su->sin6.sin6_port = htons (port);
433: #ifdef SIN6_LEN
434: su->sin6.sin6_len = size;
435: #endif /* SIN6_LEN */
436: if (su_addr == NULL)
437: {
438: #if defined(LINUX_IPV6) || defined(NRL)
439: memset (&su->sin6.sin6_addr, 0, sizeof (struct in6_addr));
440: #else
441: su->sin6.sin6_addr = in6addr_any;
442: #endif /* LINUX_IPV6 */
443: }
444: }
445: #endif /* HAVE_IPV6 */
446:
447:
448: ret = bind (sock, (struct sockaddr *)su, size);
449: if (ret < 0)
450: zlog (NULL, LOG_WARNING, "can't bind socket : %s", safe_strerror (errno));
451:
452: return ret;
453: }
454:
455: int
456: sockopt_reuseaddr (int sock)
457: {
458: int ret;
459: int on = 1;
460:
461: ret = setsockopt (sock, SOL_SOCKET, SO_REUSEADDR,
462: (void *) &on, sizeof (on));
463: if (ret < 0)
464: {
465: zlog (NULL, LOG_WARNING, "can't set sockopt SO_REUSEADDR to socket %d", sock);
466: return -1;
467: }
468: return 0;
469: }
470:
471: #ifdef SO_REUSEPORT
472: int
473: sockopt_reuseport (int sock)
474: {
475: int ret;
476: int on = 1;
477:
478: ret = setsockopt (sock, SOL_SOCKET, SO_REUSEPORT,
479: (void *) &on, sizeof (on));
480: if (ret < 0)
481: {
482: zlog (NULL, LOG_WARNING, "can't set sockopt SO_REUSEPORT to socket %d", sock);
483: return -1;
484: }
485: return 0;
486: }
487: #else
488: int
489: sockopt_reuseport (int sock)
490: {
491: return 0;
492: }
493: #endif /* 0 */
494:
495: int
496: sockopt_ttl (int family, int sock, int ttl)
497: {
498: int ret;
499:
500: #ifdef IP_TTL
501: if (family == AF_INET)
502: {
503: ret = setsockopt (sock, IPPROTO_IP, IP_TTL,
504: (void *) &ttl, sizeof (int));
505: if (ret < 0)
506: {
507: zlog (NULL, LOG_WARNING, "can't set sockopt IP_TTL %d to socket %d", ttl, sock);
508: return -1;
509: }
510: return 0;
511: }
512: #endif /* IP_TTL */
513: #ifdef HAVE_IPV6
514: if (family == AF_INET6)
515: {
516: ret = setsockopt (sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
517: (void *) &ttl, sizeof (int));
518: if (ret < 0)
519: {
520: zlog (NULL, LOG_WARNING, "can't set sockopt IPV6_UNICAST_HOPS %d to socket %d",
521: ttl, sock);
522: return -1;
523: }
524: return 0;
525: }
526: #endif /* HAVE_IPV6 */
527: return 0;
528: }
529:
530: int
531: sockopt_cork (int sock, int onoff)
532: {
533: #ifdef TCP_CORK
534: return setsockopt (sock, IPPROTO_TCP, TCP_CORK, &onoff, sizeof(onoff));
535: #else
536: return 0;
537: #endif
538: }
539:
540: int
541: sockopt_minttl (int family, int sock, int minttl)
542: {
543: #ifdef IP_MINTTL
544: if (family == AF_INET)
545: {
546: int ret = setsockopt (sock, IPPROTO_IP, IP_MINTTL, &minttl, sizeof(minttl));
547: if (ret < 0)
548: zlog (NULL, LOG_WARNING,
549: "can't set sockopt IP_MINTTL to %d on socket %d: %s",
550: minttl, sock, safe_strerror (errno));
551: return ret;
552: }
553: #endif /* IP_MINTTL */
554: #ifdef IPV6_MINHOPCNT
555: if (family == AF_INET6)
556: {
557: int ret = setsockopt (sock, IPPROTO_IPV6, IPV6_MINHOPCNT, &minttl, sizeof(minttl));
558: if (ret < 0)
559: zlog (NULL, LOG_WARNING,
560: "can't set sockopt IPV6_MINHOPCNT to %d on socket %d: %s",
561: minttl, sock, safe_strerror (errno));
562: return ret;
563: }
564: #endif
565:
566: errno = EOPNOTSUPP;
567: return -1;
568: }
569:
570: /* If same family and same prefix return 1. */
571: int
572: sockunion_same (union sockunion *su1, union sockunion *su2)
573: {
574: int ret = 0;
575:
576: if (su1->sa.sa_family != su2->sa.sa_family)
577: return 0;
578:
579: switch (su1->sa.sa_family)
580: {
581: case AF_INET:
582: ret = memcmp (&su1->sin.sin_addr, &su2->sin.sin_addr,
583: sizeof (struct in_addr));
584: break;
585: #ifdef HAVE_IPV6
586: case AF_INET6:
587: ret = memcmp (&su1->sin6.sin6_addr, &su2->sin6.sin6_addr,
588: sizeof (struct in6_addr));
589: break;
590: #endif /* HAVE_IPV6 */
591: }
592: if (ret == 0)
593: return 1;
594: else
595: return 0;
596: }
597:
598: /* After TCP connection is established. Get local address and port. */
599: union sockunion *
600: sockunion_getsockname (int fd)
601: {
602: int ret;
603: socklen_t len;
604: union
605: {
606: struct sockaddr sa;
607: struct sockaddr_in sin;
608: #ifdef HAVE_IPV6
609: struct sockaddr_in6 sin6;
610: #endif /* HAVE_IPV6 */
611: char tmp_buffer[128];
612: } name;
613: union sockunion *su;
614:
615: memset (&name, 0, sizeof name);
616: len = sizeof name;
617:
618: ret = getsockname (fd, (struct sockaddr *)&name, &len);
619: if (ret < 0)
620: {
621: zlog_warn ("Can't get local address and port by getsockname: %s",
622: safe_strerror (errno));
623: return NULL;
624: }
625:
626: if (name.sa.sa_family == AF_INET)
627: {
628: su = XCALLOC (MTYPE_SOCKUNION, sizeof (union sockunion));
629: memcpy (su, &name, sizeof (struct sockaddr_in));
630: return su;
631: }
632: #ifdef HAVE_IPV6
633: if (name.sa.sa_family == AF_INET6)
634: {
635: su = XCALLOC (MTYPE_SOCKUNION, sizeof (union sockunion));
636: memcpy (su, &name, sizeof (struct sockaddr_in6));
637: sockunion_normalise_mapped (su);
638: return su;
639: }
640: #endif /* HAVE_IPV6 */
641: return NULL;
642: }
643:
644: /* After TCP connection is established. Get remote address and port. */
645: union sockunion *
646: sockunion_getpeername (int fd)
647: {
648: int ret;
649: socklen_t len;
650: union
651: {
652: struct sockaddr sa;
653: struct sockaddr_in sin;
654: #ifdef HAVE_IPV6
655: struct sockaddr_in6 sin6;
656: #endif /* HAVE_IPV6 */
657: char tmp_buffer[128];
658: } name;
659: union sockunion *su;
660:
661: memset (&name, 0, sizeof name);
662: len = sizeof name;
663: ret = getpeername (fd, (struct sockaddr *)&name, &len);
664: if (ret < 0)
665: {
666: zlog (NULL, LOG_WARNING, "Can't get remote address and port: %s",
667: safe_strerror (errno));
668: return NULL;
669: }
670:
671: if (name.sa.sa_family == AF_INET)
672: {
673: su = XCALLOC (MTYPE_SOCKUNION, sizeof (union sockunion));
674: memcpy (su, &name, sizeof (struct sockaddr_in));
675: return su;
676: }
677: #ifdef HAVE_IPV6
678: if (name.sa.sa_family == AF_INET6)
679: {
680: su = XCALLOC (MTYPE_SOCKUNION, sizeof (union sockunion));
681: memcpy (su, &name, sizeof (struct sockaddr_in6));
682: sockunion_normalise_mapped (su);
683: return su;
684: }
685: #endif /* HAVE_IPV6 */
686: return NULL;
687: }
688:
689: /* Print sockunion structure */
690: static void __attribute__ ((unused))
691: sockunion_print (union sockunion *su)
692: {
693: if (su == NULL)
694: return;
695:
696: switch (su->sa.sa_family)
697: {
698: case AF_INET:
699: printf ("%s\n", inet_ntoa (su->sin.sin_addr));
700: break;
701: #ifdef HAVE_IPV6
702: case AF_INET6:
703: {
704: char buf [SU_ADDRSTRLEN];
705:
706: printf ("%s\n", inet_ntop (AF_INET6, &(su->sin6.sin6_addr),
707: buf, sizeof (buf)));
708: }
709: break;
710: #endif /* HAVE_IPV6 */
711:
712: #ifdef AF_LINK
713: case AF_LINK:
714: {
715: struct sockaddr_dl *sdl;
716:
717: sdl = (struct sockaddr_dl *)&(su->sa);
718: printf ("link#%d\n", sdl->sdl_index);
719: }
720: break;
721: #endif /* AF_LINK */
722: default:
723: printf ("af_unknown %d\n", su->sa.sa_family);
724: break;
725: }
726: }
727:
728: #ifdef HAVE_IPV6
729: static int
730: in6addr_cmp (struct in6_addr *addr1, struct in6_addr *addr2)
731: {
732: unsigned int i;
733: u_char *p1, *p2;
734:
735: p1 = (u_char *)addr1;
736: p2 = (u_char *)addr2;
737:
738: for (i = 0; i < sizeof (struct in6_addr); i++)
739: {
740: if (p1[i] > p2[i])
741: return 1;
742: else if (p1[i] < p2[i])
743: return -1;
744: }
745: return 0;
746: }
747: #endif /* HAVE_IPV6 */
748:
749: int
750: sockunion_cmp (union sockunion *su1, union sockunion *su2)
751: {
752: if (su1->sa.sa_family > su2->sa.sa_family)
753: return 1;
754: if (su1->sa.sa_family < su2->sa.sa_family)
755: return -1;
756:
757: if (su1->sa.sa_family == AF_INET)
758: {
759: if (ntohl (su1->sin.sin_addr.s_addr) == ntohl (su2->sin.sin_addr.s_addr))
760: return 0;
761: if (ntohl (su1->sin.sin_addr.s_addr) > ntohl (su2->sin.sin_addr.s_addr))
762: return 1;
763: else
764: return -1;
765: }
766: #ifdef HAVE_IPV6
767: if (su1->sa.sa_family == AF_INET6)
768: return in6addr_cmp (&su1->sin6.sin6_addr, &su2->sin6.sin6_addr);
769: #endif /* HAVE_IPV6 */
770: return 0;
771: }
772:
773: /* Duplicate sockunion. */
774: union sockunion *
775: sockunion_dup (union sockunion *su)
776: {
777: union sockunion *dup = XCALLOC (MTYPE_SOCKUNION, sizeof (union sockunion));
778: memcpy (dup, su, sizeof (union sockunion));
779: return dup;
780: }
781:
782: void
783: sockunion_free (union sockunion *su)
784: {
785: XFREE (MTYPE_SOCKUNION, su);
786: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>