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 * 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.
19 *
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
30 * SUCH DAMAGE.
31 *
32 * $FreeBSD: releng/5.1/sys/netncp/ncp_sock.c 111577 2003-02-26 21:25:55Z fjoe $
33 *
34 * Low level socket routines
35 */
36
37 #include <sys/param.h>
38 #include <sys/errno.h>
39 #include <sys/lock.h>
40 #include <sys/malloc.h>
41 #include <sys/mutex.h>
42 #include <sys/systm.h>
43 #include <sys/proc.h>
44 #include <sys/socket.h>
45 #include <sys/socketvar.h>
46 #include <sys/protosw.h>
47 #include <sys/kernel.h>
48 #include <sys/uio.h>
49 #include <sys/syslog.h>
50 #include <sys/mbuf.h>
51 #include <sys/condvar.h>
52 #include <net/route.h>
53
54 #include <netipx/ipx.h>
55 #include <netipx/ipx_pcb.h>
56
57 #include <netncp/ncp.h>
58 #include <netncp/ncp_conn.h>
59 #include <netncp/ncp_sock.h>
60 #include <netncp/ncp_subr.h>
61 #include <netncp/ncp_rq.h>
62
63 #define ipx_setnullnet(x) ((x).x_net.s_net[0]=0); ((x).x_net.s_net[1]=0);
64 #define ipx_setnullhost(x) ((x).x_host.s_host[0] = 0); \
65 ((x).x_host.s_host[1] = 0); ((x).x_host.s_host[2] = 0);
66
67 /*int ncp_poll(struct socket *so, int events);*/
68 /*static int ncp_getsockname(struct socket *so, caddr_t asa, int *alen);*/
69 static int ncp_soconnect(struct socket *so, struct sockaddr *target,
70 struct thread *td);
71
72
73 /* This will need only if native IP used, or (unlikely) NCP will be
74 * implemented on the socket level
75 */
76 static int
77 ncp_soconnect(struct socket *so, struct sockaddr *target, struct thread *td)
78 {
79 int error, s;
80
81 error = soconnect(so, (struct sockaddr*)target, td);
82 if (error)
83 return error;
84 /*
85 * Wait for the connection to complete. Cribbed from the
86 * connect system call but with the wait timing out so
87 * that interruptible mounts don't hang here for a long time.
88 */
89 error = EIO;
90 s = splnet();
91 while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
92 (void) tsleep((caddr_t)&so->so_timeo, PSOCK, "ncpcon", 2 * hz);
93 if ((so->so_state & SS_ISCONNECTING) &&
94 so->so_error == 0 /*&& rep &&*/) {
95 so->so_state &= ~SS_ISCONNECTING;
96 splx(s);
97 goto bad;
98 }
99 }
100 if (so->so_error) {
101 error = so->so_error;
102 so->so_error = 0;
103 splx(s);
104 goto bad;
105 }
106 splx(s);
107 error=0;
108 bad:
109 return error;
110 }
111 #ifdef notyet
112 static int
113 ncp_getsockname(struct socket *so, caddr_t asa, int *alen) {
114 struct sockaddr *sa;
115 int len=0, error;
116
117 sa = 0;
118 error = (*so->so_proto->pr_usrreqs->pru_sockaddr)(so, &sa);
119 if (error==0) {
120 if (sa) {
121 len = min(len, sa->sa_len);
122 bcopy(sa, (caddr_t)asa, (u_int)len);
123 }
124 *alen=len;
125 }
126 if (sa)
127 FREE(sa, M_SONAME);
128 return (error);
129 }
130 #endif
131 int ncp_sock_recv(struct socket *so, struct mbuf **mp, int *rlen)
132 {
133 struct uio auio;
134 struct thread *td = curthread; /* XXX */
135 int error,flags,len;
136
137 auio.uio_resid = len = 1000000;
138 auio.uio_td = td;
139 flags = MSG_DONTWAIT;
140
141 /* error = so->so_proto->pr_usrreqs->pru_soreceive(so, 0, &auio,
142 (struct mbuf **)0, (struct mbuf **)0, &flags);*/
143 error = so->so_proto->pr_usrreqs->pru_soreceive(so, 0, &auio,
144 mp, (struct mbuf **)0, &flags);
145 *rlen = len - auio.uio_resid;
146 /* if (!error) {
147 *rlen=iov.iov_len;
148 } else
149 *rlen=0;*/
150 #ifdef NCP_SOCKET_DEBUG
151 if (error)
152 printf("ncp_recv: err=%d\n", error);
153 #endif
154 return (error);
155 }
156
157 int
158 ncp_sock_send(struct socket *so, struct mbuf *top, struct ncp_rq *rqp)
159 {
160 struct thread *td = curthread; /* XXX */
161 struct sockaddr *to = 0;
162 struct ncp_conn *conn = rqp->nr_conn;
163 struct mbuf *m;
164 int error, flags=0;
165 int sendwait;
166
167 for (;;) {
168 m = m_copym(top, 0, M_COPYALL, M_TRYWAIT);
169 /* NCPDDEBUG(m);*/
170 error = so->so_proto->pr_usrreqs->pru_sosend(so, to, 0, m, 0, flags, td);
171 if (error == 0 || error == EINTR || error == ENETDOWN)
172 break;
173 if (rqp->rexmit == 0) break;
174 rqp->rexmit--;
175 tsleep(&sendwait, PWAIT, "ncprsn", conn->li.timeout * hz);
176 error = ncp_chkintr(conn, td);
177 if (error == EINTR) break;
178 }
179 if (error) {
180 log(LOG_INFO, "ncp_send: error %d for server %s", error, conn->li.server);
181 }
182 return error;
183 }
184
185 int
186 ncp_poll(struct socket *so, int events)
187 {
188 struct thread *td = curthread;
189 struct ucred *cred = NULL;
190
191 return so->so_proto->pr_usrreqs->pru_sopoll(so, events, cred, td);
192 }
193
194 int
195 ncp_sock_rselect(struct socket *so, struct thread *td, struct timeval *tv,
196 int events)
197 {
198 struct timeval atv, rtv, ttv;
199 int ncoll, timo, error = 0;
200
201 if (tv) {
202 atv = *tv;
203 if (itimerfix(&atv)) {
204 error = EINVAL;
205 goto done_noproclock;
206 }
207 getmicrouptime(&rtv);
208 timevaladd(&atv, &rtv);
209 }
210 timo = 0;
211 mtx_lock(&sellock);
212
213 retry:
214 ncoll = nselcoll;
215 mtx_lock_spin(&sched_lock);
216 td->td_flags |= TDF_SELECT;
217 mtx_unlock_spin(&sched_lock);
218 mtx_unlock(&sellock);
219
220 TAILQ_INIT(&td->td_selq);
221 error = ncp_poll(so, events);
222 mtx_lock(&sellock);
223 if (error) {
224 error = 0;
225 goto done;
226 }
227 if (tv) {
228 getmicrouptime(&rtv);
229 if (timevalcmp(&rtv, &atv, >=))
230 goto done;
231 ttv = atv;
232 timevalsub(&ttv, &rtv);
233 timo = tvtohz(&ttv);
234 }
235 /*
236 * An event of our interest may occur during locking a thread.
237 * In order to avoid missing the event that occurred during locking
238 * the process, test TDF_SELECT and rescan file descriptors if
239 * necessary.
240 */
241 mtx_lock_spin(&sched_lock);
242 if ((td->td_flags & TDF_SELECT) == 0 || nselcoll != ncoll) {
243 mtx_unlock_spin(&sched_lock);
244 goto retry;
245 }
246 mtx_unlock_spin(&sched_lock);
247
248 if (timo > 0)
249 error = cv_timedwait(&selwait, &sellock, timo);
250 else {
251 cv_wait(&selwait, &sellock);
252 error = 0;
253 }
254
255 done:
256 clear_selinfo_list(td);
257
258 mtx_lock_spin(&sched_lock);
259 td->td_flags &= ~TDF_SELECT;
260 mtx_unlock_spin(&sched_lock);
261 mtx_unlock(&sellock);
262
263 done_noproclock:
264 if (error == ERESTART)
265 error = 0;
266 return (error);
267 }
268
269 /*
270 * Connect to specified server via IPX
271 */
272 static int
273 ncp_sock_connect_ipx(struct ncp_conn *conn)
274 {
275 struct sockaddr_ipx sipx;
276 struct ipxpcb *npcb;
277 struct thread *td = conn->td;
278 int addrlen, error, count;
279
280 sipx.sipx_port = htons(0);
281
282 for (count = 0;;count++) {
283 if (count > (IPXPORT_WELLKNOWN-IPXPORT_RESERVED)*2) {
284 error = EADDRINUSE;
285 goto bad;
286 }
287 conn->ncp_so = conn->wdg_so = NULL;
288 checkbad(socreate(AF_IPX, &conn->ncp_so, SOCK_DGRAM, 0, td->td_ucred, td));
289 if (conn->li.opt & NCP_OPT_WDOG)
290 checkbad(socreate(AF_IPX, &conn->wdg_so, SOCK_DGRAM, 0, td->td_ucred, td));
291 addrlen = sizeof(sipx);
292 sipx.sipx_family = AF_IPX;
293 ipx_setnullnet(sipx.sipx_addr);
294 ipx_setnullhost(sipx.sipx_addr);
295 sipx.sipx_len = addrlen;
296 error = sobind(conn->ncp_so, (struct sockaddr *)&sipx, td);
297 if (error == 0) {
298 if ((conn->li.opt & NCP_OPT_WDOG) == 0)
299 break;
300 sipx.sipx_addr = sotoipxpcb(conn->ncp_so)->ipxp_laddr;
301 sipx.sipx_port = htons(ntohs(sipx.sipx_port) + 1);
302 ipx_setnullnet(sipx.sipx_addr);
303 ipx_setnullhost(sipx.sipx_addr);
304 error = sobind(conn->wdg_so, (struct sockaddr *)&sipx, td);
305 }
306 if (!error) break;
307 if (error != EADDRINUSE) goto bad;
308 sipx.sipx_port = htons((ntohs(sipx.sipx_port)+4) & 0xfff8);
309 soclose(conn->ncp_so);
310 if (conn->wdg_so)
311 soclose(conn->wdg_so);
312 }
313 npcb = sotoipxpcb(conn->ncp_so);
314 npcb->ipxp_dpt = IPXPROTO_NCP;
315 /* IPXrouted must be running, i.e. route must be presented */
316 conn->li.ipxaddr.sipx_len = sizeof(struct sockaddr_ipx);
317 checkbad(ncp_soconnect(conn->ncp_so, &conn->li.saddr, td));
318 if (conn->wdg_so) {
319 sotoipxpcb(conn->wdg_so)->ipxp_laddr.x_net = npcb->ipxp_laddr.x_net;
320 sotoipxpcb(conn->wdg_so)->ipxp_laddr.x_host= npcb->ipxp_laddr.x_host;
321 }
322 if (!error) {
323 conn->flags |= NCPFL_SOCONN;
324 }
325 #ifdef NCPBURST
326 if (ncp_burst_enabled) {
327 checkbad(socreate(AF_IPX, &conn->bc_so, SOCK_DGRAM, 0, td));
328 bzero(&sipx, sizeof(sipx));
329 sipx.sipx_len = sizeof(sipx);
330 checkbad(sobind(conn->bc_so, (struct sockaddr *)&sipx, td));
331 checkbad(ncp_soconnect(conn->bc_so, &conn->li.saddr, td));
332 }
333 #endif
334 if (!error) {
335 conn->flags |= NCPFL_SOCONN;
336 ncp_sock_checksum(conn, 0);
337 }
338 return error;
339 bad:
340 ncp_sock_disconnect(conn);
341 return (error);
342 }
343
344 int
345 ncp_sock_checksum(struct ncp_conn *conn, int enable)
346 {
347
348 if (enable) {
349 sotoipxpcb(conn->ncp_so)->ipxp_flags |= IPXP_CHECKSUM;
350 } else {
351 sotoipxpcb(conn->ncp_so)->ipxp_flags &= ~IPXP_CHECKSUM;
352 }
353 return 0;
354 }
355
356 /*
357 * Connect to specified server via IP
358 */
359 static int
360 ncp_sock_connect_in(struct ncp_conn *conn)
361 {
362 struct sockaddr_in sin;
363 struct thread *td = conn->td;
364 int addrlen = sizeof(sin), error;
365
366 conn->flags = 0;
367 bzero(&sin,addrlen);
368 conn->ncp_so = conn->wdg_so = NULL;
369 checkbad(socreate(AF_INET, &conn->ncp_so, SOCK_DGRAM, IPPROTO_UDP, td->td_ucred, td));
370 sin.sin_family = AF_INET;
371 sin.sin_len = addrlen;
372 checkbad(sobind(conn->ncp_so, (struct sockaddr *)&sin, td));
373 checkbad(ncp_soconnect(conn->ncp_so,(struct sockaddr*)&conn->li.addr, td));
374 if (!error)
375 conn->flags |= NCPFL_SOCONN;
376 return error;
377 bad:
378 ncp_sock_disconnect(conn);
379 return (error);
380 }
381
382 int
383 ncp_sock_connect(struct ncp_conn *ncp)
384 {
385 int error;
386
387 switch (ncp->li.saddr.sa_family) {
388 case AF_IPX:
389 error = ncp_sock_connect_ipx(ncp);
390 break;
391 case AF_INET:
392 error = ncp_sock_connect_in(ncp);
393 break;
394 default:
395 return EPROTONOSUPPORT;
396 }
397 return error;
398 }
399
400 /*
401 * Connection expected to be locked
402 */
403 int
404 ncp_sock_disconnect(struct ncp_conn *conn) {
405 register struct socket *so;
406 conn->flags &= ~(NCPFL_SOCONN | NCPFL_ATTACHED | NCPFL_LOGGED);
407 if (conn->ncp_so) {
408 so = conn->ncp_so;
409 conn->ncp_so = (struct socket *)0;
410 soshutdown(so, 2);
411 soclose(so);
412 }
413 if (conn->wdg_so) {
414 so = conn->wdg_so;
415 conn->wdg_so = (struct socket *)0;
416 soshutdown(so, 2);
417 soclose(so);
418 }
419 #ifdef NCPBURST
420 if (conn->bc_so) {
421 so = conn->bc_so;
422 conn->bc_so = (struct socket *)NULL;
423 soshutdown(so, 2);
424 soclose(so);
425 }
426 #endif
427 return 0;
428 }
429
430 static void
431 ncp_watchdog(struct ncp_conn *conn) {
432 char *buf;
433 struct mbuf *m;
434 int error, len, flags;
435 struct socket *so;
436 struct sockaddr *sa;
437 struct uio auio;
438
439 sa = NULL;
440 while (conn->wdg_so) { /* not a loop */
441 so = conn->wdg_so;
442 auio.uio_resid = len = 1000000;
443 auio.uio_td = curthread;
444 flags = MSG_DONTWAIT;
445 error = so->so_proto->pr_usrreqs->pru_soreceive(so,
446 (struct sockaddr**)&sa, &auio, &m, (struct mbuf**)0, &flags);
447 if (error) break;
448 len -= auio.uio_resid;
449 NCPSDEBUG("got watch dog %d\n",len);
450 if (len != 2) break;
451 buf = mtod(m, char*);
452 if (buf[1] != '?') break;
453 buf[1] = 'Y';
454 error = so->so_proto->pr_usrreqs->pru_sosend(so, (struct sockaddr*)sa, 0, m, 0, 0, curthread);
455 NCPSDEBUG("send watch dog %d\n",error);
456 break;
457 }
458 if (sa) FREE(sa, M_SONAME);
459 return;
460 }
461
462 void
463 ncp_check_conn(struct ncp_conn *conn) {
464 int s;
465
466 if (conn == NULL || !(conn->flags & NCPFL_ATTACHED))
467 return;
468 s = splnet();
469 ncp_check_rq(conn);
470 splx(s);
471 if (conn->li.saddr.sa_family == AF_IPX)
472 ncp_watchdog(conn);
473 }
Cache object: ce14c3711ac43c9bdaa46d32f7fdfb24
|