xref: /csrg-svn/sys/kern/uipc_socket.c (revision 4916)
1 /*	uipc_socket.c	4.5	81/11/16	*/
2 
3 #include "../h/param.h"
4 #include "../h/systm.h"
5 #include "../h/dir.h"
6 #include "../h/user.h"
7 #include "../h/proc.h"
8 #include "../h/file.h"
9 #include "../h/inode.h"
10 #include "../h/buf.h"
11 #include "../h/mbuf.h"
12 #include "../h/protocol.h"
13 #include "../h/protosw.h"
14 #include "../h/socket.h"
15 #include "../h/socketvar.h"
16 #include "../h/inaddr.h"
17 #include "../h/stat.h"
18 #include "../net/inet.h"
19 #include "../net/inet_systm.h"
20 
21 /*
22  * Socket support routines.
23  *
24  * DEAL WITH INTERRUPT NOTIFICATION.
25  * DO NEWFD STUFF
26  */
27 
28 /*
29  * Create a socket.
30  */
31 socket(aso, type, iap, options)
32 	struct socket **aso;
33 	int type;
34 	register struct in_addr *iap;
35 	int options;
36 {
37 	register struct protosw *prp;
38 	register struct socket *so;
39 	struct mbuf *m;
40 	int pf, proto, error;
41 
42 	/*
43 	 * Use process standard protocol/protocol family if none
44 	 * specified by address argument.
45 	 */
46 	if (iap == 0) {
47 		pf = PF_INET;		/* should be u.u_protof */
48 		proto = 0;
49 	} else {
50 		pf = iap->ia_pf;
51 		proto = iap->ia_proto;
52 	}
53 
54 	/*
55 	 * If protocol specified, look for it, otherwise
56 	 * for a protocol of the correct type in the right family.
57 	 */
58 	if (proto)
59 		prp = pffindproto(pf, proto);
60 	else
61 		prp = pffindtype(pf, type);
62 	if (prp == 0)
63 		return (EPROTONOSUPPORT);
64 
65 	/*
66 	 * Get a socket structure.
67 	 */
68 	m = m_getclr(M_WAIT);
69 	if (m == 0)
70 		return (ENOBUFS);
71 	so = mtod(m, struct socket *);
72 	so->so_options = options;
73 
74 	/*
75 	 * Attach protocol to socket, initializing
76 	 * and reserving resources.
77 	 */
78 	so->so_proto = prp;
79 	(*prp->pr_usrreq)(so, PRU_ATTACH, 0, 0);
80 	if (so->so_error) {
81 		error = so->so_error;
82 		m_free(dtom(so));
83 		return (error);
84 	}
85 	*aso = so;
86 	return (0);
87 }
88 
89 sofree(so)
90 	struct socket *so;
91 {
92 
93 	m_free(dtom(so));
94 }
95 
96 /*
97  * Close a socket on last file table reference removal.
98  * Initiate disconnect if connected.
99  * Free socket when disconnect complete.
100  */
101 soclose(so)
102 	register struct socket *so;
103 {
104 	int s = splnet();		/* conservative */
105 
106 	if (so->so_pcb == 0)
107 		goto discard;
108 	if (so->so_state & SS_ISCONNECTED) {
109 		if ((so->so_state & SS_ISDISCONNECTING) == 0) {
110 			u.u_error = disconnect(so, (struct in_addr *)0);
111 			if (u.u_error) {
112 				splx(s);
113 				return;
114 			}
115 		}
116 		if ((so->so_state & SS_ISDISCONNECTING) &&
117 		    (so->so_options & SO_NBIO)) {
118 			u.u_error = EINPROGRESS;
119 			splx(s);
120 			return;
121 		}
122 		while (so->so_state & SS_ISCONNECTED)
123 			sleep((caddr_t)&so->so_timeo, PZERO+1);
124 	}
125 	u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_DETACH, 0, 0);
126 discard:
127 	if (so->so_pcb == 0)
128 		sofree(so);
129 	splx(s);
130 }
131 
132 /*ARGSUSED*/
133 sostat(so, sb)
134 	struct socket *so;
135 	struct stat *sb;
136 {
137 
138 	return (EOPNOTSUPP);
139 }
140 
141 /*
142  * Connect socket to a specified address.
143  * If already connected or connecting, then avoid
144  * the protocol entry, to keep its job simpler.
145  */
146 connect(so, iap)
147 	struct socket *so;
148 	struct in_addr *iap;
149 {
150 	int s = splnet();
151 	int error;
152 
153 	if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) {
154 		error = EISCONN;
155 		goto bad;
156 	}
157 	error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 0, (caddr_t)iap);
158 bad:
159 	splx(s);
160 	return (error);
161 }
162 
163 /*
164  * Disconnect from a socket.
165  * Address parameter is from system call for later multicast
166  * protocols.  Check to make sure that connected and no disconnect
167  * in progress (for protocol's sake), and then invoke protocol.
168  */
169 /*ARGSUSED*/
170 disconnect(so, iap)
171 	struct socket *so;
172 	struct in_addr *iap;
173 {
174 	int s = splnet();
175 	int error;
176 
177 	if ((so->so_state & SS_ISCONNECTED) == 0) {
178 		error = ENOTCONN;
179 		goto bad;
180 	}
181 	if (so->so_state & SS_ISDISCONNECTING) {
182 		error = EALREADY;
183 		goto bad;
184 	}
185 	error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 0, 0);
186 bad:
187 	splx(s);
188 	return (error);
189 }
190 
191 /*
192  * Send on a socket.
193  * If send must go all at once and message is larger than
194  * send buffering, then hard error.
195  * Lock against other senders.
196  * If must go all at once and not enough room now, then
197  * inform user that this would block and do nothing.
198  */
199 send(so, iap)
200 	register struct socket *so;
201 	struct inaddr *iap;
202 {
203 	struct mbuf *top = 0;
204 	register struct mbuf *m, **mp = ⊤
205 	register u_int len;
206 	int error = 0, space, s;
207 
208 	if (so->so_state & SS_CANTSENDMORE)
209 		return (EPIPE);
210 	if (sosendallatonce(so) && u.u_count > so->so_snd.sb_hiwat)
211 		return (EMSGSIZE);
212 	if ((so->so_snd.sb_flags & SB_LOCK) && (so->so_options & SO_NBIO))
213 		return (EWOULDBLOCK);
214 	sblock(&so->so_snd);
215 #define	snderr(errno)	{ error = errno; splx(s); goto release; }
216 
217 	s = splnet();
218 again:
219 	if ((so->so_state & SS_ISCONNECTED) == 0) {
220 		if (so->so_proto->pr_flags & PR_CONNREQUIRED)
221 			snderr(ENOTCONN);
222 		if (iap == 0)
223 			snderr(EDESTADDRREQ);
224 	}
225 	if (so->so_error)
226 		snderr(so->so_error);
227 	if (top) {
228 		error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, top, iap);
229 		if (error) {
230 			splx(s);
231 			goto release;
232 		}
233 		top = 0;
234 		mp = ⊤
235 	}
236 	if (sosendallatonce(so) && sbspace(&so->so_snd) < u.u_count) {
237 		if (so->so_options & SO_NBIO)
238 			snderr(EWOULDBLOCK);
239 		sbunlock(&so->so_snd);
240 		sbwait(&so->so_snd);
241 		splx(s);
242 		goto again;
243 	}
244 	splx(s);
245 	while (u.u_count && (space = sbspace(&so->so_snd)) > 0) {
246 		MGET(m, 1);
247 		if (m == NULL) {
248 			error = ENOBUFS;
249 			m_freem(top);
250 			goto release;
251 		}
252 		if (u.u_count >= PGSIZE && space >= NMBPG) {
253 			register struct mbuf *p;
254 			MPGET(p, 1);
255 			if (p == 0)
256 				goto nopages;
257 			m->m_off = (int)p - (int)m;
258 			len = PGSIZE;
259 		} else {
260 nopages:
261 			m->m_off = MMINOFF;
262 			len = MIN(MLEN, u.u_count);
263 		}
264 		iomove(mtod(m, caddr_t), len, B_WRITE);
265 		m->m_len = len;
266 		*mp = m;
267 		mp = &m->m_next;
268 	}
269 	s = splnet();
270 	goto again;
271 
272 release:
273 	sbunlock(&so->so_snd);
274 	return (error);
275 }
276 
277 receive(so, iap)
278 	register struct socket *so;
279 	struct inaddr *iap;
280 {
281 	register struct mbuf *m, *n;
282 	u_int len;
283 	int eor, s, error = 0;
284 
285 restart:
286 	sblock(&so->so_rcv);
287 	s = splnet();
288 
289 #define	rcverr(errno)	{ error = errno; splx(s); goto release; }
290 	if (so->so_rcv.sb_cc == 0) {
291 		if ((so->so_state & SS_ISCONNECTED) == 0 &&
292 		    (so->so_proto->pr_flags & PR_CONNREQUIRED))
293 			rcverr(ENOTCONN);
294 		if (so->so_state & SS_CANTRCVMORE) {
295 			splx(s);
296 			goto release;
297 		}
298 		if (so->so_options & SO_NBIO)
299 			rcverr (EWOULDBLOCK);
300 		sbunlock(&so->so_rcv);
301 		sleep((caddr_t)&so->so_rcv.sb_cc, PZERO+1);
302 		goto restart;
303 	}
304 	m = so->so_rcv.sb_mb;
305 	if (m == 0)
306 		panic("receive");
307 	/*
308 	 * Pull address off receive chain, if protocol
309 	 * put one there.
310 	 */
311 	if ((so->so_proto->pr_flags & PR_ADDR)) {
312 		so->so_rcv.sb_mb = m->m_next;
313 		if (iap) {
314 			so->so_rcv.sb_cc -= m->m_len;
315 			len = MIN(m->m_len, sizeof (struct in_addr));
316 			bcopy(mtod(m, caddr_t), (caddr_t)iap, len);
317 		} else
318 			bzero((caddr_t)iap, sizeof (*iap));
319 		m = so->so_rcv.sb_mb;
320 		if (m == 0)
321 			panic("receive 2");
322 	}
323 
324 	/*
325 	 * Next pull data off the chain.
326 	 * Stop at eor or when run out of space in user buffer.
327 	 */
328 	eor = 0;
329 	do {
330 		len = MIN(m->m_len, u.u_count);
331 		if (len == m->m_len) {
332 			eor = (int)m->m_act;
333 			sbfree(&so->so_rcv, m);
334 		}
335 		splx(s);
336 		iomove(mtod(m, caddr_t), len, B_READ);
337 		s = splnet();
338 		if (len == m->m_len) {
339 			MFREE(m, n);
340 		} else {
341 			m->m_off += len;
342 			m->m_len -= len;
343 			so->so_rcv.sb_cc -= len;
344 		}
345 	} while ((m = so->so_rcv.sb_mb) && u.u_count && !eor);
346 
347 	/*
348 	 * If atomic protocol discard rest of record.
349 	 */
350 	if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0)
351 		do {
352 			if (m == 0)
353 				panic("receive 3");
354 			sbfree(&so->so_rcv, m);
355 			eor = (int)m->m_act;
356 			so->so_rcv.sb_mb = m->m_next;
357 			MFREE(m, n);
358 			m = n;
359 		} while (eor == 0);
360 
361 	/*
362 	 * If protocol cares, inform it that
363 	 * there is more space in the receive buffer.
364 	 */
365 	if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb)
366 		(*so->so_proto->pr_usrreq)(so, PRU_RCVD, 0, 0);
367 
368 release:
369 	sbunlock(&so->so_rcv);
370 	splx(s);
371 	return (error);
372 }
373 
374 /*ARGSUSED*/
375 soioctl(so, cmd, cmdp)
376 	register struct socket *so;
377 	int cmd;
378 	register caddr_t cmdp;
379 {
380 
381 	switch (cmdp) {
382 
383 	}
384 	switch (so->so_type) {
385 
386 	case SOCK_STREAM:
387 		break;
388 
389 	case SOCK_DGRAM:
390 		break;
391 
392 	case SOCK_RDM:
393 		break;
394 
395 	case SOCK_RAW:
396 		break;
397 
398 	}
399 }
400