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