FreeBSD/Linux Kernel Cross Reference
sys/netncp/ncp_sock.c
1 /*-
2 * Copyright (c) 1999, 2001 Boris Popov
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
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 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * Low level socket routines
27 */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD: releng/9.2/sys/netncp/ncp_sock.c 206361 2010-04-07 16:50:38Z joel $");
31
32 #include <sys/param.h>
33 #include <sys/errno.h>
34 #include <sys/lock.h>
35 #include <sys/malloc.h>
36 #include <sys/mutex.h>
37 #include <sys/systm.h>
38 #include <sys/proc.h>
39 #include <sys/socket.h>
40 #include <sys/socketvar.h>
41 #include <sys/protosw.h>
42 #include <sys/kernel.h>
43 #include <sys/uio.h>
44 #include <sys/syslog.h>
45 #include <sys/mbuf.h>
46 #include <sys/condvar.h>
47 #include <net/route.h>
48
49 #include <netipx/ipx.h>
50 #include <netipx/ipx_pcb.h>
51
52 #include <netncp/ncp.h>
53 #include <netncp/ncp_conn.h>
54 #include <netncp/ncp_sock.h>
55 #include <netncp/ncp_subr.h>
56 #include <netncp/ncp_rq.h>
57
58 #define ipx_setnullnet(x) ((x).x_net.s_net[0]=0); ((x).x_net.s_net[1]=0);
59 #define ipx_setnullhost(x) ((x).x_host.s_host[0] = 0); \
60 ((x).x_host.s_host[1] = 0); ((x).x_host.s_host[2] = 0);
61
62 /*static int ncp_getsockname(struct socket *so, caddr_t asa, int *alen);*/
63 static int ncp_soconnect(struct socket *so, struct sockaddr *target,
64 struct thread *td);
65
66
67 /* This will need only if native IP used, or (unlikely) NCP will be
68 * implemented on the socket level
69 */
70 static int
71 ncp_soconnect(struct socket *so, struct sockaddr *target, struct thread *td)
72 {
73 int error, s;
74
75 error = soconnect(so, (struct sockaddr*)target, td);
76 if (error)
77 return error;
78 /*
79 * Wait for the connection to complete. Cribbed from the
80 * connect system call but with the wait timing out so
81 * that interruptible mounts don't hang here for a long time.
82 */
83 error = EIO;
84 s = splnet();
85 while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
86 (void) tsleep((caddr_t)&so->so_timeo, PSOCK, "ncpcon", 2 * hz);
87 if ((so->so_state & SS_ISCONNECTING) &&
88 so->so_error == 0 /*&& rep &&*/) {
89 so->so_state &= ~SS_ISCONNECTING;
90 splx(s);
91 goto bad;
92 }
93 }
94 if (so->so_error) {
95 error = so->so_error;
96 so->so_error = 0;
97 splx(s);
98 goto bad;
99 }
100 splx(s);
101 error=0;
102 bad:
103 return error;
104 }
105 #ifdef notyet
106 static int
107 ncp_getsockname(struct socket *so, caddr_t asa, int *alen) {
108 struct sockaddr *sa;
109 int len=0, error;
110
111 sa = 0;
112 error = (*so->so_proto->pr_usrreqs->pru_sockaddr)(so, &sa);
113 if (error==0) {
114 if (sa) {
115 len = min(len, sa->sa_len);
116 bcopy(sa, (caddr_t)asa, (u_int)len);
117 }
118 *alen=len;
119 }
120 if (sa)
121 free(sa, M_SONAME);
122 return (error);
123 }
124 #endif
125 int ncp_sock_recv(struct socket *so, struct mbuf **mp, int *rlen)
126 {
127 struct uio auio;
128 struct thread *td = curthread; /* XXX */
129 int error,flags,len;
130
131 auio.uio_resid = len = 1000000;
132 auio.uio_td = td;
133 flags = MSG_DONTWAIT;
134
135 /* error = soreceive(so, 0, &auio, (struct mbuf **)0, (struct mbuf **)0,
136 &flags);*/
137 error = soreceive(so, 0, &auio, mp, (struct mbuf **)0, &flags);
138 *rlen = len - auio.uio_resid;
139 /* if (!error) {
140 *rlen=iov.iov_len;
141 } else
142 *rlen=0;*/
143 #ifdef NCP_SOCKET_DEBUG
144 if (error)
145 printf("ncp_recv: err=%d\n", error);
146 #endif
147 return (error);
148 }
149
150 int
151 ncp_sock_send(struct socket *so, struct mbuf *top, struct ncp_rq *rqp)
152 {
153 struct thread *td = curthread; /* XXX */
154 struct sockaddr *to = 0;
155 struct ncp_conn *conn = rqp->nr_conn;
156 struct mbuf *m;
157 int error, flags=0;
158
159 for (;;) {
160 m = m_copym(top, 0, M_COPYALL, M_WAIT);
161 /* NCPDDEBUG(m);*/
162 error = sosend(so, to, 0, m, 0, flags, td);
163 if (error == 0 || error == EINTR || error == ENETDOWN)
164 break;
165 if (rqp->rexmit == 0) break;
166 rqp->rexmit--;
167 pause("ncprsn", conn->li.timeout * hz);
168 error = ncp_chkintr(conn, td);
169 if (error == EINTR) break;
170 }
171 if (error) {
172 log(LOG_INFO, "ncp_send: error %d for server %s", error, conn->li.server);
173 }
174 return error;
175 }
176
177 /*
178 * Connect to specified server via IPX
179 */
180 static int
181 ncp_sock_connect_ipx(struct ncp_conn *conn)
182 {
183 struct sockaddr_ipx sipx;
184 struct ipxpcb *npcb;
185 struct thread *td = conn->td;
186 int addrlen, error, count;
187
188 sipx.sipx_port = htons(0);
189
190 for (count = 0;;count++) {
191 if (count > (IPXPORT_WELLKNOWN-IPXPORT_RESERVED)*2) {
192 error = EADDRINUSE;
193 goto bad;
194 }
195 conn->ncp_so = conn->wdg_so = NULL;
196 checkbad(socreate(AF_IPX, &conn->ncp_so, SOCK_DGRAM, 0, td->td_ucred, td));
197 if (conn->li.opt & NCP_OPT_WDOG)
198 checkbad(socreate(AF_IPX, &conn->wdg_so, SOCK_DGRAM, 0, td->td_ucred, td));
199 addrlen = sizeof(sipx);
200 sipx.sipx_family = AF_IPX;
201 ipx_setnullnet(sipx.sipx_addr);
202 ipx_setnullhost(sipx.sipx_addr);
203 sipx.sipx_len = addrlen;
204 error = sobind(conn->ncp_so, (struct sockaddr *)&sipx, td);
205 if (error == 0) {
206 if ((conn->li.opt & NCP_OPT_WDOG) == 0)
207 break;
208 sipx.sipx_addr = sotoipxpcb(conn->ncp_so)->ipxp_laddr;
209 sipx.sipx_port = htons(ntohs(sipx.sipx_port) + 1);
210 ipx_setnullnet(sipx.sipx_addr);
211 ipx_setnullhost(sipx.sipx_addr);
212 error = sobind(conn->wdg_so, (struct sockaddr *)&sipx, td);
213 }
214 if (!error) break;
215 if (error != EADDRINUSE) goto bad;
216 sipx.sipx_port = htons((ntohs(sipx.sipx_port)+4) & 0xfff8);
217 soclose(conn->ncp_so);
218 if (conn->wdg_so)
219 soclose(conn->wdg_so);
220 }
221 npcb = sotoipxpcb(conn->ncp_so);
222 npcb->ipxp_dpt = IPXPROTO_NCP;
223 /* IPXrouted must be running, i.e. route must be presented */
224 conn->li.ipxaddr.sipx_len = sizeof(struct sockaddr_ipx);
225 checkbad(ncp_soconnect(conn->ncp_so, &conn->li.saddr, td));
226 if (conn->wdg_so) {
227 sotoipxpcb(conn->wdg_so)->ipxp_laddr.x_net = npcb->ipxp_laddr.x_net;
228 sotoipxpcb(conn->wdg_so)->ipxp_laddr.x_host= npcb->ipxp_laddr.x_host;
229 }
230 if (!error) {
231 conn->flags |= NCPFL_SOCONN;
232 }
233 #ifdef NCPBURST
234 if (ncp_burst_enabled) {
235 checkbad(socreate(AF_IPX, &conn->bc_so, SOCK_DGRAM, 0, td));
236 bzero(&sipx, sizeof(sipx));
237 sipx.sipx_len = sizeof(sipx);
238 checkbad(sobind(conn->bc_so, (struct sockaddr *)&sipx, td));
239 checkbad(ncp_soconnect(conn->bc_so, &conn->li.saddr, td));
240 }
241 #endif
242 if (!error) {
243 conn->flags |= NCPFL_SOCONN;
244 ncp_sock_checksum(conn, 0);
245 }
246 return error;
247 bad:
248 ncp_sock_disconnect(conn);
249 return (error);
250 }
251
252 int
253 ncp_sock_checksum(struct ncp_conn *conn, int enable)
254 {
255
256 if (enable) {
257 sotoipxpcb(conn->ncp_so)->ipxp_flags |= IPXP_CHECKSUM;
258 } else {
259 sotoipxpcb(conn->ncp_so)->ipxp_flags &= ~IPXP_CHECKSUM;
260 }
261 return 0;
262 }
263
264 /*
265 * Connect to specified server via IP
266 */
267 static int
268 ncp_sock_connect_in(struct ncp_conn *conn)
269 {
270 struct sockaddr_in sin;
271 struct thread *td = conn->td;
272 int addrlen = sizeof(sin), error;
273
274 conn->flags = 0;
275 bzero(&sin,addrlen);
276 conn->ncp_so = conn->wdg_so = NULL;
277 checkbad(socreate(AF_INET, &conn->ncp_so, SOCK_DGRAM, IPPROTO_UDP, td->td_ucred, td));
278 sin.sin_family = AF_INET;
279 sin.sin_len = addrlen;
280 checkbad(sobind(conn->ncp_so, (struct sockaddr *)&sin, td));
281 checkbad(ncp_soconnect(conn->ncp_so,(struct sockaddr*)&conn->li.addr, td));
282 if (!error)
283 conn->flags |= NCPFL_SOCONN;
284 return error;
285 bad:
286 ncp_sock_disconnect(conn);
287 return (error);
288 }
289
290 int
291 ncp_sock_connect(struct ncp_conn *ncp)
292 {
293 int error;
294
295 switch (ncp->li.saddr.sa_family) {
296 case AF_IPX:
297 error = ncp_sock_connect_ipx(ncp);
298 break;
299 case AF_INET:
300 error = ncp_sock_connect_in(ncp);
301 break;
302 default:
303 return EPROTONOSUPPORT;
304 }
305 return error;
306 }
307
308 /*
309 * Connection expected to be locked
310 */
311 int
312 ncp_sock_disconnect(struct ncp_conn *conn) {
313 register struct socket *so;
314 conn->flags &= ~(NCPFL_SOCONN | NCPFL_ATTACHED | NCPFL_LOGGED);
315 if (conn->ncp_so) {
316 so = conn->ncp_so;
317 conn->ncp_so = (struct socket *)0;
318 soshutdown(so, 2);
319 soclose(so);
320 }
321 if (conn->wdg_so) {
322 so = conn->wdg_so;
323 conn->wdg_so = (struct socket *)0;
324 soshutdown(so, 2);
325 soclose(so);
326 }
327 #ifdef NCPBURST
328 if (conn->bc_so) {
329 so = conn->bc_so;
330 conn->bc_so = (struct socket *)NULL;
331 soshutdown(so, 2);
332 soclose(so);
333 }
334 #endif
335 return 0;
336 }
337
338 static void
339 ncp_watchdog(struct ncp_conn *conn) {
340 char *buf;
341 struct mbuf *m;
342 int error, len, flags;
343 struct socket *so;
344 struct sockaddr *sa;
345 struct uio auio;
346
347 sa = NULL;
348 while (conn->wdg_so) { /* not a loop */
349 so = conn->wdg_so;
350 auio.uio_resid = len = 1000000;
351 auio.uio_td = curthread;
352 flags = MSG_DONTWAIT;
353 error = soreceive(so, (struct sockaddr**)&sa, &auio, &m,
354 (struct mbuf**)0, &flags);
355 if (error) break;
356 len -= auio.uio_resid;
357 NCPSDEBUG("got watch dog %d\n",len);
358 if (len != 2) break;
359 buf = mtod(m, char*);
360 if (buf[1] != '?') break;
361 buf[1] = 'Y';
362 error = sosend(so, (struct sockaddr*)sa, 0, m, 0, 0, curthread);
363 NCPSDEBUG("send watch dog %d\n",error);
364 break;
365 }
366 if (sa) free(sa, M_SONAME);
367 return;
368 }
369
370 void
371 ncp_check_conn(struct ncp_conn *conn) {
372 int s;
373
374 if (conn == NULL || !(conn->flags & NCPFL_ATTACHED))
375 return;
376 s = splnet();
377 ncp_check_rq(conn);
378 splx(s);
379 if (conn->li.saddr.sa_family == AF_IPX)
380 ncp_watchdog(conn);
381 }
Cache object: bd324b053a38f78620ac8f3048c59613
|