xref: /csrg-svn/sys/netinet/in_pcb.c (revision 4983)
1 /* in_pcb.c 4.7 81/11/21 */
2 
3 #include "../h/param.h"
4 #include "../h/systm.h"
5 #include "../h/dir.h"
6 #include "../h/user.h"
7 #include "../h/mbuf.h"
8 #include "../h/socket.h"
9 #include "../h/socketvar.h"
10 #include "../net/inet.h"
11 #include "../net/inet_systm.h"
12 #include "../net/if.h"
13 #include "../net/inet_pcb.h"
14 
15 /*
16  * Allocate a protocol control block, space
17  * for send and receive data, and local host information.
18  * Return error.  If no error make socket point at pcb.
19  */
20 in_pcballoc(so, head, sndcc, rcvcc, sin)
21 	struct socket *so;
22 	struct inpcb *head;
23 	int sndcc, rcvcc;
24 	struct sockaddr_in *sin;
25 {
26 	struct mbuf *m;
27 	register struct inpcb *inp, *xp;
28 	struct ifnet *ifp;
29 	u_long lport;
30 
31 	if (sin) {
32 		if (sin->sin_family != AF_INET)
33 			return (EAFNOSUPPORT);
34 		ifp = if_ifwithaddr(sin->sin_addr);
35 		if (ifp == 0)
36 			return (EADDRNOTAVAIL);
37 		lport = sin->sin_port;
38 		if (lport) {
39 			xp = head->inp_next;
40 			for (; xp != head; xp = inp->inp_next)
41 				if (xp->inp_laddr.s_addr ==
42 				    sin->sin_addr.s_addr &&
43 				    xp->inp_lport == lport &&
44 				    xp->inp_faddr.s_addr == 0)
45 					return (EADDRINUSE);
46 		}
47 	} else {
48 		ifp = if_ifwithaddr(ifnet->if_addr);
49 		lport = 0;
50 	}
51 	m = m_getclr(M_WAIT);
52 	if (m == 0)
53 		return (ENOBUFS);
54 	if (sbreserve(&so->so_snd, sndcc) == 0)
55 		goto bad;
56 	if (sbreserve(&so->so_rcv, rcvcc) == 0)
57 		goto bad2;
58 	inp = mtod(m, struct inpcb *);
59 	inp->inp_laddr = ifp->if_addr;
60 	if (lport)
61 		goto gotport;
62 again:
63 	if (head->inp_lport++ < 1024)
64 		head->inp_lport = 1024;
65 	for (xp = head->inp_next; xp != head; xp = xp->inp_next)
66 		if (xp->inp_lport == head->inp_lport)
67 			goto again;
68 	lport = head->inp_lport;
69 gotport:
70 	inp->inp_socket = so;
71 	inp->inp_lport = lport;
72 	insque(inp, head);
73 	so->so_pcb = (caddr_t)inp;
74 	sin = (struct sockaddr_in *)&so->so_addr;
75 	sin->sin_family = AF_INET;
76 	sin->sin_addr = inp->inp_laddr;
77 	sin->sin_port = inp->inp_lport;
78 	return (0);
79 bad2:
80 	sbrelease(&so->so_snd);
81 bad:
82 	(void) m_free(m);
83 	return (ENOBUFS);
84 }
85 
86 in_pcbsetpeer(inp, sin)
87 	struct inpcb *inp;
88 	struct sockaddr_in *sin;
89 {
90 
91 	if (sin->sin_family != AF_INET)
92 		return (EAFNOSUPPORT);
93 	if (sin->sin_addr.s_addr == 0 || sin->sin_port == 0)
94 		return (EADDRNOTAVAIL);
95 	/* should check not already in use... */
96 	inp->inp_faddr = sin->sin_addr;
97 	inp->inp_fport = sin->sin_port;
98 	return (0);
99 }
100 
101 in_pcbfree(inp)
102 	struct inpcb *inp;
103 {
104 	struct socket *so = inp->inp_socket;
105 
106 	if (so->so_state & SS_USERGONE)
107 		sofree(so);
108 	else
109 		so->so_pcb = 0;
110 	remque(inp);
111 	(void) m_free(dtom(inp));
112 }
113 
114 struct inpcb *
115 in_pcblookup(head, faddr, fport, laddr, lport)
116 	struct inpcb *head;
117 	struct in_addr faddr, laddr;
118 	u_short fport, lport;
119 {
120 	register struct inpcb *inp;
121 
122 	for (inp = head->inp_next; inp != head; inp = inp->inp_next)
123 		if (inp->inp_faddr.s_addr == faddr.s_addr &&
124 		    inp->inp_fport == fport &&
125 		    inp->inp_laddr.s_addr == laddr.s_addr &&
126 		    inp->inp_lport == lport)
127 			return (inp);
128 	for (inp = head->inp_next; inp != head; inp = inp->inp_next)
129 		if ((inp->inp_faddr.s_addr == faddr.s_addr ||
130 		     inp->inp_faddr.s_addr == 0) &&
131 		    (inp->inp_fport == fport || inp->inp_fport == 0) &&
132 		     inp->inp_laddr.s_addr == laddr.s_addr &&
133 		    (inp->inp_lport == lport || inp->inp_lport == 0))
134 			return (inp);
135 	return (0);
136 }
137