Merge from vendor branch GCC:
[dragonfly.git] / contrib / bind-9.2.4rc7 / lib / lwres / getaddrinfo.c
1 /*
2  * Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 1999-2001  Internet Software Consortium.
4  *
5  * This code is derived from software contributed to ISC by
6  * Berkeley Software Design, Inc.
7  *
8  * Permission to use, copy, modify, and distribute this software for any
9  * purpose with or without fee is hereby granted, provided that the above
10  * copyright notice and this permission notice appear in all copies.
11  *
12  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND BERKELEY SOFTWARE DESIGN, INC.
13  * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14  * WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE
15  * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
18  * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19  */
20
21 /* $Id: getaddrinfo.c,v 1.41.2.1 2004/03/09 06:12:33 marka Exp $ */
22
23 #include <config.h>
24
25 #include <string.h>
26 #include <errno.h>
27 #include <stdlib.h>
28
29 #include <lwres/lwres.h>
30 #include <lwres/net.h>
31 #include <lwres/netdb.h>
32
33 #define SA(addr)        ((struct sockaddr *)(addr))
34 #define SIN(addr)       ((struct sockaddr_in *)(addr))
35 #define SIN6(addr)      ((struct sockaddr_in6 *)(addr))
36 #define SUN(addr)       ((struct sockaddr_un *)(addr))
37
38 static struct addrinfo
39         *ai_reverse(struct addrinfo *oai),
40         *ai_clone(struct addrinfo *oai, int family),
41         *ai_alloc(int family, int addrlen);
42 #ifdef AF_LOCAL
43 static int get_local(const char *name, int socktype, struct addrinfo **res);
44 #endif
45
46 static int add_ipv4(const char *hostname, int flags, struct addrinfo **aip,
47     int socktype, int port);
48 static int add_ipv6(const char *hostname, int flags, struct addrinfo **aip,
49     int socktype, int port);
50 static void set_order(int, int (**)(const char *, int, struct addrinfo **,
51          int, int));
52
53 #define FOUND_IPV4      0x1
54 #define FOUND_IPV6      0x2
55 #define FOUND_MAX       2
56
57 #define ISC_AI_MASK (AI_PASSIVE|AI_CANONNAME|AI_NUMERICHOST)
58
59 int
60 lwres_getaddrinfo(const char *hostname, const char *servname,
61         const struct addrinfo *hints, struct addrinfo **res)
62 {
63         struct servent *sp;
64         const char *proto;
65         int family, socktype, flags, protocol;
66         struct addrinfo *ai, *ai_list;
67         int port, err, i;
68         int (*net_order[FOUND_MAX+1])(const char *, int, struct addrinfo **,
69                  int, int);
70
71         if (hostname == NULL && servname == NULL)
72                 return (EAI_NONAME);
73
74         proto = NULL;
75         if (hints != NULL) {
76                 if ((hints->ai_flags & ~(ISC_AI_MASK)) != 0)
77                         return (EAI_BADFLAGS);
78                 if (hints->ai_addrlen || hints->ai_canonname ||
79                     hints->ai_addr || hints->ai_next) {
80                         errno = EINVAL;
81                         return (EAI_SYSTEM);
82                 }
83                 family = hints->ai_family;
84                 socktype = hints->ai_socktype;
85                 protocol = hints->ai_protocol;
86                 flags = hints->ai_flags;
87                 switch (family) {
88                 case AF_UNSPEC:
89                         switch (hints->ai_socktype) {
90                         case SOCK_STREAM:
91                                 proto = "tcp";
92                                 break;
93                         case SOCK_DGRAM:
94                                 proto = "udp";
95                                 break;
96                         }
97                         break;
98                 case AF_INET:
99                 case AF_INET6:
100                         switch (hints->ai_socktype) {
101                         case 0:
102                                 break;
103                         case SOCK_STREAM:
104                                 proto = "tcp";
105                                 break;
106                         case SOCK_DGRAM:
107                                 proto = "udp";
108                                 break;
109                         case SOCK_RAW:
110                                 break;
111                         default:
112                                 return (EAI_SOCKTYPE);
113                         }
114                         break;
115 #ifdef  AF_LOCAL
116                 case AF_LOCAL:
117                         switch (hints->ai_socktype) {
118                         case 0:
119                                 break;
120                         case SOCK_STREAM:
121                                 break;
122                         case SOCK_DGRAM:
123                                 break;
124                         default:
125                                 return (EAI_SOCKTYPE);
126                         }
127                         break;
128 #endif
129                 default:
130                         return (EAI_FAMILY);
131                 }
132         } else {
133                 protocol = 0;
134                 family = 0;
135                 socktype = 0;
136                 flags = 0;
137         }
138
139 #ifdef  AF_LOCAL
140         /*
141          * First, deal with AF_LOCAL.  If the family was not set,
142          * then assume AF_LOCAL if the first character of the
143          * hostname/servname is '/'.
144          */
145
146         if (hostname != NULL &&
147             (family == AF_LOCAL || (family == 0 && *hostname == '/')))
148                 return (get_local(hostname, socktype, res));
149
150         if (servname != NULL &&
151             (family == AF_LOCAL || (family == 0 && *servname == '/')))
152                 return (get_local(servname, socktype, res));
153 #endif
154
155         /*
156          * Ok, only AF_INET and AF_INET6 left.
157          */
158         ai_list = NULL;
159
160         /*
161          * First, look up the service name (port) if it was
162          * requested.  If the socket type wasn't specified, then
163          * try and figure it out.
164          */
165         if (servname != NULL) {
166                 char *e;
167
168                 port = strtol(servname, &e, 10);
169                 if (*e == '\0') {
170                         if (socktype == 0)
171                                 return (EAI_SOCKTYPE);
172                         if (port < 0 || port > 65535)
173                                 return (EAI_SERVICE);
174                         port = htons((unsigned short) port);
175                 } else {
176                         sp = getservbyname(servname, proto);
177                         if (sp == NULL)
178                                 return (EAI_SERVICE);
179                         port = sp->s_port;
180                         if (socktype == 0) {
181                                 if (strcmp(sp->s_proto, "tcp") == 0)
182                                         socktype = SOCK_STREAM;
183                                 else if (strcmp(sp->s_proto, "udp") == 0)
184                                         socktype = SOCK_DGRAM;
185                         }
186                 }
187         } else
188                 port = 0;
189
190         /*
191          * Next, deal with just a service name, and no hostname.
192          * (we verified that one of them was non-null up above).
193          */
194         if (hostname == NULL && (flags & AI_PASSIVE) != 0) {
195                 if (family == AF_INET || family == 0) {
196                         ai = ai_alloc(AF_INET, sizeof(struct sockaddr_in));
197                         if (ai == NULL)
198                                 return (EAI_MEMORY);
199                         ai->ai_socktype = socktype;
200                         ai->ai_protocol = protocol;
201                         SIN(ai->ai_addr)->sin_port = port;
202                         ai->ai_next = ai_list;
203                         ai_list = ai;
204                 }
205
206                 if (family == AF_INET6 || family == 0) {
207                         ai = ai_alloc(AF_INET6, sizeof(struct sockaddr_in6));
208                         if (ai == NULL) {
209                                 lwres_freeaddrinfo(ai_list);
210                                 return (EAI_MEMORY);
211                         }
212                         ai->ai_socktype = socktype;
213                         ai->ai_protocol = protocol;
214                         SIN6(ai->ai_addr)->sin6_port = port;
215                         ai->ai_next = ai_list;
216                         ai_list = ai;
217                 }
218
219                 *res = ai_list;
220                 return (0);
221         }
222
223         /*
224          * If the family isn't specified or AI_NUMERICHOST specified,
225          * check first to see if it is a numeric address.
226          * Though the gethostbyname2() routine
227          * will recognize numeric addresses, it will only recognize
228          * the format that it is being called for.  Thus, a numeric
229          * AF_INET address will be treated by the AF_INET6 call as
230          * a domain name, and vice versa.  Checking for both numerics
231          * here avoids that.
232          */
233         if (hostname != NULL &&
234             (family == 0 || (flags & AI_NUMERICHOST) != 0)) {
235                 char abuf[sizeof(struct in6_addr)];
236                 char nbuf[NI_MAXHOST];
237                 int addrsize, addroff;
238 #ifdef LWRES_HAVE_SIN6_SCOPE_ID
239                 char *p, *ep;
240                 char ntmp[NI_MAXHOST];
241                 lwres_uint32_t scopeid;
242 #endif
243
244 #ifdef LWRES_HAVE_SIN6_SCOPE_ID
245                 /*
246                  * Scope identifier portion.
247                  */
248                 ntmp[0] = '\0';
249                 if (strchr(hostname, '%') != NULL) {
250                         strncpy(ntmp, hostname, sizeof(ntmp) - 1);
251                         ntmp[sizeof(ntmp) - 1] = '\0';
252                         p = strchr(ntmp, '%');
253                         ep = NULL;
254
255                         /*
256                          * Vendors may want to support non-numeric
257                          * scopeid around here.
258                          */
259
260                         if (p != NULL)
261                                 scopeid = (lwres_uint32_t)strtoul(p + 1,
262                                                                   &ep, 10);
263                         if (p != NULL && ep != NULL && ep[0] == '\0')
264                                 *p = '\0';
265                         else {
266                                 ntmp[0] = '\0';
267                                 scopeid = 0;
268                         }
269                 } else
270                         scopeid = 0;
271 #endif
272
273                if (lwres_net_pton(AF_INET, hostname, (struct in_addr *)abuf)
274                    == 1)
275                {
276                         if (family == AF_INET6) {
277                                 /*
278                                  * Convert to a V4 mapped address.
279                                  */
280                                 struct in6_addr *a6 = (struct in6_addr *)abuf;
281                                 memcpy(&a6->s6_addr[12], &a6->s6_addr[0], 4);
282                                 memset(&a6->s6_addr[10], 0xff, 2);
283                                 memset(&a6->s6_addr[0], 0, 10);
284                                 goto inet6_addr;
285                         }
286                         addrsize = sizeof(struct in_addr);
287                         addroff = (char *)(&SIN(0)->sin_addr) - (char *)0;
288                         family = AF_INET;
289                         goto common;
290 #ifdef LWRES_HAVE_SIN6_SCOPE_ID
291                 } else if (ntmp[0] != '\0' &&
292                            lwres_net_pton(AF_INET6, ntmp, abuf) == 1)
293                 {
294                         if (family && family != AF_INET6)
295                                 return (EAI_NONAME);
296                         addrsize = sizeof(struct in6_addr);
297                         addroff = (char *)(&SIN6(0)->sin6_addr) - (char *)0;
298                         family = AF_INET6;
299                         goto common;
300 #endif
301                 } else if (lwres_net_pton(AF_INET6, hostname, abuf) == 1) {
302                         if (family != 0 && family != AF_INET6)
303                                 return (EAI_NONAME);
304                 inet6_addr:
305                         addrsize = sizeof(struct in6_addr);
306                         addroff = (char *)(&SIN6(0)->sin6_addr) - (char *)0;
307                         family = AF_INET6;
308
309                 common:
310                         ai = ai_clone(ai_list, family);
311                         if (ai == NULL)
312                                 return (EAI_MEMORY);
313                         ai_list = ai;
314                         ai->ai_socktype = socktype;
315                         SIN(ai->ai_addr)->sin_port = port;
316                         memcpy((char *)ai->ai_addr + addroff, abuf, addrsize);
317                         if (flags & AI_CANONNAME) {
318 #if defined(LWRES_HAVE_SIN6_SCOPE_ID)
319                                 if (ai->ai_family == AF_INET6)
320                                         SIN6(ai->ai_addr)->sin6_scope_id =
321                                                                         scopeid;
322 #endif
323                                 if (lwres_getnameinfo(ai->ai_addr,
324                                     ai->ai_addrlen, nbuf, sizeof(nbuf),
325                                                       NULL, 0,
326                                                       NI_NUMERICHOST) == 0) {
327                                         ai->ai_canonname = strdup(nbuf);
328                                         if (ai->ai_canonname == NULL)
329                                                 return (EAI_MEMORY);
330                                 } else {
331                                         /* XXX raise error? */
332                                         ai->ai_canonname = NULL;
333                                 }
334                         }
335                         goto done;
336                 } else if ((flags & AI_NUMERICHOST) != 0) {
337                         return (EAI_NONAME);
338                 }
339         }
340
341         set_order(family, net_order);
342         for (i = 0; i < FOUND_MAX; i++) {
343                 if (net_order[i] == NULL)
344                         break;
345                 err = (net_order[i])(hostname, flags, &ai_list,
346                                      socktype, port);
347                 if (err != 0)
348                         return (err);
349         }
350
351         if (ai_list == NULL)
352                 return (EAI_NODATA);
353
354 done:
355         ai_list = ai_reverse(ai_list);
356
357         *res = ai_list;
358         return (0);
359 }
360
361 static char *
362 lwres_strsep(char **stringp, const char *delim) {
363         char *string = *stringp;
364         char *s;
365         const char *d;
366         char sc, dc;
367
368         if (string == NULL)
369                 return (NULL);
370
371         for (s = string; *s != '\0'; s++) {
372                 sc = *s;
373                 for (d = delim; (dc = *d) != '\0'; d++)
374                         if (sc == dc) {
375                                 *s++ = '\0';
376                                 *stringp = s;
377                                 return (string);
378                         }
379         }
380         *stringp = NULL;
381         return (string);
382 }
383
384 static void
385 set_order(int family, int (**net_order)(const char *, int, struct addrinfo **,
386                                         int, int))
387 {
388         char *order, *tok;
389         int found;
390
391         if (family) {
392                 switch (family) {
393                 case AF_INET:
394                         *net_order++ = add_ipv4;
395                         break;
396                 case AF_INET6:
397                         *net_order++ = add_ipv6;
398                         break;
399                 }
400         } else {
401                 order = getenv("NET_ORDER");
402                 found = 0;
403                 while (order != NULL) {
404                         /*
405                          * We ignore any unknown names.
406                          */
407                         tok = lwres_strsep(&order, ":");
408                         if (strcasecmp(tok, "inet6") == 0) {
409                                 if ((found & FOUND_IPV6) == 0)
410                                         *net_order++ = add_ipv6;
411                                 found |= FOUND_IPV6;
412                         } else if (strcasecmp(tok, "inet") == 0 ||
413                             strcasecmp(tok, "inet4") == 0) {
414                                 if ((found & FOUND_IPV4) == 0)
415                                         *net_order++ = add_ipv4;
416                                 found |= FOUND_IPV4;
417                         }
418                 }
419
420                 /*
421                  * Add in anything that we didn't find.
422                  */
423                 if ((found & FOUND_IPV4) == 0)
424                         *net_order++ = add_ipv4;
425                 if ((found & FOUND_IPV6) == 0)
426                         *net_order++ = add_ipv6;
427         }
428         *net_order = NULL;
429         return;
430 }
431
432 static char v4_loop[4] = { 127, 0, 0, 1 };
433
434 /*
435  * The test against 0 is there to keep the Solaris compiler
436  * from complaining about "end-of-loop code not reached".
437  */
438 #define ERR(code) \
439         do { result = (code);                   \
440                 if (result != 0) goto cleanup;  \
441         } while (0)
442
443 static int
444 add_ipv4(const char *hostname, int flags, struct addrinfo **aip,
445         int socktype, int port)
446 {
447         struct addrinfo *ai;
448         lwres_context_t *lwrctx = NULL;
449         lwres_gabnresponse_t *by = NULL;
450         lwres_addr_t *addr;
451         lwres_result_t lwres;
452         int result = 0;
453
454         lwres = lwres_context_create(&lwrctx, NULL, NULL, NULL, 0);
455         if (lwres != LWRES_R_SUCCESS)
456                 ERR(EAI_FAIL);
457         (void) lwres_conf_parse(lwrctx, lwres_resolv_conf);
458         if (hostname == NULL && (flags & AI_PASSIVE) == 0) {
459                 ai = ai_clone(*aip, AF_INET);
460                 if (ai == NULL) {
461                         lwres_freeaddrinfo(*aip);
462                         ERR(EAI_MEMORY);
463                 }
464
465                 *aip = ai;
466                 ai->ai_socktype = socktype;
467                 SIN(ai->ai_addr)->sin_port = port;
468                 memcpy(&SIN(ai->ai_addr)->sin_addr, v4_loop, 4);
469         } else {
470                 lwres = lwres_getaddrsbyname(lwrctx, hostname,
471                                              LWRES_ADDRTYPE_V4, &by);
472                 if (lwres != LWRES_R_SUCCESS) {
473                         if (lwres == LWRES_R_NOTFOUND)
474                                 goto cleanup;
475                         else
476                                 ERR(EAI_FAIL);
477                 }
478                 addr = LWRES_LIST_HEAD(by->addrs);
479                 while (addr != NULL) {
480                         ai = ai_clone(*aip, AF_INET);
481                         if (ai == NULL) {
482                                 lwres_freeaddrinfo(*aip);
483                                 ERR(EAI_MEMORY);
484                         }
485                         *aip = ai;
486                         ai->ai_socktype = socktype;
487                         SIN(ai->ai_addr)->sin_port = port;
488                         memcpy(&SIN(ai->ai_addr)->sin_addr,
489                                addr->address, 4);
490                         if (flags & AI_CANONNAME) {
491                                 ai->ai_canonname = strdup(by->realname);
492                                 if (ai->ai_canonname == NULL)
493                                         ERR(EAI_MEMORY);
494                         }
495                         addr = LWRES_LIST_NEXT(addr, link);
496                 }
497         }
498  cleanup:
499         if (by != NULL)
500                 lwres_gabnresponse_free(lwrctx, &by);
501         if (lwrctx != NULL) {
502                 lwres_conf_clear(lwrctx);
503                 lwres_context_destroy(&lwrctx);
504         }
505         return (result);
506 }
507
508 static char v6_loop[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
509
510 static int
511 add_ipv6(const char *hostname, int flags, struct addrinfo **aip,
512          int socktype, int port)
513 {
514         struct addrinfo *ai;
515         lwres_context_t *lwrctx = NULL;
516         lwres_gabnresponse_t *by = NULL;
517         lwres_addr_t *addr;
518         lwres_result_t lwres;
519         int result = 0;
520
521         lwres = lwres_context_create(&lwrctx, NULL, NULL, NULL, 0);
522         if (lwres != LWRES_R_SUCCESS)
523                 ERR(EAI_FAIL);
524         (void) lwres_conf_parse(lwrctx, lwres_resolv_conf);
525
526         if (hostname == NULL && (flags & AI_PASSIVE) == 0) {
527                 ai = ai_clone(*aip, AF_INET6);
528                 if (ai == NULL) {
529                         lwres_freeaddrinfo(*aip);
530                         ERR(EAI_MEMORY);
531                 }
532
533                 *aip = ai;
534                 ai->ai_socktype = socktype;
535                 SIN6(ai->ai_addr)->sin6_port = port;
536                 memcpy(&SIN6(ai->ai_addr)->sin6_addr, v6_loop, 16);
537         } else {
538                 lwres = lwres_getaddrsbyname(lwrctx, hostname,
539                                              LWRES_ADDRTYPE_V6, &by);
540                 if (lwres != LWRES_R_SUCCESS) {
541                         if (lwres == LWRES_R_NOTFOUND)
542                                 goto cleanup;
543                         else
544                                 ERR(EAI_FAIL);
545                 }
546                 addr = LWRES_LIST_HEAD(by->addrs);
547                 while (addr != NULL) {
548                         ai = ai_clone(*aip, AF_INET6);
549                         if (ai == NULL) {
550                                 lwres_freeaddrinfo(*aip);
551                                 ERR(EAI_MEMORY);
552                         }
553                         *aip = ai;
554                         ai->ai_socktype = socktype;
555                         SIN6(ai->ai_addr)->sin6_port = port;
556                         memcpy(&SIN6(ai->ai_addr)->sin6_addr,
557                                addr->address, 16);
558                         if (flags & AI_CANONNAME) {
559                                 ai->ai_canonname = strdup(by->realname);
560                                 if (ai->ai_canonname == NULL)
561                                         ERR(EAI_MEMORY);
562                         }
563                         addr = LWRES_LIST_NEXT(addr, link);
564                 }
565         }
566  cleanup:
567         if (by != NULL)
568                 lwres_gabnresponse_free(lwrctx, &by);
569         if (lwrctx != NULL) {
570                 lwres_conf_clear(lwrctx);
571                 lwres_context_destroy(&lwrctx);
572         }
573         return (result);
574 }
575
576 void
577 lwres_freeaddrinfo(struct addrinfo *ai) {
578         struct addrinfo *ai_next;
579
580         while (ai != NULL) {
581                 ai_next = ai->ai_next;
582                 if (ai->ai_addr != NULL)
583                         free(ai->ai_addr);
584                 if (ai->ai_canonname)
585                         free(ai->ai_canonname);
586                 free(ai);
587                 ai = ai_next;
588         }
589 }
590
591 #ifdef AF_LOCAL
592 static int
593 get_local(const char *name, int socktype, struct addrinfo **res) {
594         struct addrinfo *ai;
595         struct sockaddr_un *sun;
596
597         if (socktype == 0)
598                 return (EAI_SOCKTYPE);
599
600         ai = ai_alloc(AF_LOCAL, sizeof(*sun));
601         if (ai == NULL)
602                 return (EAI_MEMORY);
603
604         sun = SUN(ai->ai_addr);
605         strncpy(sun->sun_path, name, sizeof(sun->sun_path));
606
607         ai->ai_socktype = socktype;
608         /*
609          * ai->ai_flags, ai->ai_protocol, ai->ai_canonname,
610          * and ai->ai_next were initialized to zero.
611          */
612
613         *res = ai;
614         return (0);
615 }
616 #endif
617
618 /*
619  * Allocate an addrinfo structure, and a sockaddr structure
620  * of the specificed length.  We initialize:
621  *      ai_addrlen
622  *      ai_family
623  *      ai_addr
624  *      ai_addr->sa_family
625  *      ai_addr->sa_len (LWRES_PLATFORM_HAVESALEN)
626  * and everything else is initialized to zero.
627  */
628 static struct addrinfo *
629 ai_alloc(int family, int addrlen) {
630         struct addrinfo *ai;
631
632         ai = (struct addrinfo *)calloc(1, sizeof(*ai));
633         if (ai == NULL)
634                 return (NULL);
635
636         ai->ai_addr = SA(calloc(1, addrlen));
637         if (ai->ai_addr == NULL) {
638                 free(ai);
639                 return (NULL);
640         }
641         ai->ai_addrlen = addrlen;
642         ai->ai_family = family;
643         ai->ai_addr->sa_family = family;
644 #ifdef LWRES_PLATFORM_HAVESALEN
645         ai->ai_addr->sa_len = addrlen;
646 #endif
647         return (ai);
648 }
649
650 static struct addrinfo *
651 ai_clone(struct addrinfo *oai, int family) {
652         struct addrinfo *ai;
653
654         ai = ai_alloc(family, ((family == AF_INET6) ?
655             sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)));
656
657         if (ai == NULL) {
658                 lwres_freeaddrinfo(oai);
659                 return (NULL);
660         }
661         if (oai == NULL)
662                 return (ai);
663
664         ai->ai_flags = oai->ai_flags;
665         ai->ai_socktype = oai->ai_socktype;
666         ai->ai_protocol = oai->ai_protocol;
667         ai->ai_canonname = NULL;
668         ai->ai_next = oai;
669         return (ai);
670 }
671
672 static struct addrinfo *
673 ai_reverse(struct addrinfo *oai) {
674         struct addrinfo *nai, *tai;
675
676         nai = NULL;
677
678         while (oai != NULL) {
679                 /*
680                  * Grab one off the old list.
681                  */
682                 tai = oai;
683                 oai = oai->ai_next;
684                 /*
685                  * Put it on the front of the new list.
686                  */
687                 tai->ai_next = nai;
688                 nai = tai;
689         }
690         return (nai);
691 }