2 * Copyright (c) 1999, Boris Popov
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by Boris Popov.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * $FreeBSD: src/sys/netncp/ncp_sock.c,v 1.2 1999/10/12 10:36:59 bp Exp $
33 * $DragonFly: src/sys/netproto/ncp/ncp_sock.c,v 1.20 2007/05/18 17:05:12 dillon Exp $
35 * Low level socket routines
41 #if !defined(INET) && !defined(IPX)
42 #error "NCP requires either INET of IPX protocol family"
45 #include <sys/param.h>
46 #include <sys/errno.h>
47 #include <sys/malloc.h>
48 #include <sys/systm.h>
50 #include <sys/protosw.h>
51 #include <sys/socket.h>
52 #include <sys/socketvar.h>
53 #include <sys/socketops.h>
54 #include <sys/kernel.h>
56 #include <sys/fcntl.h>
57 #include <sys/syslog.h>
59 #include <net/route.h>
60 #include <sys/thread2.h>
63 #include <netproto/ipx/ipx.h>
64 #include <netproto/ipx/ipx_pcb.h>
74 #define ipx_setnullnet(x) ((x).x_net.s_net[0]=0); ((x).x_net.s_net[1]=0);
75 #define ipx_setnullhost(x) ((x).x_host.s_host[0] = 0); \
76 ((x).x_host.s_host[1] = 0); ((x).x_host.s_host[2] = 0);
79 /*int ncp_poll(struct socket *so, int events);*/
80 /*static int ncp_getsockname(struct socket *so, caddr_t asa, int *alen);*/
81 static int ncp_soconnect(struct socket
*so
,struct sockaddr
*target
, struct thread
*p
);
84 /* This will need only if native IP used, or (unlikely) NCP will be
85 * implemented on the socket level
88 ncp_soconnect(struct socket
*so
,struct sockaddr
*target
, struct thread
*td
) {
91 error
= soconnect(so
, (struct sockaddr
*)target
, td
);
95 * Wait for the connection to complete. Cribbed from the
96 * connect system call but with the wait timing out so
97 * that interruptible mounts don't hang here for a long time.
101 while ((so
->so_state
& SS_ISCONNECTING
) && so
->so_error
== 0) {
102 tsleep((caddr_t
)&so
->so_timeo
, 0, "ncpcon", 2 * hz
);
103 if ((so
->so_state
& SS_ISCONNECTING
) &&
104 so
->so_error
== 0 /*&& rep &&*/) {
105 so
->so_state
&= ~SS_ISCONNECTING
;
111 error
= so
->so_error
;
123 ncp_getsockname(struct socket
*so
, caddr_t asa
, int *alen
) {
128 error
= so_pru_sockaddr(so
, &sa
);
131 len
= min(len
, sa
->sa_len
);
132 bcopy(sa
, (caddr_t
)asa
, (u_int
)len
);
142 ncp_sock_recv(struct socket
*so
, struct sockbuf
*sio
)
146 sbinit(sio
, 1000000); /* limit data returned (inexact, hint only) */
147 flags
= MSG_DONTWAIT
;
149 error
= so_pru_soreceive(so
, NULL
, NULL
, sio
, NULL
, &flags
);
150 #ifdef NCP_SOCKET_DEBUG
152 kprintf("ncp_recv: err=%d\n", error
);
158 ncp_sock_send(struct socket
*so
, struct mbuf
*top
, struct ncp_rq
*rqp
)
160 struct thread
*td
= curthread
; /* XXX */
161 struct sockaddr
*to
= 0;
162 struct ncp_conn
*conn
= rqp
->conn
;
168 m
= m_copym(top
, 0, M_COPYALL
, MB_WAIT
);
170 error
= so_pru_sosend(so
, to
, NULL
, m
, NULL
, flags
, td
);
171 if (error
== 0 || error
== EINTR
|| error
== ENETDOWN
)
173 if (rqp
->rexmit
== 0) break;
175 tsleep(&sendwait
, 0, "ncprsn", conn
->li
.timeout
* hz
);
176 error
= ncp_chkintr(conn
, td
);
177 if (error
== EINTR
) break;
180 log(LOG_INFO
, "ncp_send: error %d for server %s", error
, conn
->li
.server
);
186 ncp_poll(struct socket
*so
, int events
)
188 return (so_pru_sopoll(so
, events
, NULL
));
192 ncp_sock_rselect(struct socket
*so
, struct thread
*td
,
193 struct timeval
*tv
, int events
)
195 struct timeval atv
,rtv
,ttv
;
196 struct lwp
*lp
= td
->td_lwp
;
203 if (itimerfix(&atv
)) {
207 getmicrouptime(&rtv
);
208 timevaladd(&atv
, &rtv
);
212 lp
->lwp_flag
|= LWP_SELECT
;
213 error
= ncp_poll(so
, events
);
219 getmicrouptime(&rtv
);
220 if (timevalcmp(&rtv
, &atv
, >=))
223 timevalsub(&ttv
, &rtv
);
224 timo
= tvtohz_high(&ttv
);
227 if ((lp
->lwp_flag
& LWP_SELECT
) == 0) {
231 lp
->lwp_flag
&= ~LWP_SELECT
;
232 error
= tsleep((caddr_t
)&selwait
, 0, "ncpslt", timo
);
235 lp
->lwp_flag
&= ~LWP_SELECT
;
236 if (error
== ERESTART
) {
237 /* kprintf("Signal: %x", CURSIG(p));*/
245 * Connect to specified server via IPX
248 ncp_sock_connect_ipx(struct ncp_conn
*conn
) {
249 struct sockaddr_ipx sipx
;
251 struct thread
*td
= conn
->td
;
252 int addrlen
, error
, count
;
254 sipx
.sipx_port
= htons(0);
256 for (count
= 0;;count
++) {
257 if (count
> (IPXPORT_WELLKNOWN
-IPXPORT_RESERVED
)*2) {
261 conn
->ncp_so
= conn
->wdg_so
= NULL
;
262 checkbad(socreate(AF_IPX
, &conn
->ncp_so
, SOCK_DGRAM
, 0, td
));
263 if (conn
->li
.opt
& NCP_OPT_WDOG
)
264 checkbad(socreate(AF_IPX
, &conn
->wdg_so
, SOCK_DGRAM
,0,td
));
265 addrlen
= sizeof(sipx
);
266 sipx
.sipx_family
= AF_IPX
;
267 ipx_setnullnet(sipx
.sipx_addr
);
268 ipx_setnullhost(sipx
.sipx_addr
);
269 sipx
.sipx_len
= addrlen
;
270 error
= sobind(conn
->ncp_so
, (struct sockaddr
*)&sipx
, td
);
272 if ((conn
->li
.opt
& NCP_OPT_WDOG
) == 0)
274 sipx
.sipx_addr
= sotoipxpcb(conn
->ncp_so
)->ipxp_laddr
;
275 sipx
.sipx_port
= htons(ntohs(sipx
.sipx_port
) + 1);
276 ipx_setnullnet(sipx
.sipx_addr
);
277 ipx_setnullhost(sipx
.sipx_addr
);
278 error
= sobind(conn
->wdg_so
, (struct sockaddr
*)&sipx
, td
);
281 if (error
!= EADDRINUSE
) goto bad
;
282 sipx
.sipx_port
= htons((ntohs(sipx
.sipx_port
)+4) & 0xfff8);
283 soclose(conn
->ncp_so
, FNONBLOCK
);
285 soclose(conn
->wdg_so
, FNONBLOCK
);
287 npcb
= sotoipxpcb(conn
->ncp_so
);
288 npcb
->ipxp_dpt
= IPXPROTO_NCP
;
289 /* IPXrouted must be running, i.e. route must be presented */
290 conn
->li
.ipxaddr
.sipx_len
= sizeof(struct sockaddr_ipx
);
291 checkbad(ncp_soconnect(conn
->ncp_so
, &conn
->li
.saddr
, td
));
293 sotoipxpcb(conn
->wdg_so
)->ipxp_laddr
.x_net
= npcb
->ipxp_laddr
.x_net
;
294 sotoipxpcb(conn
->wdg_so
)->ipxp_laddr
.x_host
= npcb
->ipxp_laddr
.x_host
;
297 conn
->flags
|= NCPFL_SOCONN
;
300 if (ncp_burst_enabled
) {
301 checkbad(socreate(AF_IPX
, &conn
->bc_so
, SOCK_DGRAM
, 0, td
));
302 bzero(&sipx
, sizeof(sipx
));
303 sipx
.sipx_len
= sizeof(sipx
);
304 checkbad(sobind(conn
->bc_so
, (struct sockaddr
*)&sipx
, td
));
305 checkbad(ncp_soconnect(conn
->bc_so
, &conn
->li
.saddr
, td
));
309 conn
->flags
|= NCPFL_SOCONN
;
310 ncp_sock_checksum(conn
, 0);
314 ncp_sock_disconnect(conn
);
319 ncp_sock_checksum(struct ncp_conn
*conn
, int enable
) {
321 #ifdef SO_IPX_CHECKSUM
323 sotoipxpcb(conn
->ncp_so
)->ipxp_flags
|= IPXP_CHECKSUM
;
325 sotoipxpcb(conn
->ncp_so
)->ipxp_flags
&= ~IPXP_CHECKSUM
;
334 * Connect to specified server via IP
337 ncp_sock_connect_in(struct ncp_conn
*conn
) {
338 struct sockaddr_in sin
;
339 struct thread
*td
= conn
->td
;
340 int addrlen
=sizeof(sin
), error
;
344 conn
->ncp_so
= conn
->wdg_so
= NULL
;
345 checkbad(socreate(AF_INET
, &conn
->ncp_so
, SOCK_DGRAM
, IPPROTO_UDP
, td
));
346 sin
.sin_family
= AF_INET
;
347 sin
.sin_len
= addrlen
;
348 checkbad(sobind(conn
->ncp_so
, (struct sockaddr
*)&sin
, td
));
349 checkbad(ncp_soconnect(conn
->ncp_so
,(struct sockaddr
*)&conn
->li
.addr
, td
));
351 conn
->flags
|= NCPFL_SOCONN
;
354 ncp_sock_disconnect(conn
);
361 * Connection expected to be locked
364 ncp_sock_disconnect(struct ncp_conn
*conn
) {
366 conn
->flags
&= ~(NCPFL_SOCONN
| NCPFL_ATTACHED
| NCPFL_LOGGED
);
369 conn
->ncp_so
= (struct socket
*)0;
370 soshutdown(so
, SHUT_RDWR
);
371 soclose(so
, FNONBLOCK
);
375 conn
->wdg_so
= (struct socket
*)0;
376 soshutdown(so
, SHUT_RDWR
);
377 soclose(so
, FNONBLOCK
);
382 conn
->bc_so
= (struct socket
*)NULL
;
383 soshutdown(so
, SHUT_RDWR
);
384 soclose(so
, FNONBLOCK
);
392 ncp_watchdog(struct ncp_conn
*conn
) {
394 int error
, len
, flags
;
400 while (conn
->wdg_so
) { /* not a loop */
402 sbinit(&sio
, 1000000);
403 flags
= MSG_DONTWAIT
;
404 error
= so_pru_soreceive(so
, (struct sockaddr
**)&sa
,
405 NULL
, &sio
, NULL
, &flags
);
409 NCPSDEBUG("got watch dog %d\n",len
);
414 buf
= mtod(sio
.sb_mb
, char *);
420 error
= so_pru_sosend(so
, sa
, NULL
, sio
.sb_mb
, NULL
, 0, curthread
);
421 NCPSDEBUG("send watch dog %d\n",error
);
431 ncp_check_conn(struct ncp_conn
*conn
) {
432 if (conn
== NULL
|| !(conn
->flags
& NCPFL_ATTACHED
))