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