|
|
1.1 root 1: /* in_pcb.c 6.1 83/07/29 */
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 "../netinet/in.h"
11: #include "../netinet/in_systm.h"
12: #include "../net/if.h"
13: #include "../net/route.h"
14: #include "../netinet/in_pcb.h"
15: #include "../h/protosw.h"
16:
17: struct in_addr zeroin_addr;
1.1.1.2 ! root 18: extern struct inpcb tcb;
1.1 root 19:
20: in_pcballoc(so, head)
21: struct socket *so;
22: struct inpcb *head;
23: {
24: struct mbuf *m;
25: register struct inpcb *inp;
26:
27: m = m_getclr(M_DONTWAIT, MT_PCB);
28: MBUFNULL(45, m); /* for debugging */
29: if (m == NULL)
30: return (ENOBUFS);
31: inp = mtod(m, struct inpcb *);
32: inp->inp_head = head;
33: inp->inp_socket = so;
34: insque(inp, head);
35: so->so_pcb = (caddr_t)inp;
36: return (0);
37: }
38:
39: in_pcbbind(inp, nam)
40: register struct inpcb *inp;
41: struct mbuf *nam;
42: {
43: register struct socket *so = inp->inp_socket;
44: register struct inpcb *head = inp->inp_head;
45: register struct sockaddr_in *sin;
46: u_short lport = 0;
47:
48: if (ifnet == 0)
49: return (EADDRNOTAVAIL);
50: if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY)
51: return (EINVAL);
52: if (nam == 0)
53: goto noname;
54: sin = mtod(nam, struct sockaddr_in *);
55: if (nam->m_len != sizeof (*sin))
56: return (EINVAL);
57: if (sin->sin_addr.s_addr != INADDR_ANY) {
58: int tport = sin->sin_port;
59:
60: sin->sin_port = 0; /* yech... */
61: if (if_ifwithaddr((struct sockaddr *)sin) == 0)
62: return (EADDRNOTAVAIL);
63: sin->sin_port = tport;
64: }
65: lport = sin->sin_port;
66: if (lport) {
67: u_short aport = ntohs(lport);
68: int wild = 0;
69:
70: /* GROSS */
71: if (aport < IPPORT_RESERVED && u.u_uid != 0)
72: return (EACCES);
73: /* even GROSSER, but this is the Internet */
74: if ((so->so_options & SO_REUSEADDR) == 0 &&
75: ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 ||
76: (so->so_options & SO_ACCEPTCONN) == 0))
77: wild = INPLOOKUP_WILDCARD;
78: if (in_pcblookup(head,
79: zeroin_addr, 0, sin->sin_addr, lport, wild))
80: return (EADDRINUSE);
81: }
82: inp->inp_laddr = sin->sin_addr;
83: noname:
84: if (lport == 0)
85: do {
86: if (head->inp_lport++ < IPPORT_RESERVED)
87: head->inp_lport = IPPORT_RESERVED;
88: lport = htons(head->inp_lport);
89: } while (in_pcblookup(head,
90: zeroin_addr, 0, inp->inp_laddr, lport, 0));
91: inp->inp_lport = lport;
92: return (0);
93: }
94:
95: /*
96: * Connect from a socket to a specified address.
97: * Both address and port must be specified in argument sin.
98: * If don't have a local address for this socket yet,
99: * then pick one.
100: */
101: in_pcbconnect(inp, nam)
102: struct inpcb *inp;
103: struct mbuf *nam;
104: {
105: struct ifnet *ifp;
106: struct sockaddr_in *ifaddr;
107: register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
1.1.1.2 ! root 108: struct route ro;
1.1 root 109:
110: if (nam->m_len != sizeof (*sin))
111: return (EINVAL);
112: if (sin->sin_family != AF_INET)
113: return (EAFNOSUPPORT);
114: if (sin->sin_addr.s_addr == INADDR_ANY || sin->sin_port == 0)
115: return (EADDRNOTAVAIL);
1.1.1.2 ! root 116:
1.1 root 117: if (inp->inp_laddr.s_addr == INADDR_ANY) {
1.1.1.2 ! root 118: if (inp->inp_head == &tcb) {
! 119: register short *sptr, *dptr;
! 120:
! 121: /* TCP protocol; bind local address
! 122: to that of route to be used.
! 123: */
! 124: bzero((caddr_t)&ro,sizeof(ro));
! 125: ro.ro_dst.sa_family = AF_INET;
! 126: ((struct sockaddr_in *)&ro.ro_dst)->sin_addr = sin->sin_addr;
! 127: rtalloc(&ro);
! 128: if (ro.ro_rt == 0 ||
! 129: ((ifp = ro.ro_rt->rt_ifp) == 0)) {
! 130: goto nxttry;
! 131: }
! 132: rtfree(ro.ro_rt);
! 133: }
! 134: else {
! 135: nxttry:
! 136: ifp = if_ifonnetof(in_netof(sin->sin_addr));
! 137: }
! 138:
1.1 root 139: if (ifp == 0) {
140: ifp = if_ifwithaf(AF_INET);
141: if (ifp == 0)
142: return (EADDRNOTAVAIL);
143: }
144: ifaddr = (struct sockaddr_in *)&ifp->if_addr;
145: }
146: if (in_pcblookup(inp->inp_head,
147: sin->sin_addr,
148: sin->sin_port,
149: inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr,
150: inp->inp_lport,
151: 0))
152: return (EADDRINUSE);
153: if (inp->inp_laddr.s_addr == INADDR_ANY) {
154: if (inp->inp_lport == 0)
155: in_pcbbind(inp, (struct mbuf *)0);
156: inp->inp_laddr = ifaddr->sin_addr;
157: }
158: inp->inp_faddr = sin->sin_addr;
159: inp->inp_fport = sin->sin_port;
160: return (0);
161: }
162:
163: in_pcbdisconnect(inp)
164: struct inpcb *inp;
165: {
166:
167: inp->inp_faddr.s_addr = INADDR_ANY;
168: inp->inp_fport = 0;
169: if (inp->inp_socket->so_state & SS_NOFDREF)
170: in_pcbdetach(inp);
171: }
172:
173: in_pcbdetach(inp)
174: struct inpcb *inp;
175: {
176: struct socket *so = inp->inp_socket;
177:
178: so->so_pcb = 0;
179: sofree(so);
180: if (inp->inp_route.ro_rt)
181: rtfree(inp->inp_route.ro_rt);
182: remque(inp);
183: (void) m_free(dtom(inp));
184: }
185:
186: in_setsockaddr(inp, nam)
187: register struct inpcb *inp;
188: struct mbuf *nam;
189: {
190: register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
191:
192: nam->m_len = sizeof (*sin);
193: sin = mtod(nam, struct sockaddr_in *);
194: bzero((caddr_t)sin, sizeof (*sin));
195: sin->sin_family = AF_INET;
196: sin->sin_port = inp->inp_lport;
197: sin->sin_addr = inp->inp_laddr;
198: }
199:
200: in_setpeeraddr(inp, nam)
201: register struct inpcb *inp;
202: struct mbuf *nam;
203: {
204: register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
205:
206: nam->m_len = sizeof (*sin);
207: sin = mtod(nam, struct sockaddr_in *);
208: bzero((caddr_t)sin, sizeof (*sin));
209: sin->sin_family = AF_INET;
210: sin->sin_port = inp->inp_fport;
211: sin->sin_addr = inp->inp_faddr;
212: }
213:
214: /*
215: * Pass an error to all internet connections
216: * associated with address sin. Call the
217: * protocol specific routine to clean up the
218: * mess afterwards.
219: */
220: in_pcbnotify(head, dst, errno, abort)
221: struct inpcb *head;
222: register struct in_addr *dst;
223: int errno, (*abort)();
224: {
225: register struct inpcb *inp, *oinp;
226: int s = splimp();
227:
228: for (inp = head->inp_next; inp != head;) {
229: if (inp->inp_faddr.s_addr != dst->s_addr) {
230: next:
231: inp = inp->inp_next;
232: continue;
233: }
234: if (inp->inp_socket == 0)
235: goto next;
236: inp->inp_socket->so_error = errno;
237: oinp = inp;
238: inp = inp->inp_next;
239: (*abort)(oinp);
240: }
241: splx(s);
242: }
243:
244: struct inpcb *
245: in_pcblookup(head, faddr, fport, laddr, lport, flags)
246: struct inpcb *head;
247: struct in_addr faddr, laddr;
248: u_short fport, lport;
249: int flags;
250: {
251: register struct inpcb *inp, *match = 0;
252: int matchwild = 3, wildcard;
253:
254: for (inp = head->inp_next; inp != head; inp = inp->inp_next) {
255: if (inp->inp_lport != lport)
256: continue;
257: wildcard = 0;
258: if (inp->inp_laddr.s_addr != INADDR_ANY) {
259: if (laddr.s_addr == INADDR_ANY)
260: wildcard++;
261: else if (inp->inp_laddr.s_addr != laddr.s_addr)
262: continue;
263: } else {
264: if (laddr.s_addr != INADDR_ANY)
265: wildcard++;
266: }
267: if (inp->inp_faddr.s_addr != INADDR_ANY) {
268: if (faddr.s_addr == INADDR_ANY)
269: wildcard++;
270: else if (inp->inp_faddr.s_addr != faddr.s_addr ||
271: inp->inp_fport != fport)
272: continue;
273: } else {
274: if (faddr.s_addr != INADDR_ANY)
275: wildcard++;
276: }
277: if (wildcard && (flags & INPLOOKUP_WILDCARD) == 0)
278: continue;
279: if (wildcard < matchwild) {
280: match = inp;
281: matchwild = wildcard;
282: if (matchwild == 0)
283: break;
284: }
285: }
286: return (match);
287: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.