xref: /csrg-svn/sys/kern/uipc_socket.c (revision 4927)
1*4927Swnj /*	uipc_socket.c	4.6	81/11/18	*/
24786Swnj 
34786Swnj #include "../h/param.h"
44829Swnj #include "../h/systm.h"
54786Swnj #include "../h/dir.h"
64786Swnj #include "../h/user.h"
74829Swnj #include "../h/proc.h"
84829Swnj #include "../h/file.h"
94786Swnj #include "../h/inode.h"
104829Swnj #include "../h/buf.h"
114786Swnj #include "../h/mbuf.h"
124829Swnj #include "../h/protosw.h"
134829Swnj #include "../h/socket.h"
144829Swnj #include "../h/socketvar.h"
154916Swnj #include "../h/stat.h"
164829Swnj #include "../net/inet.h"
174829Swnj #include "../net/inet_systm.h"
184786Swnj 
194786Swnj /*
204890Swnj  * Socket support routines.
214890Swnj  *
224890Swnj  * DEAL WITH INTERRUPT NOTIFICATION.
234786Swnj  */
244786Swnj 
254786Swnj /*
264786Swnj  * Create a socket.
274786Swnj  */
28*4927Swnj socreate(aso, type, asp, asa, options)
294786Swnj 	struct socket **aso;
304786Swnj 	int type;
31*4927Swnj 	struct sockproto *asp;
32*4927Swnj 	struct sockaddr *asa;
334829Swnj 	int options;
344786Swnj {
354786Swnj 	register struct protosw *prp;
364786Swnj 	register struct socket *so;
374786Swnj 	struct mbuf *m;
384890Swnj 	int pf, proto, error;
39*4927Swnj COUNT(SOCREATE);
404786Swnj 
414786Swnj 	/*
424890Swnj 	 * Use process standard protocol/protocol family if none
434890Swnj 	 * specified by address argument.
444786Swnj 	 */
45*4927Swnj 	if (asp == 0) {
464890Swnj 		pf = PF_INET;		/* should be u.u_protof */
474786Swnj 		proto = 0;
484786Swnj 	} else {
49*4927Swnj 		pf = asp->sp_family;
50*4927Swnj 		proto = asp->sp_protocol;
514786Swnj 	}
524786Swnj 
534786Swnj 	/*
544890Swnj 	 * If protocol specified, look for it, otherwise
554890Swnj 	 * for a protocol of the correct type in the right family.
564890Swnj 	 */
574890Swnj 	if (proto)
584890Swnj 		prp = pffindproto(pf, proto);
594890Swnj 	else
604890Swnj 		prp = pffindtype(pf, type);
614890Swnj 	if (prp == 0)
624890Swnj 		return (EPROTONOSUPPORT);
634890Swnj 
644890Swnj 	/*
654786Swnj 	 * Get a socket structure.
664786Swnj 	 */
674890Swnj 	m = m_getclr(M_WAIT);
684786Swnj 	if (m == 0)
694786Swnj 		return (ENOBUFS);
704786Swnj 	so = mtod(m, struct socket *);
714829Swnj 	so->so_options = options;
724786Swnj 
734786Swnj 	/*
744890Swnj 	 * Attach protocol to socket, initializing
754890Swnj 	 * and reserving resources.
764786Swnj 	 */
774786Swnj 	so->so_proto = prp;
78*4927Swnj 	(*prp->pr_usrreq)(so, PRU_ATTACH, 0, asa);
794786Swnj 	if (so->so_error) {
804890Swnj 		error = so->so_error;
814786Swnj 		m_free(dtom(so));
824890Swnj 		return (error);
834786Swnj 	}
844786Swnj 	*aso = so;
854786Swnj 	return (0);
864786Swnj }
874786Swnj 
884916Swnj sofree(so)
894916Swnj 	struct socket *so;
904916Swnj {
914916Swnj 
92*4927Swnj COUNT(SOFREE);
934916Swnj 	m_free(dtom(so));
944916Swnj }
954916Swnj 
964786Swnj /*
974890Swnj  * Close a socket on last file table reference removal.
984890Swnj  * Initiate disconnect if connected.
994890Swnj  * Free socket when disconnect complete.
1004829Swnj  */
1014890Swnj soclose(so)
1024829Swnj 	register struct socket *so;
1034829Swnj {
1044890Swnj 	int s = splnet();		/* conservative */
1054829Swnj 
106*4927Swnj COUNT(SOCLOSE);
1074890Swnj 	if (so->so_pcb == 0)
1084890Swnj 		goto discard;
1094890Swnj 	if (so->so_state & SS_ISCONNECTED) {
1104890Swnj 		if ((so->so_state & SS_ISDISCONNECTING) == 0) {
111*4927Swnj 			u.u_error = sodisconnect(so, (struct sockaddr *)0);
1124890Swnj 			if (u.u_error) {
1134890Swnj 				splx(s);
1144890Swnj 				return;
1154890Swnj 			}
1164890Swnj 		}
1174890Swnj 		if ((so->so_state & SS_ISDISCONNECTING) &&
1184890Swnj 		    (so->so_options & SO_NBIO)) {
1194890Swnj 			u.u_error = EINPROGRESS;
1204890Swnj 			splx(s);
1214890Swnj 			return;
1224890Swnj 		}
1234890Swnj 		while (so->so_state & SS_ISCONNECTED)
1244890Swnj 			sleep((caddr_t)&so->so_timeo, PZERO+1);
1254890Swnj 	}
1264890Swnj 	u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_DETACH, 0, 0);
1274890Swnj discard:
1284890Swnj 	if (so->so_pcb == 0)
1294890Swnj 		sofree(so);
1304890Swnj 	splx(s);
1314829Swnj }
1324829Swnj 
133*4927Swnj sosplice(pso, so)
134*4927Swnj 	struct socket *pso, *so;
135*4927Swnj {
136*4927Swnj 
137*4927Swnj COUNT(SOSPLICE);
138*4927Swnj 	if (pso->so_proto->pr_family != PF_LOCAL) {
139*4927Swnj 		struct socket *tso;
140*4927Swnj 		tso = pso; pso = so; so = tso;
141*4927Swnj 	}
142*4927Swnj 	if (pso->so_proto->pr_family != PF_LOCAL)
143*4927Swnj 		return (EOPNOTSUPP);
144*4927Swnj 	/* check types and buffer space */
145*4927Swnj 	/* merge buffers */
146*4927Swnj 	return (0);
147*4927Swnj }
148*4927Swnj 
1494916Swnj /*ARGSUSED*/
1504890Swnj sostat(so, sb)
1514829Swnj 	struct socket *so;
1524890Swnj 	struct stat *sb;
1534829Swnj {
1544829Swnj 
155*4927Swnj COUNT(SOSTAT);
1564890Swnj 	return (EOPNOTSUPP);
1574829Swnj }
1584829Swnj 
1594829Swnj /*
160*4927Swnj  * Accept connection on a socket.
161*4927Swnj  */
162*4927Swnj soaccept(so, asa)
163*4927Swnj 	struct socket *so;
164*4927Swnj 	struct sockaddr *asa;
165*4927Swnj {
166*4927Swnj 	int s = splnet();
167*4927Swnj 	int error;
168*4927Swnj 
169*4927Swnj COUNT(SOACCEPT);
170*4927Swnj 	if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) {
171*4927Swnj 		error = EISCONN;
172*4927Swnj 		goto bad;
173*4927Swnj 	}
174*4927Swnj 	if ((so->so_options & SO_ACCEPTCONN) == 0) {
175*4927Swnj 		error = EINVAL;			/* XXX */
176*4927Swnj 		goto bad;
177*4927Swnj 	}
178*4927Swnj 	error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, 0, (caddr_t)asa);
179*4927Swnj bad:
180*4927Swnj 	splx(s);
181*4927Swnj 	return (error);
182*4927Swnj }
183*4927Swnj 
184*4927Swnj /*
1854890Swnj  * Connect socket to a specified address.
1864890Swnj  * If already connected or connecting, then avoid
1874890Swnj  * the protocol entry, to keep its job simpler.
1884786Swnj  */
189*4927Swnj soconnect(so, asa)
1904786Swnj 	struct socket *so;
191*4927Swnj 	struct sockaddr *asa;
1924786Swnj {
1934890Swnj 	int s = splnet();
1944890Swnj 	int error;
1954786Swnj 
196*4927Swnj COUNT(SOCONNECT);
1974890Swnj 	if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) {
1984890Swnj 		error = EISCONN;
1994890Swnj 		goto bad;
2004890Swnj 	}
201*4927Swnj 	error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 0, (caddr_t)asa);
2024890Swnj bad:
2034890Swnj 	splx(s);
2044890Swnj 	return (error);
2054786Swnj }
2064786Swnj 
2074786Swnj /*
2084890Swnj  * Disconnect from a socket.
2094890Swnj  * Address parameter is from system call for later multicast
2104890Swnj  * protocols.  Check to make sure that connected and no disconnect
2114890Swnj  * in progress (for protocol's sake), and then invoke protocol.
2124786Swnj  */
213*4927Swnj sodisconnect(so, asa)
2144786Swnj 	struct socket *so;
215*4927Swnj 	struct sockaddr *asa;
2164786Swnj {
2174890Swnj 	int s = splnet();
2184890Swnj 	int error;
2194786Swnj 
220*4927Swnj COUNT(SODISCONNECT);
2214890Swnj 	if ((so->so_state & SS_ISCONNECTED) == 0) {
2224890Swnj 		error = ENOTCONN;
2234890Swnj 		goto bad;
2244890Swnj 	}
2254890Swnj 	if (so->so_state & SS_ISDISCONNECTING) {
2264890Swnj 		error = EALREADY;
2274890Swnj 		goto bad;
2284890Swnj 	}
229*4927Swnj 	error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 0, asa);
2304890Swnj bad:
2314890Swnj 	splx(s);
2324890Swnj 	return (error);
2334786Swnj }
2344786Swnj 
2354786Swnj /*
2364890Swnj  * Send on a socket.
2374890Swnj  * If send must go all at once and message is larger than
2384890Swnj  * send buffering, then hard error.
2394890Swnj  * Lock against other senders.
2404890Swnj  * If must go all at once and not enough room now, then
2414890Swnj  * inform user that this would block and do nothing.
2424786Swnj  */
243*4927Swnj sosend(so, asa)
2444786Swnj 	register struct socket *so;
245*4927Swnj 	struct sockaddr *asa;
2464786Swnj {
2474890Swnj 	struct mbuf *top = 0;
2484890Swnj 	register struct mbuf *m, **mp = ⊤
2494916Swnj 	register u_int len;
2504916Swnj 	int error = 0, space, s;
2514786Swnj 
252*4927Swnj COUNT(SOSEND);
2534890Swnj 	if (so->so_state & SS_CANTSENDMORE)
2544890Swnj 		return (EPIPE);
2554890Swnj 	if (sosendallatonce(so) && u.u_count > so->so_snd.sb_hiwat)
2564890Swnj 		return (EMSGSIZE);
2574890Swnj 	if ((so->so_snd.sb_flags & SB_LOCK) && (so->so_options & SO_NBIO))
2584890Swnj 		return (EWOULDBLOCK);
2594890Swnj 	sblock(&so->so_snd);
2604890Swnj #define	snderr(errno)	{ error = errno; splx(s); goto release; }
2614890Swnj 
2624890Swnj 	s = splnet();
2634890Swnj again:
2644890Swnj 	if ((so->so_state & SS_ISCONNECTED) == 0) {
2654890Swnj 		if (so->so_proto->pr_flags & PR_CONNREQUIRED)
2664890Swnj 			snderr(ENOTCONN);
267*4927Swnj 		if (asa == 0)
2684890Swnj 			snderr(EDESTADDRREQ);
2694890Swnj 	}
2704890Swnj 	if (so->so_error)
2714890Swnj 		snderr(so->so_error);
2724890Swnj 	if (top) {
273*4927Swnj 		error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, top, asa);
2744890Swnj 		if (error) {
2754890Swnj 			splx(s);
2764786Swnj 			goto release;
2774786Swnj 		}
2784890Swnj 		top = 0;
2794890Swnj 		mp = ⊤
2804786Swnj 	}
2814890Swnj 	if (sosendallatonce(so) && sbspace(&so->so_snd) < u.u_count) {
2824890Swnj 		if (so->so_options & SO_NBIO)
2834890Swnj 			snderr(EWOULDBLOCK);
2844890Swnj 		sbunlock(&so->so_snd);
2854890Swnj 		sbwait(&so->so_snd);
2864890Swnj 		splx(s);
2874786Swnj 		goto again;
2884786Swnj 	}
2894890Swnj 	splx(s);
2904916Swnj 	while (u.u_count && (space = sbspace(&so->so_snd)) > 0) {
2914890Swnj 		MGET(m, 1);
2924890Swnj 		if (m == NULL) {
2934890Swnj 			error = ENOBUFS;
2944890Swnj 			m_freem(top);
2954890Swnj 			goto release;
2964786Swnj 		}
2974916Swnj 		if (u.u_count >= PGSIZE && space >= NMBPG) {
2984890Swnj 			register struct mbuf *p;
2994890Swnj 			MPGET(p, 1);
3004890Swnj 			if (p == 0)
3014890Swnj 				goto nopages;
3024890Swnj 			m->m_off = (int)p - (int)m;
3034890Swnj 			len = PGSIZE;
3044890Swnj 		} else {
3054786Swnj nopages:
3064890Swnj 			m->m_off = MMINOFF;
3074890Swnj 			len = MIN(MLEN, u.u_count);
3084786Swnj 		}
3094890Swnj 		iomove(mtod(m, caddr_t), len, B_WRITE);
3104890Swnj 		m->m_len = len;
3114890Swnj 		*mp = m;
3124890Swnj 		mp = &m->m_next;
3134786Swnj 	}
3144890Swnj 	s = splnet();
3154890Swnj 	goto again;
3164890Swnj 
3174786Swnj release:
3184890Swnj 	sbunlock(&so->so_snd);
3194786Swnj 	return (error);
3204786Swnj }
3214786Swnj 
322*4927Swnj soreceive(so, asa)
3234786Swnj 	register struct socket *so;
324*4927Swnj 	struct sockaddr *asa;
3254786Swnj {
3264786Swnj 	register struct mbuf *m, *n;
3274916Swnj 	u_int len;
3284890Swnj 	int eor, s, error = 0;
3294786Swnj 
330*4927Swnj COUNT(SORECEIVE);
3314890Swnj restart:
3324890Swnj 	sblock(&so->so_rcv);
3334890Swnj 	s = splnet();
3344890Swnj 
3354890Swnj #define	rcverr(errno)	{ error = errno; splx(s); goto release; }
3364786Swnj 	if (so->so_rcv.sb_cc == 0) {
3374890Swnj 		if ((so->so_state & SS_ISCONNECTED) == 0 &&
3384890Swnj 		    (so->so_proto->pr_flags & PR_CONNREQUIRED))
3394890Swnj 			rcverr(ENOTCONN);
3404890Swnj 		if (so->so_state & SS_CANTRCVMORE) {
3414890Swnj 			splx(s);
3424890Swnj 			goto release;
3434890Swnj 		}
3444890Swnj 		if (so->so_options & SO_NBIO)
3454916Swnj 			rcverr (EWOULDBLOCK);
3464890Swnj 		sbunlock(&so->so_rcv);
3474786Swnj 		sleep((caddr_t)&so->so_rcv.sb_cc, PZERO+1);
3484890Swnj 		goto restart;
3494786Swnj 	}
3504829Swnj 	m = so->so_rcv.sb_mb;
3514786Swnj 	if (m == 0)
3524786Swnj 		panic("receive");
3534890Swnj 	if ((so->so_proto->pr_flags & PR_ADDR)) {
3544890Swnj 		so->so_rcv.sb_mb = m->m_next;
355*4927Swnj 		if (asa) {
3564890Swnj 			so->so_rcv.sb_cc -= m->m_len;
357*4927Swnj 			len = MIN(m->m_len, sizeof (struct sockaddr));
358*4927Swnj 			bcopy(mtod(m, caddr_t), (caddr_t)asa, len);
3594890Swnj 		} else
360*4927Swnj 			bzero((caddr_t)asa, sizeof (*asa));
3614890Swnj 		m = so->so_rcv.sb_mb;
3624890Swnj 		if (m == 0)
3634890Swnj 			panic("receive 2");
3644890Swnj 	}
3654786Swnj 	eor = 0;
3664786Swnj 	do {
3674786Swnj 		len = MIN(m->m_len, u.u_count);
3684786Swnj 		if (len == m->m_len) {
3694786Swnj 			eor = (int)m->m_act;
3704890Swnj 			sbfree(&so->so_rcv, m);
3714786Swnj 		}
3724786Swnj 		splx(s);
3734786Swnj 		iomove(mtod(m, caddr_t), len, B_READ);
3744786Swnj 		s = splnet();
3754786Swnj 		if (len == m->m_len) {
3764786Swnj 			MFREE(m, n);
3774786Swnj 		} else {
3784786Swnj 			m->m_off += len;
3794786Swnj 			m->m_len -= len;
3804829Swnj 			so->so_rcv.sb_cc -= len;
3814786Swnj 		}
3824829Swnj 	} while ((m = so->so_rcv.sb_mb) && u.u_count && !eor);
3834786Swnj 	if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0)
3844786Swnj 		do {
3854786Swnj 			if (m == 0)
3864890Swnj 				panic("receive 3");
3874890Swnj 			sbfree(&so->so_rcv, m);
3884786Swnj 			eor = (int)m->m_act;
3894786Swnj 			so->so_rcv.sb_mb = m->m_next;
3904786Swnj 			MFREE(m, n);
3914890Swnj 			m = n;
3924786Swnj 		} while (eor == 0);
3934890Swnj 	if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb)
3944890Swnj 		(*so->so_proto->pr_usrreq)(so, PRU_RCVD, 0, 0);
3954890Swnj release:
3964916Swnj 	sbunlock(&so->so_rcv);
3974890Swnj 	splx(s);
3984916Swnj 	return (error);
3994786Swnj }
4004786Swnj 
4014916Swnj /*ARGSUSED*/
4024916Swnj soioctl(so, cmd, cmdp)
4034829Swnj 	register struct socket *so;
4044829Swnj 	int cmd;
4054829Swnj 	register caddr_t cmdp;
4064786Swnj {
4074786Swnj 
408*4927Swnj COUNT(SOIOCTL);
4094829Swnj 	switch (cmdp) {
4104829Swnj 
4114829Swnj 	}
4124829Swnj 	switch (so->so_type) {
4134829Swnj 
4144829Swnj 	case SOCK_STREAM:
4154829Swnj 		break;
4164829Swnj 
4174829Swnj 	case SOCK_DGRAM:
4184829Swnj 		break;
4194829Swnj 
4204829Swnj 	case SOCK_RDM:
4214829Swnj 		break;
4224829Swnj 
4234829Swnj 	case SOCK_RAW:
4244829Swnj 		break;
4254829Swnj 
4264829Swnj 	}
4274786Swnj }
428