xref: /csrg-svn/sys/kern/uipc_socket.c (revision 4786)
1 /*	uipc_socket.c	4.1	81/11/07	*/
2 
3 #include "../h/param.h"
4 #include "../h/dir.h"
5 #include "../h/user.h"
6 #include "file.h"
7 #include "../h/inode.h"
8 #include "../h/mbuf.h"
9 #include "protocol.h"
10 #include "protocolsw.h"
11 #include "socket.h"
12 #include "socketvar.h"
13 
14 struct	socket zerosocket;
15 struct	in_addr zeroin_addr;
16 
17 /*
18  * Socket system call interface.  Copy in arguments
19  * set up file descriptor and call internal socket
20  * creation routine.
21  */
22 ssocket()
23 {
24 	register struct a {
25 		int type;
26 		in_addr *ain;
27 		int flags;
28 	} *uap = (struct a *)u.u_ap;
29 	in_addr in;
30 	struct socket *so0;
31 	register struct socket *so;
32 	register struct file *fp;
33 
34 	if ((fp = falloc()) == NULL)
35 		return;
36 	fp->f_flag = FSOCKET|FREAD|FWRITE;
37 	if (copyin((caddr_t)uap->ain, &in, sizeof (in))) {
38 		u.u_error = EFAULT;
39 		return;
40 	}
41 	u.u_error = socket(&so0, a->type, &in, a->flags);
42 	if (u.u_error)
43 		goto bad;
44 	fp->f_socket = so;
45 	return;
46 bad:
47 	u.u_ofile[u.u_r.r_val1] = 0;
48 	fp->f_count = 0;
49 }
50 
51 /*
52  * Create a socket.
53  */
54 socket(aso, type, iap, flags)
55 	struct socket **aso;
56 	int type;
57 	register struct in_addr *iap;
58 	int flags;
59 {
60 	register struct protosw *prp;
61 	register struct socket *so;
62 	struct mbuf *m;
63 	int pf, proto;
64 
65 	/*
66 	 * Pin down protocol if possible.
67 	 * If no address specified, use a generic protocol.
68 	 */
69 	if (iap == 0) {
70 		pf = PF_GENERIC;
71 		proto = 0;
72 	} else {
73 		pf = iap->ia_pf;
74 		proto = iap->ia_proto;
75 	}
76 	if (proto) {
77 		/*
78 		 * A specific protocol was requested.  Look
79 		 * for the protocol.  If not found, then we
80 		 * don't support it.
81 		 */
82 		prp = pf_findproto(pf, proto);
83 		if (prp == 0)
84 			return (EPROTONOTSUPP);
85 	} else {
86 		/*
87 		 * No specific protocol was requested.  Look
88 		 * in the specified (or generic) protocol set
89 		 * for a protocol of this type.
90 		 */
91 		prp = pf_findtype(pf, type);
92 		if (prp == 0)
93 			return (ESOCKTYPENOTSUPP);
94 	}
95 
96 	/*
97 	 * Get a socket structure.
98 	 */
99 	m = m_get(M_WAIT);
100 	if (m == 0)
101 		return (ENOBUFS);
102 	m->m_off = MMINOFF;
103 	so = mtod(m, struct socket *);
104 	*so = zerosocket;
105 	so->so_flags = flags;
106 
107 	/*
108 	 * An early call to protocol initialization.  If protocol
109 	 * actually hasn't been decided on yet (till we know
110 	 * peer), then the generic protocol allocated so far can
111 	 * just make sure a reasonable amount of resources will
112 	 * be available to it (say by allocating liberally now
113 	 * and returning some of the resources later).
114 	 */
115 	so->so_proto = prp;
116 	(*prp->pr_usrreq)(so, PRU_ATTACH, 0, 0);
117 	if (so->so_error) {
118 		m_free(dtom(so));
119 		return (u.u_error);
120 	}
121 	*aso = so;
122 	return (0);
123 }
124 
125 /*
126  * Connect socket to foreign peer; system call
127  * interface.  Copy in arguments and call internal routine.
128  */
129 sconnect()
130 {
131 	register struct a {
132 		int fdes;
133 		in_addr *a;
134 	} *uap = (struct a *)u.u_ap;
135 	in_addr in;
136 
137 	if (copyin((caddr_t)uap->aaddr, &in, sizeof (in))) {
138 		u.u_error = EFAULT;
139 		return;
140 	}
141 	fp = getf(uap->fdes);
142 	if (fp == 0)
143 		return;
144 	if ((fp->f_flag & FSOCKET) == 0) {
145 		u.u_error = ENOTSOCK;
146 		return;
147 	}
148 	u.u_error = connect(fp->f_socket, &in);
149 	if (u.u_error)
150 		return;
151 	s = splnet();
152 	for (;;) {
153 		/* should use tsleep here */
154 		if ((*so->so_proto->pr_usrreq)(so, PRU_ISCONN, 0, &in) == 0)
155 			break;
156 		sleep((caddr_t)&so->so_timeo, PZERO+1);
157 	}
158 	splx(s);
159 }
160 
161 connect(so, iap)
162 	struct socket *so;
163 	struct in_addr *iap;
164 {
165 
166 	return ((*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 0, &in));
167 }
168 
169 /*
170  * Disconnect socket from foreign peer; system call
171  * interface.  Copy in arguments and call internal routine.
172  */
173 sdisconnect()
174 {
175 	register struct a {
176 		int fdes;
177 		in_addr *a;
178 	} *uap = (struct a *)u.u_ap;
179 	in_addr in;
180 
181 	if (uap->a && copyin((caddr_t)uap->aaddr, &in, sizeof (in))) {
182 		u.u_error = EFAULT;
183 		return;
184 	}
185 	fp = getf(uap->fdes);
186 	if (fp == 0)
187 		return;
188 	if ((fp->f_flag & FSOCKET) == 0) {
189 		u.u_error = ENOTSOCK;
190 		return;
191 	}
192 	disconnect(fp->f_socket, uap->a ? &in : 0);
193 }
194 
195 disconnect(so, iap)
196 	struct socket *so;
197 	struct in_addr *iap;
198 {
199 
200 	u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 0, &in);
201 }
202 
203 /*
204  * Send data on socket.
205  */
206 ssend()
207 {
208 	register struct a {
209 		int fdes;
210 		in_addr *ain;
211 		caddr_t cbuf;
212 		int count;
213 	} *uap = (struct a *)u.u_ap;
214 
215 	fp = getf(uap->fdes);
216 	if (fp == 0)
217 		return;
218 	if ((fp->f_flag & FSOCKET) == 0) {
219 		u.u_error = ENOTSOCK;
220 		return;
221 	}
222 	if (uap->count < 0) {
223 		u.u_error = EINVAL;
224 		return;
225 	}
226 	u.u_base = uap->buf;
227 	u.u_count = uap->len;
228 	u.u_segflg = 0;
229 	if (useracc(u.u_base, u.u_count, B_READ) == 0 ||
230 	    uap->ain && copyin((caddr_t)uap->ain, (caddr_t)&in, sizeof (in))) {
231 		u.u_error = EFAULT;
232 		return;
233 	}
234 	u.u_error = send(fp->f_socket, uap->ain ? &in : 0);
235 }
236 
237 send(so, iap)
238 	register struct socket *so;
239 	struct in_addr *iap;
240 {
241 	register struct mbuf *m, **mp;
242 	struct mbuf *top;
243 	int error = 0;
244 
245 	if (so->so_proto->pr_flags & PR_ATOMIC) {
246 		if (u.u_count > so->so_snd.sb_hiwat) {
247 			error = EMSGSIZE;
248 			goto release;
249 		}
250 	}
251 again:
252 	while (so->so_snd.sb_flags & SB_LOCK) {
253 		so->so_snd.sb_flags |= SB_WANT;
254 		sleep((caddr_t)&so->so_snd.sb_flags, PZERO+1);
255 	}
256 	if (so->so_snd.sb_hiwat - so->so_snd.sb_cc < u.u_count) {
257 		so->so_snd.sb_flags |= SB_WAIT;
258 		sleep((caddr_t)&so->so_snd.sb_cc, PZERO+1);
259 		goto again;
260 	}
261 	so->so_snd.sb_flags |= SB_LOCK;
262 	while (u.u_count > 0) {
263 		bufs = so->so_snd.sb_mbmax - so->so_snd.sb_mbcnt;
264 		while (bufs == 0) {
265 			so->so_snd.sb_flags |= SB_WAIT;
266 			sleep((caddr_t)&so->so_snd.sb_cc, PZERO+1);
267 		}
268 		mp = &top;
269 		top = 0;
270 		while (--bufs >= 0 && u.u_count > 0) {
271 			MGET(m, 1);
272 			if (m == NULL) {
273 				error = ENOBUFS;
274 				m_freem(top);
275 				goto release;
276 			}
277 			if (u.u_count >= PGSIZE && bufs >= NMBPG) {
278 				MPGET(p, 1);
279 				if (p == 0)
280 					goto nopage;
281 				m->m_off = (int)p - (int)m;
282 				len = PGSIZE;
283 			} else {
284 nopages:
285 				m->m_off = MMINOFF;
286 				len = MIN(MLEN, u.u_count);
287 			}
288 			iomove(mtod(m, caddr_t), len, B_WRITE);
289 			m->m_len = len;
290 			*mp = m;
291 			mp = &m->m_next;
292 		}
293 		s = splnet();
294 		error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, top, iap);
295 		splx(s);
296 		if (error)
297 			break;
298 	}
299 release:
300 	so->so_snd.sb_flags &= ~SB_LOCK;
301 	if (so->so_snd.sb_flags & SB_WANT)
302 		wakeup((caddr_t)&so->so_sb.sb_flags);
303 	return (error);
304 }
305 
306 /*
307  * Receive data on socket.
308  */
309 sreceive()
310 {
311 	register struct a {
312 		int fdes;
313 		in_addr *ain;
314 		caddr_t cbuf;
315 		int count;
316 	} *uap = (struct a *)u.u_ap;
317 
318 	fp = getf(uap->fdes);
319 	if (fp == 0)
320 		return;
321 	if ((fp->f_flag & FSOCKET) == 0) {
322 		u.u_error = ENOTSOCK;
323 		return;
324 	}
325 	if (uap->count < 0) {
326 		u.u_error = EINVAL;
327 		return;
328 	}
329 	u.u_base = uap->buf;
330 	u.u_count = uap->len;
331 	u.u_segflg = 0;
332 	if (useracc(u.u_base, u.u_count, B_WRITE) == 0 ||
333 	    uap->ain && copyin((caddr_t)uap->ain, (caddr_t)&in, sizeof (in))) {
334 		u.u_error = EFAULT;
335 		return;
336 	}
337 	receive(fp->f_socket, uap->ain ? &in : 0);
338 }
339 
340 receive(so, iap)
341 	register struct socket *so;
342 	struct in_addr *iap;
343 {
344 	register struct mbuf *m, *n;
345 	register int eor, len, s;
346 
347 again:
348 	while (so->so_rcv.sb_flags & SB_LOCK) {
349 		so->so_rcv.sb_flags |= SB_WANT;
350 		sleep((caddr_t)&so->so_rcv.sb_flags, PZERO+1);
351 	}
352 	if (so->so_rcv.sb_cc == 0) {
353 		if ((so->so_proto->pr_usrreq)(so, PR_ISDISCONN, 0, 0) == 0)
354 			return;
355 		so->so_rcv.sb_flags |= SB_WAIT;
356 		sleep((caddr_t)&so->so_rcv.sb_cc, PZERO+1);
357 		goto again;
358 	}
359 	so->so_rcv.sb_flags |= SB_LOCK;
360 	m = up->uc_rcv.sb_mb;
361 	if (m == 0)
362 		panic("receive");
363 	eor = 0;
364 	do {
365 		len = MIN(m->m_len, u.u_count);
366 		if (len == m->m_len) {
367 			eor = (int)m->m_act;
368 			up->uc_rcv.sb_mb = m->m_next;
369 			up->uc_rcv.sb_cc -= len;
370 			if (up->uc_rcv.sb_cc < 0)
371 				panic("receive 2");
372 		}
373 		splx(s);
374 		iomove(mtod(m, caddr_t), len, B_READ);
375 		s = splnet();
376 		if (len == m->m_len) {
377 			MFREE(m, n);
378 		} else {
379 			m->m_off += len;
380 			m->m_len -= len;
381 			up->uc_rcv.sb_cc -= len;
382 			if (up->uc_rcv.sb_cc < 0)
383 				panic("receive 3");
384 		}
385 	} while ((m = up->uc_rcv.sb_mb) && u.u_count && !eor);
386 	if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0)
387 		do {
388 			m = so->so_rcv.sb_mb;
389 			if (m == 0)
390 				panic("receive 4");
391 			up->uc_rcv.sb_cc -= m->m_len;
392 			if (up->uc_rcv.sb_cc < 0)
393 				panic("receive 5");
394 			eor = (int)m->m_act;
395 			so->so_rcv.sb_mb = m->m_next;
396 			MFREE(m, n);
397 		} while (eor == 0);
398 	if (iap)
399 		if ((so->so_proto->pr_flags & PR_PROVIDEADDR)) {
400 			m = up->uc_rcv.sb_mb;
401 			if (m == 0)
402 				panic("receive 6");
403 			up->uc_rcv.sb_mb = m->m_next;
404 			up->uc_rcv.sb_cc -= m->m_len;
405 			len = MIN(m->m_len, sizeof (struct in_addr));
406 			bcopy(mtod(m, caddr_t), (caddr_t)iap, len);
407 		} else
408 			*iap = zeroin_addr;
409 	(*so->so_proto->pr_usrreq)(up, PRU_RCVD, m, 0);
410 }
411 
412 skioctl()
413 {
414 
415 	/* switch out based on socket type */
416 }
417