]> git.proxmox.com Git - mirror_frr.git/blame - lib/sockunion.c
bgpd: Fix memory leak of some "show ip bgp neighbor" commands
[mirror_frr.git] / lib / sockunion.c
CommitLineData
718e3744 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
32int
33inet_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
73int
74inet_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
93const char *
94inet_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
118const char *
119inet_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
135int
a149411b 136str2sockunion (const char *str, union sockunion *su)
718e3744 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;
6f0e3f6e 146#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
718e3744 147 su->sin.sin_len = sizeof(struct sockaddr_in);
6f0e3f6e 148#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
718e3744 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
165const char *
166sockunion2str (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
1a7dcf42
PJ
177/* Convert IPv4 compatible IPv6 address to IPv4 address. */
178static void
179sockunion_normalise_mapped (union sockunion *su)
180{
181 struct sockaddr_in sin;
182
183#ifdef HAVE_IPV6
184 if (su->sa.sa_family == AF_INET6
185 && IN6_IS_ADDR_V4MAPPED (&su->sin6.sin6_addr))
186 {
187 memset (&sin, 0, sizeof (struct sockaddr_in));
188 sin.sin_family = AF_INET;
3fa3f957 189 sin.sin_port = su->sin6.sin6_port;
1a7dcf42
PJ
190 memcpy (&sin.sin_addr, ((char *)&su->sin6.sin6_addr) + 12, 4);
191 memcpy (su, &sin, sizeof (struct sockaddr_in));
192 }
193#endif /* HAVE_IPV6 */
194}
195
718e3744 196/* Return socket of sockunion. */
197int
198sockunion_socket (union sockunion *su)
199{
200 int sock;
201
202 sock = socket (su->sa.sa_family, SOCK_STREAM, 0);
203 if (sock < 0)
204 {
6099b3b5 205 zlog (NULL, LOG_WARNING, "Can't make socket : %s", safe_strerror (errno));
718e3744 206 return -1;
207 }
208
209 return sock;
210}
211
212/* Return accepted new socket file descriptor. */
213int
214sockunion_accept (int sock, union sockunion *su)
215{
216 socklen_t len;
217 int client_sock;
218
219 len = sizeof (union sockunion);
220 client_sock = accept (sock, (struct sockaddr *) su, &len);
221
84152ee6 222 sockunion_normalise_mapped (su);
718e3744 223 return client_sock;
224}
225
226/* Return sizeof union sockunion. */
8cc4198f 227static int
718e3744 228sockunion_sizeof (union sockunion *su)
229{
230 int ret;
231
232 ret = 0;
233 switch (su->sa.sa_family)
234 {
235 case AF_INET:
236 ret = sizeof (struct sockaddr_in);
237 break;
238#ifdef HAVE_IPV6
239 case AF_INET6:
240 ret = sizeof (struct sockaddr_in6);
241 break;
242#endif /* AF_INET6 */
243 }
244 return ret;
245}
246
247/* return sockunion structure : this function should be revised. */
b24b19f7
SH
248static const char *
249sockunion_log (union sockunion *su, char *buf, size_t len)
718e3744 250{
718e3744 251 switch (su->sa.sa_family)
252 {
253 case AF_INET:
b24b19f7
SH
254 return inet_ntop(AF_INET, &su->sin.sin_addr, buf, len);
255
718e3744 256#ifdef HAVE_IPV6
257 case AF_INET6:
b24b19f7 258 return inet_ntop(AF_INET6, &(su->sin6.sin6_addr), buf, len);
718e3744 259 break;
260#endif /* HAVE_IPV6 */
b24b19f7 261
718e3744 262 default:
b24b19f7
SH
263 snprintf (buf, len, "af_unknown %d ", su->sa.sa_family);
264 return buf;
718e3744 265 }
718e3744 266}
267
268/* sockunion_connect returns
269 -1 : error occured
270 0 : connect success
271 1 : connect is in progress */
272enum connect_result
273sockunion_connect (int fd, union sockunion *peersu, unsigned short port,
274 unsigned int ifindex)
275{
276 int ret;
277 int val;
278 union sockunion su;
279
280 memcpy (&su, peersu, sizeof (union sockunion));
281
282 switch (su.sa.sa_family)
283 {
284 case AF_INET:
285 su.sin.sin_port = port;
286 break;
287#ifdef HAVE_IPV6
288 case AF_INET6:
289 su.sin6.sin6_port = port;
290#ifdef KAME
291 if (IN6_IS_ADDR_LINKLOCAL(&su.sin6.sin6_addr) && ifindex)
292 {
6f0e3f6e 293#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
718e3744 294 /* su.sin6.sin6_scope_id = ifindex; */
726f9b2b 295#ifdef MUSICA
296 su.sin6.sin6_scope_id = ifindex;
297#endif
6f0e3f6e 298#endif /* HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID */
726f9b2b 299#ifndef MUSICA
718e3744 300 SET_IN6_LINKLOCAL_IFINDEX (su.sin6.sin6_addr, ifindex);
726f9b2b 301#endif
718e3744 302 }
303#endif /* KAME */
304 break;
305#endif /* HAVE_IPV6 */
306 }
307
308 /* Make socket non-block. */
309 val = fcntl (fd, F_GETFL, 0);
310 fcntl (fd, F_SETFL, val|O_NONBLOCK);
311
312 /* Call connect function. */
313 ret = connect (fd, (struct sockaddr *) &su, sockunion_sizeof (&su));
314
315 /* Immediate success */
316 if (ret == 0)
317 {
318 fcntl (fd, F_SETFL, val);
319 return connect_success;
320 }
321
322 /* If connect is in progress then return 1 else it's real error. */
323 if (ret < 0)
324 {
325 if (errno != EINPROGRESS)
326 {
b24b19f7 327 char str[SU_ADDRSTRLEN];
718e3744 328 zlog_info ("can't connect to %s fd %d : %s",
b24b19f7
SH
329 sockunion_log (&su, str, sizeof str),
330 fd, safe_strerror (errno));
718e3744 331 return connect_error;
332 }
333 }
334
335 fcntl (fd, F_SETFL, val);
336
337 return connect_in_progress;
338}
339
340/* Make socket from sockunion union. */
341int
342sockunion_stream_socket (union sockunion *su)
343{
344 int sock;
345
346 if (su->sa.sa_family == 0)
347 su->sa.sa_family = AF_INET_UNION;
348
349 sock = socket (su->sa.sa_family, SOCK_STREAM, 0);
350
351 if (sock < 0)
352 zlog (NULL, LOG_WARNING, "can't make socket sockunion_stream_socket");
353
354 return sock;
355}
356
357/* Bind socket to specified address. */
358int
359sockunion_bind (int sock, union sockunion *su, unsigned short port,
360 union sockunion *su_addr)
361{
362 int size = 0;
363 int ret;
364
365 if (su->sa.sa_family == AF_INET)
366 {
367 size = sizeof (struct sockaddr_in);
368 su->sin.sin_port = htons (port);
6f0e3f6e 369#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
718e3744 370 su->sin.sin_len = size;
6f0e3f6e 371#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
718e3744 372 if (su_addr == NULL)
373 su->sin.sin_addr.s_addr = htonl (INADDR_ANY);
374 }
375#ifdef HAVE_IPV6
376 else if (su->sa.sa_family == AF_INET6)
377 {
378 size = sizeof (struct sockaddr_in6);
379 su->sin6.sin6_port = htons (port);
380#ifdef SIN6_LEN
381 su->sin6.sin6_len = size;
382#endif /* SIN6_LEN */
383 if (su_addr == NULL)
384 {
385#if defined(LINUX_IPV6) || defined(NRL)
386 memset (&su->sin6.sin6_addr, 0, sizeof (struct in6_addr));
387#else
388 su->sin6.sin6_addr = in6addr_any;
389#endif /* LINUX_IPV6 */
390 }
391 }
392#endif /* HAVE_IPV6 */
393
394
395 ret = bind (sock, (struct sockaddr *)su, size);
396 if (ret < 0)
6099b3b5 397 zlog (NULL, LOG_WARNING, "can't bind socket : %s", safe_strerror (errno));
718e3744 398
399 return ret;
400}
401
402int
403sockopt_reuseaddr (int sock)
404{
405 int ret;
406 int on = 1;
407
408 ret = setsockopt (sock, SOL_SOCKET, SO_REUSEADDR,
409 (void *) &on, sizeof (on));
410 if (ret < 0)
411 {
412 zlog (NULL, LOG_WARNING, "can't set sockopt SO_REUSEADDR to socket %d", sock);
413 return -1;
414 }
415 return 0;
416}
417
418#ifdef SO_REUSEPORT
419int
420sockopt_reuseport (int sock)
421{
422 int ret;
423 int on = 1;
424
425 ret = setsockopt (sock, SOL_SOCKET, SO_REUSEPORT,
426 (void *) &on, sizeof (on));
427 if (ret < 0)
428 {
e7fe8c88 429 zlog (NULL, LOG_WARNING, "can't set sockopt SO_REUSEPORT to socket %d", sock);
718e3744 430 return -1;
431 }
432 return 0;
433}
434#else
435int
436sockopt_reuseport (int sock)
437{
438 return 0;
439}
440#endif /* 0 */
441
442int
443sockopt_ttl (int family, int sock, int ttl)
444{
445 int ret;
446
447#ifdef IP_TTL
448 if (family == AF_INET)
449 {
450 ret = setsockopt (sock, IPPROTO_IP, IP_TTL,
451 (void *) &ttl, sizeof (int));
452 if (ret < 0)
453 {
454 zlog (NULL, LOG_WARNING, "can't set sockopt IP_TTL %d to socket %d", ttl, sock);
455 return -1;
456 }
457 return 0;
458 }
459#endif /* IP_TTL */
460#ifdef HAVE_IPV6
461 if (family == AF_INET6)
462 {
463 ret = setsockopt (sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
464 (void *) &ttl, sizeof (int));
465 if (ret < 0)
466 {
467 zlog (NULL, LOG_WARNING, "can't set sockopt IPV6_UNICAST_HOPS %d to socket %d",
468 ttl, sock);
469 return -1;
470 }
471 return 0;
472 }
473#endif /* HAVE_IPV6 */
474 return 0;
475}
476
58192df7
SH
477int
478sockopt_cork (int sock, int onoff)
479{
480#ifdef TCP_CORK
481 return setsockopt (sock, IPPROTO_TCP, TCP_CORK, &onoff, sizeof(onoff));
482#else
483 return 0;
484#endif
485}
486
fa411a21
NH
487int
488sockopt_minttl (int family, int sock, int minttl)
489{
89b6d1f8 490#ifdef IP_MINTTL
d876bdf4 491 if (family == AF_INET)
fa411a21 492 {
d876bdf4
SH
493 int ret = setsockopt (sock, IPPROTO_IP, IP_MINTTL, &minttl, sizeof(minttl));
494 if (ret < 0)
495 zlog (NULL, LOG_WARNING,
496 "can't set sockopt IP_MINTTL to %d on socket %d: %s",
497 minttl, sock, safe_strerror (errno));
498 return ret;
fa411a21 499 }
d876bdf4
SH
500#endif /* IP_MINTTL */
501#ifdef IPV6_MINHOPCNT
502 if (family == AF_INET6)
503 {
504 int ret = setsockopt (sock, IPPROTO_IPV6, IPV6_MINHOPCNT, &minttl, sizeof(minttl));
505 if (ret < 0)
506 zlog (NULL, LOG_WARNING,
507 "can't set sockopt IPV6_MINHOPCNT to %d on socket %d: %s",
508 minttl, sock, safe_strerror (errno));
509 return ret;
510 }
511#endif
fa411a21 512
89b6d1f8
SH
513 errno = EOPNOTSUPP;
514 return -1;
fa411a21
NH
515}
516
ca051269
DL
517int
518sockopt_v6only (int family, int sock)
519{
520 int ret, on = 1;
521
522#ifdef HAVE_IPV6
523#ifdef IPV6_V6ONLY
524 if (family == AF_INET6)
525 {
526 ret = setsockopt (sock, IPPROTO_IPV6, IPV6_V6ONLY,
527 (void *) &on, sizeof (int));
528 if (ret < 0)
529 {
530 zlog (NULL, LOG_WARNING, "can't set sockopt IPV6_V6ONLY "
531 "to socket %d", sock);
532 return -1;
533 }
534 return 0;
535 }
536#endif /* IPV6_V6ONLY */
537#endif /* HAVE_IPV6 */
538 return 0;
539}
540
718e3744 541/* If same family and same prefix return 1. */
542int
543sockunion_same (union sockunion *su1, union sockunion *su2)
544{
545 int ret = 0;
546
547 if (su1->sa.sa_family != su2->sa.sa_family)
548 return 0;
549
550 switch (su1->sa.sa_family)
551 {
552 case AF_INET:
553 ret = memcmp (&su1->sin.sin_addr, &su2->sin.sin_addr,
554 sizeof (struct in_addr));
555 break;
556#ifdef HAVE_IPV6
557 case AF_INET6:
558 ret = memcmp (&su1->sin6.sin6_addr, &su2->sin6.sin6_addr,
559 sizeof (struct in6_addr));
560 break;
561#endif /* HAVE_IPV6 */
562 }
563 if (ret == 0)
564 return 1;
565 else
566 return 0;
567}
568
569/* After TCP connection is established. Get local address and port. */
570union sockunion *
571sockunion_getsockname (int fd)
572{
573 int ret;
22528299 574 socklen_t len;
718e3744 575 union
576 {
577 struct sockaddr sa;
578 struct sockaddr_in sin;
579#ifdef HAVE_IPV6
580 struct sockaddr_in6 sin6;
581#endif /* HAVE_IPV6 */
582 char tmp_buffer[128];
583 } name;
584 union sockunion *su;
585
586 memset (&name, 0, sizeof name);
587 len = sizeof name;
588
589 ret = getsockname (fd, (struct sockaddr *)&name, &len);
590 if (ret < 0)
591 {
592 zlog_warn ("Can't get local address and port by getsockname: %s",
6099b3b5 593 safe_strerror (errno));
718e3744 594 return NULL;
595 }
596
597 if (name.sa.sa_family == AF_INET)
598 {
2ba9a37a 599 su = XCALLOC (MTYPE_SOCKUNION, sizeof (union sockunion));
718e3744 600 memcpy (su, &name, sizeof (struct sockaddr_in));
601 return su;
602 }
603#ifdef HAVE_IPV6
604 if (name.sa.sa_family == AF_INET6)
605 {
2ba9a37a 606 su = XCALLOC (MTYPE_SOCKUNION, sizeof (union sockunion));
718e3744 607 memcpy (su, &name, sizeof (struct sockaddr_in6));
1a7dcf42 608 sockunion_normalise_mapped (su);
718e3744 609 return su;
610 }
611#endif /* HAVE_IPV6 */
612 return NULL;
613}
614
615/* After TCP connection is established. Get remote address and port. */
616union sockunion *
617sockunion_getpeername (int fd)
618{
619 int ret;
22528299 620 socklen_t len;
718e3744 621 union
622 {
623 struct sockaddr sa;
624 struct sockaddr_in sin;
625#ifdef HAVE_IPV6
626 struct sockaddr_in6 sin6;
627#endif /* HAVE_IPV6 */
628 char tmp_buffer[128];
629 } name;
630 union sockunion *su;
631
632 memset (&name, 0, sizeof name);
633 len = sizeof name;
634 ret = getpeername (fd, (struct sockaddr *)&name, &len);
635 if (ret < 0)
636 {
637 zlog (NULL, LOG_WARNING, "Can't get remote address and port: %s",
6099b3b5 638 safe_strerror (errno));
718e3744 639 return NULL;
640 }
641
642 if (name.sa.sa_family == AF_INET)
643 {
2ba9a37a 644 su = XCALLOC (MTYPE_SOCKUNION, sizeof (union sockunion));
718e3744 645 memcpy (su, &name, sizeof (struct sockaddr_in));
646 return su;
647 }
648#ifdef HAVE_IPV6
649 if (name.sa.sa_family == AF_INET6)
650 {
2ba9a37a 651 su = XCALLOC (MTYPE_SOCKUNION, sizeof (union sockunion));
718e3744 652 memcpy (su, &name, sizeof (struct sockaddr_in6));
1a7dcf42 653 sockunion_normalise_mapped (su);
718e3744 654 return su;
655 }
656#endif /* HAVE_IPV6 */
657 return NULL;
658}
659
660/* Print sockunion structure */
8cc4198f 661static void __attribute__ ((unused))
718e3744 662sockunion_print (union sockunion *su)
663{
664 if (su == NULL)
665 return;
666
667 switch (su->sa.sa_family)
668 {
669 case AF_INET:
670 printf ("%s\n", inet_ntoa (su->sin.sin_addr));
671 break;
672#ifdef HAVE_IPV6
673 case AF_INET6:
674 {
42d49865 675 char buf [SU_ADDRSTRLEN];
718e3744 676
677 printf ("%s\n", inet_ntop (AF_INET6, &(su->sin6.sin6_addr),
678 buf, sizeof (buf)));
679 }
680 break;
681#endif /* HAVE_IPV6 */
682
683#ifdef AF_LINK
684 case AF_LINK:
685 {
686 struct sockaddr_dl *sdl;
687
688 sdl = (struct sockaddr_dl *)&(su->sa);
689 printf ("link#%d\n", sdl->sdl_index);
690 }
691 break;
692#endif /* AF_LINK */
693 default:
694 printf ("af_unknown %d\n", su->sa.sa_family);
695 break;
696 }
697}
698
699#ifdef HAVE_IPV6
8cc4198f 700static int
718e3744 701in6addr_cmp (struct in6_addr *addr1, struct in6_addr *addr2)
702{
8c328f11 703 unsigned int i;
718e3744 704 u_char *p1, *p2;
705
706 p1 = (u_char *)addr1;
707 p2 = (u_char *)addr2;
708
709 for (i = 0; i < sizeof (struct in6_addr); i++)
710 {
711 if (p1[i] > p2[i])
712 return 1;
713 else if (p1[i] < p2[i])
714 return -1;
715 }
716 return 0;
717}
718#endif /* HAVE_IPV6 */
719
720int
721sockunion_cmp (union sockunion *su1, union sockunion *su2)
722{
723 if (su1->sa.sa_family > su2->sa.sa_family)
724 return 1;
725 if (su1->sa.sa_family < su2->sa.sa_family)
726 return -1;
727
728 if (su1->sa.sa_family == AF_INET)
729 {
730 if (ntohl (su1->sin.sin_addr.s_addr) == ntohl (su2->sin.sin_addr.s_addr))
731 return 0;
732 if (ntohl (su1->sin.sin_addr.s_addr) > ntohl (su2->sin.sin_addr.s_addr))
733 return 1;
734 else
735 return -1;
736 }
737#ifdef HAVE_IPV6
738 if (su1->sa.sa_family == AF_INET6)
739 return in6addr_cmp (&su1->sin6.sin6_addr, &su2->sin6.sin6_addr);
740#endif /* HAVE_IPV6 */
741 return 0;
742}
743
744/* Duplicate sockunion. */
745union sockunion *
746sockunion_dup (union sockunion *su)
747{
748 union sockunion *dup = XCALLOC (MTYPE_SOCKUNION, sizeof (union sockunion));
749 memcpy (dup, su, sizeof (union sockunion));
750 return dup;
751}
752
753void
754sockunion_free (union sockunion *su)
755{
756 XFREE (MTYPE_SOCKUNION, su);
757}