1fcf3ce44SJohn Forte /*
2fcf3ce44SJohn Forte * CDDL HEADER START
3fcf3ce44SJohn Forte *
4fcf3ce44SJohn Forte * The contents of this file are subject to the terms of the
5fcf3ce44SJohn Forte * Common Development and Distribution License (the "License").
6fcf3ce44SJohn Forte * You may not use this file except in compliance with the License.
7fcf3ce44SJohn Forte *
8fcf3ce44SJohn Forte * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9fcf3ce44SJohn Forte * or http://www.opensolaris.org/os/licensing.
10fcf3ce44SJohn Forte * See the License for the specific language governing permissions
11fcf3ce44SJohn Forte * and limitations under the License.
12fcf3ce44SJohn Forte *
13fcf3ce44SJohn Forte * When distributing Covered Code, include this CDDL HEADER in each
14fcf3ce44SJohn Forte * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fcf3ce44SJohn Forte * If applicable, add the following below this CDDL HEADER, with the
16fcf3ce44SJohn Forte * fields enclosed by brackets "[]" replaced with your own identifying
17fcf3ce44SJohn Forte * information: Portions Copyright [yyyy] [name of copyright owner]
18fcf3ce44SJohn Forte *
19fcf3ce44SJohn Forte * CDDL HEADER END
20fcf3ce44SJohn Forte */
21*59927d31SYuri Pankov
22fcf3ce44SJohn Forte /*
23fcf3ce44SJohn Forte * Copyright 2000 by Cisco Systems, Inc. All rights reserved.
244246c8e9SJack Meng * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
25fcf3ce44SJohn Forte * Use is subject to license terms.
26*59927d31SYuri Pankov * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
27*59927d31SYuri Pankov */
28*59927d31SYuri Pankov
29*59927d31SYuri Pankov /*
30fcf3ce44SJohn Forte * iSCSI Software Initiator
31fcf3ce44SJohn Forte */
32fcf3ce44SJohn Forte
33fcf3ce44SJohn Forte #include <sys/types.h>
34fcf3ce44SJohn Forte #include <sys/errno.h>
35fcf3ce44SJohn Forte #include <sys/conf.h>
36fcf3ce44SJohn Forte #include <sys/cmn_err.h>
37fcf3ce44SJohn Forte #include <sys/stat.h>
38fcf3ce44SJohn Forte #include <sys/pathname.h>
39fcf3ce44SJohn Forte #include <sys/door.h>
40fcf3ce44SJohn Forte #include <sys/kmem.h>
41fcf3ce44SJohn Forte #include <sys/socket.h>
42fcf3ce44SJohn Forte #include <sys/fs/snode.h>
43fcf3ce44SJohn Forte #include <netinet/in.h>
44fcf3ce44SJohn Forte
45fcf3ce44SJohn Forte #include <sys/scsi/adapters/iscsi_door.h>
46fcf3ce44SJohn Forte #include "iscsi.h"
47fcf3ce44SJohn Forte
48fcf3ce44SJohn Forte #define ISCSI_DOOR_MAX_SEMA_VALUE 16
49fcf3ce44SJohn Forte
50fcf3ce44SJohn Forte static boolean_t iscsi_door_init = B_FALSE;
51fcf3ce44SJohn Forte static ksema_t iscsi_door_sema;
52fcf3ce44SJohn Forte static krwlock_t iscsi_door_lock;
53fcf3ce44SJohn Forte static door_handle_t iscsi_door_handle;
54fcf3ce44SJohn Forte
55fcf3ce44SJohn Forte typedef struct _mybuffer {
56fcf3ce44SJohn Forte size_t signature;
57fcf3ce44SJohn Forte size_t size;
58fcf3ce44SJohn Forte } mybuffer_t;
59fcf3ce44SJohn Forte
60fcf3ce44SJohn Forte /*
61fcf3ce44SJohn Forte * iscsi_door_ini
62fcf3ce44SJohn Forte *
63fcf3ce44SJohn Forte * This function initializes the variables needed to handle the door upcall.
64fcf3ce44SJohn Forte */
65fcf3ce44SJohn Forte boolean_t
iscsi_door_ini(void)66fcf3ce44SJohn Forte iscsi_door_ini(void)
67fcf3ce44SJohn Forte {
68fcf3ce44SJohn Forte ASSERT(!iscsi_door_init);
69fcf3ce44SJohn Forte if (!iscsi_door_init) {
70fcf3ce44SJohn Forte rw_init(
71fcf3ce44SJohn Forte &iscsi_door_lock,
72fcf3ce44SJohn Forte NULL,
73fcf3ce44SJohn Forte RW_DRIVER,
74fcf3ce44SJohn Forte NULL);
75fcf3ce44SJohn Forte
76fcf3ce44SJohn Forte sema_init(
77fcf3ce44SJohn Forte &iscsi_door_sema,
78fcf3ce44SJohn Forte ISCSI_DOOR_MAX_SEMA_VALUE,
79fcf3ce44SJohn Forte NULL,
80fcf3ce44SJohn Forte SEMA_DRIVER,
81fcf3ce44SJohn Forte NULL);
82fcf3ce44SJohn Forte
83fcf3ce44SJohn Forte iscsi_door_handle = NULL;
84fcf3ce44SJohn Forte iscsi_door_init = B_TRUE;
85fcf3ce44SJohn Forte return (B_TRUE);
86fcf3ce44SJohn Forte }
87fcf3ce44SJohn Forte return (B_FALSE);
88fcf3ce44SJohn Forte }
89fcf3ce44SJohn Forte
90fcf3ce44SJohn Forte /*
91fcf3ce44SJohn Forte * iscsi_door_term
92fcf3ce44SJohn Forte *
93fcf3ce44SJohn Forte * This function releases the resources allocated to handle the door
94fcf3ce44SJohn Forte * upcall. It disconnects from the door if currently connected.
95fcf3ce44SJohn Forte */
96fcf3ce44SJohn Forte boolean_t
iscsi_door_term(void)97fcf3ce44SJohn Forte iscsi_door_term(void)
98fcf3ce44SJohn Forte {
99fcf3ce44SJohn Forte ASSERT(iscsi_door_init);
100fcf3ce44SJohn Forte if (iscsi_door_init) {
101fcf3ce44SJohn Forte iscsi_door_init = B_FALSE;
102fcf3ce44SJohn Forte iscsi_door_unbind();
103fcf3ce44SJohn Forte rw_destroy(&iscsi_door_lock);
104fcf3ce44SJohn Forte sema_destroy(&iscsi_door_sema);
105fcf3ce44SJohn Forte return (B_TRUE);
106fcf3ce44SJohn Forte }
107fcf3ce44SJohn Forte return (B_FALSE);
108fcf3ce44SJohn Forte }
109fcf3ce44SJohn Forte
110fcf3ce44SJohn Forte /*
111fcf3ce44SJohn Forte * iscsi_door_bind
112fcf3ce44SJohn Forte *
113fcf3ce44SJohn Forte * This function tries to connect the iscsi_door. If it succeeds
114fcf3ce44SJohn Forte * it keeps the vnode.
115fcf3ce44SJohn Forte */
116fcf3ce44SJohn Forte boolean_t
iscsi_door_bind(int did)117fcf3ce44SJohn Forte iscsi_door_bind(
118fcf3ce44SJohn Forte int did
119fcf3ce44SJohn Forte )
120fcf3ce44SJohn Forte {
121fcf3ce44SJohn Forte door_handle_t new_handle;
122fcf3ce44SJohn Forte
123fcf3ce44SJohn Forte new_handle = door_ki_lookup(did);
124fcf3ce44SJohn Forte if (new_handle == NULL) {
125fcf3ce44SJohn Forte /* The lookup failed. */
126fcf3ce44SJohn Forte return (B_FALSE);
127fcf3ce44SJohn Forte }
128fcf3ce44SJohn Forte
129fcf3ce44SJohn Forte /* The new handle is stored. If we had one, it is released. */
130fcf3ce44SJohn Forte rw_enter(&iscsi_door_lock, RW_WRITER);
131fcf3ce44SJohn Forte if (iscsi_door_handle != NULL) {
132fcf3ce44SJohn Forte door_ki_rele(iscsi_door_handle);
133fcf3ce44SJohn Forte }
134fcf3ce44SJohn Forte iscsi_door_handle = new_handle;
135fcf3ce44SJohn Forte rw_exit(&iscsi_door_lock);
136fcf3ce44SJohn Forte
137fcf3ce44SJohn Forte return (B_TRUE);
138fcf3ce44SJohn Forte }
139fcf3ce44SJohn Forte
140fcf3ce44SJohn Forte /*
141fcf3ce44SJohn Forte * iscsi_door_unbind
142fcf3ce44SJohn Forte *
143fcf3ce44SJohn Forte * This function releases the current door handle.
144fcf3ce44SJohn Forte */
145fcf3ce44SJohn Forte void
iscsi_door_unbind(void)146fcf3ce44SJohn Forte iscsi_door_unbind(void)
147fcf3ce44SJohn Forte {
148fcf3ce44SJohn Forte rw_enter(&iscsi_door_lock, RW_WRITER);
149fcf3ce44SJohn Forte if (iscsi_door_handle != NULL) {
150fcf3ce44SJohn Forte door_ki_rele(iscsi_door_handle);
151fcf3ce44SJohn Forte iscsi_door_handle = NULL;
152fcf3ce44SJohn Forte }
153fcf3ce44SJohn Forte rw_exit(&iscsi_door_lock);
154fcf3ce44SJohn Forte }
155fcf3ce44SJohn Forte
156fcf3ce44SJohn Forte /*
157fcf3ce44SJohn Forte * iscsi_door_upcall
158fcf3ce44SJohn Forte *
159fcf3ce44SJohn Forte * This function tries to call the iscsi_door.
160fcf3ce44SJohn Forte */
161fcf3ce44SJohn Forte static
162fcf3ce44SJohn Forte boolean_t
iscsi_door_upcall(door_arg_t * arg)163fcf3ce44SJohn Forte iscsi_door_upcall(door_arg_t *arg)
164fcf3ce44SJohn Forte {
165fcf3ce44SJohn Forte int error;
166fcf3ce44SJohn Forte
167fcf3ce44SJohn Forte /*
168fcf3ce44SJohn Forte * This semaphore limits the number of simultaneous calls
169fcf3ce44SJohn Forte * to the door.
170fcf3ce44SJohn Forte */
171fcf3ce44SJohn Forte sema_p(&iscsi_door_sema);
172fcf3ce44SJohn Forte /*
173fcf3ce44SJohn Forte * The mutex protecting the iscsi_door_handle is entered.
174fcf3ce44SJohn Forte */
175fcf3ce44SJohn Forte rw_enter(&iscsi_door_lock, RW_READER);
176fcf3ce44SJohn Forte
177fcf3ce44SJohn Forte if (iscsi_door_handle == NULL) {
178fcf3ce44SJohn Forte /* There's no door handle. */
179fcf3ce44SJohn Forte rw_exit(&iscsi_door_lock);
180fcf3ce44SJohn Forte sema_v(&iscsi_door_sema);
181fcf3ce44SJohn Forte return (B_FALSE);
182fcf3ce44SJohn Forte }
183fcf3ce44SJohn Forte error = door_ki_upcall(iscsi_door_handle, arg);
184fcf3ce44SJohn Forte
185fcf3ce44SJohn Forte rw_exit(&iscsi_door_lock);
186fcf3ce44SJohn Forte sema_v(&iscsi_door_sema);
187fcf3ce44SJohn Forte
188fcf3ce44SJohn Forte if (error != 0) {
189fcf3ce44SJohn Forte return (B_FALSE);
190fcf3ce44SJohn Forte } else {
191fcf3ce44SJohn Forte return (B_TRUE);
192fcf3ce44SJohn Forte }
193fcf3ce44SJohn Forte }
194fcf3ce44SJohn Forte
195fcf3ce44SJohn Forte /*
196fcf3ce44SJohn Forte * kfreehostent
197fcf3ce44SJohn Forte *
198fcf3ce44SJohn Forte * This function frees the memory returned by kgetipnodebyname.
199fcf3ce44SJohn Forte */
200fcf3ce44SJohn Forte void
kfreehostent(struct hostent * hptr)201fcf3ce44SJohn Forte kfreehostent(
202fcf3ce44SJohn Forte struct hostent *hptr
203fcf3ce44SJohn Forte )
204fcf3ce44SJohn Forte {
205fcf3ce44SJohn Forte mybuffer_t *buffer;
206fcf3ce44SJohn Forte
207fcf3ce44SJohn Forte ASSERT(hptr != NULL);
208fcf3ce44SJohn Forte if (hptr) {
209fcf3ce44SJohn Forte buffer = (mybuffer_t *)((char *)hptr - sizeof (mybuffer_t));
210fcf3ce44SJohn Forte ASSERT(buffer->signature == ISCSI_DOOR_REQ_SIGNATURE);
211fcf3ce44SJohn Forte if (buffer->signature == ISCSI_DOOR_REQ_SIGNATURE) {
212fcf3ce44SJohn Forte kmem_free((void *)buffer, buffer->size);
213fcf3ce44SJohn Forte return;
214fcf3ce44SJohn Forte }
215fcf3ce44SJohn Forte }
216fcf3ce44SJohn Forte /* A message should be logged here. */
217fcf3ce44SJohn Forte }
218fcf3ce44SJohn Forte
219fcf3ce44SJohn Forte /*
220fcf3ce44SJohn Forte * kgetipnodebyname
221fcf3ce44SJohn Forte *
222fcf3ce44SJohn Forte * This function builds a request that will be sent to the iscsi_door.
223fcf3ce44SJohn Forte * The iSCSI door after receiving the request calls getipnodebyaddr().
224fcf3ce44SJohn Forte * for more information on the input, output parameter and return value,
225fcf3ce44SJohn Forte * consult the man page for getipnodebyname().
226fcf3ce44SJohn Forte *
227fcf3ce44SJohn Forte * Before calling the iscsi door this function tries to do the conversion
228fcf3ce44SJohn Forte * locally. If a name resolution is needed the iscsi door is called.
229fcf3ce44SJohn Forte *
230fcf3ce44SJohn Forte * There's some limitations to the information returned by this function.
231fcf3ce44SJohn Forte * Only one address of the address list returned by getipnodebyname() is
232fcf3ce44SJohn Forte * returned. The other parameters of the structure should be ignored.
233fcf3ce44SJohn Forte */
234fcf3ce44SJohn Forte struct hostent *
kgetipnodebyname(const char * name,int af,int flags,int * error_num)235fcf3ce44SJohn Forte kgetipnodebyname(
236fcf3ce44SJohn Forte const char *name,
237fcf3ce44SJohn Forte int af,
238fcf3ce44SJohn Forte int flags,
239fcf3ce44SJohn Forte int *error_num
240fcf3ce44SJohn Forte )
241fcf3ce44SJohn Forte {
242fcf3ce44SJohn Forte door_arg_t arg;
243fcf3ce44SJohn Forte mybuffer_t *buffer;
244fcf3ce44SJohn Forte size_t msg_size = ISCSI_DOOR_MAX_DATA_SIZE;
245fcf3ce44SJohn Forte size_t hostent_size = ISCSI_DOOR_MAX_DATA_SIZE;
246fcf3ce44SJohn Forte size_t buffer_size;
247fcf3ce44SJohn Forte getipnodebyname_req_t *req;
248fcf3ce44SJohn Forte getipnodebyname_cnf_t *cnf;
249fcf3ce44SJohn Forte struct hostent *hptr;
250fcf3ce44SJohn Forte
251fcf3ce44SJohn Forte
252fcf3ce44SJohn Forte buffer_size = msg_size + hostent_size + sizeof (mybuffer_t);
253fcf3ce44SJohn Forte buffer = (mybuffer_t *)kmem_zalloc(buffer_size, KM_SLEEP);
254fcf3ce44SJohn Forte
255fcf3ce44SJohn Forte if (buffer) {
256fcf3ce44SJohn Forte
257fcf3ce44SJohn Forte /*
258fcf3ce44SJohn Forte * The buffer was successfully allocated.
259fcf3ce44SJohn Forte *
260fcf3ce44SJohn Forte * Buffer
261fcf3ce44SJohn Forte *
262fcf3ce44SJohn Forte * +--------------------+ <--- buffer
263fcf3ce44SJohn Forte * | mybuffer_t |
264fcf3ce44SJohn Forte * +--------------------+ <--- hptr
265fcf3ce44SJohn Forte * | |
266fcf3ce44SJohn Forte * | |
267fcf3ce44SJohn Forte * | hostent_size |
268fcf3ce44SJohn Forte * | |
269fcf3ce44SJohn Forte * | |
270fcf3ce44SJohn Forte * | |
271fcf3ce44SJohn Forte * +--------------------+ <--- req, cnf
272fcf3ce44SJohn Forte * | |
273fcf3ce44SJohn Forte * | |
274fcf3ce44SJohn Forte * | |
275fcf3ce44SJohn Forte * | msg_size |
276fcf3ce44SJohn Forte * | |
277fcf3ce44SJohn Forte * | |
278fcf3ce44SJohn Forte * | |
279fcf3ce44SJohn Forte * +--------------------+
280fcf3ce44SJohn Forte */
281fcf3ce44SJohn Forte buffer->signature = ISCSI_DOOR_REQ_SIGNATURE;
282fcf3ce44SJohn Forte buffer->size = buffer_size;
283fcf3ce44SJohn Forte
284fcf3ce44SJohn Forte hptr = (struct hostent *)((char *)buffer + sizeof (mybuffer_t));
285fcf3ce44SJohn Forte req = (getipnodebyname_req_t *)((char *)hptr + hostent_size);
286fcf3ce44SJohn Forte cnf = (getipnodebyname_cnf_t *)((char *)hptr + hostent_size);
287fcf3ce44SJohn Forte
288fcf3ce44SJohn Forte hostent_size -= sizeof (struct hostent);
289fcf3ce44SJohn Forte
290fcf3ce44SJohn Forte /*
291fcf3ce44SJohn Forte * We try first locally. If the conversion cannot be done
292fcf3ce44SJohn Forte * by inet_pton the door is called.
293fcf3ce44SJohn Forte * The cnf address is used as output buffer.
294fcf3ce44SJohn Forte * inet_pton returns '1' if the conversion was successful.
295fcf3ce44SJohn Forte */
296fcf3ce44SJohn Forte switch (af) {
297fcf3ce44SJohn Forte case AF_INET:
298fcf3ce44SJohn Forte hptr->h_length = sizeof (struct in_addr);
299fcf3ce44SJohn Forte break;
300fcf3ce44SJohn Forte case AF_INET6:
301fcf3ce44SJohn Forte hptr->h_length = sizeof (struct in6_addr);
302fcf3ce44SJohn Forte break;
303fcf3ce44SJohn Forte default:
304fcf3ce44SJohn Forte kfreehostent(hptr);
305fcf3ce44SJohn Forte *error_num = NO_RECOVERY;
306fcf3ce44SJohn Forte return (NULL);
307fcf3ce44SJohn Forte }
308fcf3ce44SJohn Forte if ((msg_size < hptr->h_length) ||
309fcf3ce44SJohn Forte (hostent_size < sizeof (char *))) {
310fcf3ce44SJohn Forte kfreehostent(hptr);
311fcf3ce44SJohn Forte *error_num = NO_RECOVERY;
312fcf3ce44SJohn Forte return (NULL);
313fcf3ce44SJohn Forte }
314fcf3ce44SJohn Forte if (inet_pton(af, (char *)name, cnf) == 1) {
315fcf3ce44SJohn Forte /*
316fcf3ce44SJohn Forte * inet_pton converted the string successfully.
317fcf3ce44SJohn Forte */
318fcf3ce44SJohn Forte hptr->h_addrtype = af;
319fcf3ce44SJohn Forte hptr->h_addr_list = (char **)((char *)hptr +
320fcf3ce44SJohn Forte sizeof (struct hostent));
321fcf3ce44SJohn Forte *hptr->h_addr_list = (char *)cnf;
322fcf3ce44SJohn Forte return (hptr);
323fcf3ce44SJohn Forte }
324fcf3ce44SJohn Forte
325fcf3ce44SJohn Forte /*
326fcf3ce44SJohn Forte * The name couldn't ne converted by inet_pton. The door is
327fcf3ce44SJohn Forte * called.
328fcf3ce44SJohn Forte */
329fcf3ce44SJohn Forte
330fcf3ce44SJohn Forte /* Header initialization. */
331fcf3ce44SJohn Forte req->hdr.signature = ISCSI_DOOR_REQ_SIGNATURE;
332fcf3ce44SJohn Forte req->hdr.version = ISCSI_DOOR_REQ_VERSION_1;
333fcf3ce44SJohn Forte req->hdr.opcode = ISCSI_DOOR_GETIPNODEBYNAME_REQ;
334fcf3ce44SJohn Forte
335fcf3ce44SJohn Forte /* Body initialization. */
336fcf3ce44SJohn Forte req->name_length = strlen(name);
337fcf3ce44SJohn Forte if (req->name_length >
338fcf3ce44SJohn Forte (msg_size - sizeof (getipnodebyname_req_t) - 1)) {
339fcf3ce44SJohn Forte kfreehostent(hptr);
340fcf3ce44SJohn Forte *error_num = NO_RECOVERY;
341fcf3ce44SJohn Forte return (NULL);
342fcf3ce44SJohn Forte }
343fcf3ce44SJohn Forte
344fcf3ce44SJohn Forte req->name_offset = sizeof (getipnodebyname_req_t);
345fcf3ce44SJohn Forte req->af = af;
346fcf3ce44SJohn Forte req->flags = flags;
347fcf3ce44SJohn Forte bcopy(
348fcf3ce44SJohn Forte name,
349fcf3ce44SJohn Forte ((char *)req + req->name_offset),
350fcf3ce44SJohn Forte req->name_length);
351fcf3ce44SJohn Forte
352fcf3ce44SJohn Forte /* Door argument initialization. */
353fcf3ce44SJohn Forte arg.data_ptr = (char *)req;
354fcf3ce44SJohn Forte arg.data_size = msg_size;
355fcf3ce44SJohn Forte arg.desc_num = 0;
356fcf3ce44SJohn Forte arg.desc_ptr = NULL;
357fcf3ce44SJohn Forte arg.rbuf = (char *)cnf;
358fcf3ce44SJohn Forte arg.rsize = msg_size;
359fcf3ce44SJohn Forte
360fcf3ce44SJohn Forte if (iscsi_door_upcall(&arg) == B_FALSE) {
361fcf3ce44SJohn Forte /* The door call failed */
362fcf3ce44SJohn Forte kfreehostent(hptr);
363fcf3ce44SJohn Forte *error_num = NO_RECOVERY;
364fcf3ce44SJohn Forte return (NULL);
365fcf3ce44SJohn Forte }
366fcf3ce44SJohn Forte
367fcf3ce44SJohn Forte /*
368fcf3ce44SJohn Forte * The door call itself was successful. The value returned
369fcf3ce44SJohn Forte * in arg.rbuf should be cnf, but we never know.
370fcf3ce44SJohn Forte */
371fcf3ce44SJohn Forte cnf = (getipnodebyname_cnf_t *)arg.rbuf;
372fcf3ce44SJohn Forte
373fcf3ce44SJohn Forte if ((cnf == NULL) ||
374fcf3ce44SJohn Forte (arg.rsize < sizeof (getipnodebyname_cnf_t)) ||
375fcf3ce44SJohn Forte (cnf->hdr.signature != ISCSI_DOOR_REQ_SIGNATURE) ||
376fcf3ce44SJohn Forte (cnf->hdr.version != ISCSI_DOOR_REQ_VERSION_1) ||
377fcf3ce44SJohn Forte (cnf->hdr.opcode != ISCSI_DOOR_GETIPNODEBYNAME_CNF) ||
378fcf3ce44SJohn Forte ((cnf->hdr.status != ISCSI_DOOR_STATUS_SUCCESS) &&
379fcf3ce44SJohn Forte (cnf->hdr.status != ISCSI_DOOR_STATUS_MORE))) {
380fcf3ce44SJohn Forte /* The door didn't like the request */
381fcf3ce44SJohn Forte kfreehostent(hptr);
382fcf3ce44SJohn Forte *error_num = NO_RECOVERY;
383fcf3ce44SJohn Forte return (NULL);
384fcf3ce44SJohn Forte }
385fcf3ce44SJohn Forte
386fcf3ce44SJohn Forte if (cnf->h_addr_list_length == 0) {
387fcf3ce44SJohn Forte kfreehostent(hptr);
388fcf3ce44SJohn Forte *error_num = HOST_NOT_FOUND;
389fcf3ce44SJohn Forte return (NULL);
390fcf3ce44SJohn Forte }
391fcf3ce44SJohn Forte
392fcf3ce44SJohn Forte hptr->h_addrtype = cnf->h_addrtype;
393fcf3ce44SJohn Forte hptr->h_length = cnf->h_addrlen;
394fcf3ce44SJohn Forte hptr->h_addr_list = (char **)((char *)hptr +
395fcf3ce44SJohn Forte sizeof (struct hostent));
396fcf3ce44SJohn Forte *hptr->h_addr_list = ((char *)cnf + cnf->h_addr_list_offset);
397fcf3ce44SJohn Forte return (hptr);
398fcf3ce44SJohn Forte } else {
399fcf3ce44SJohn Forte *error_num = NO_RECOVERY;
400fcf3ce44SJohn Forte return (NULL);
401fcf3ce44SJohn Forte }
402fcf3ce44SJohn Forte }
403