1 /* in_pcb.c 6.2 84/08/29 */ 2 3 #include "param.h" 4 #include "systm.h" 5 #include "dir.h" 6 #include "user.h" 7 #include "mbuf.h" 8 #include "socket.h" 9 #include "socketvar.h" 10 #include "in.h" 11 #include "in_systm.h" 12 #include "../net/if.h" 13 #include "../net/route.h" 14 #include "in_pcb.h" 15 #include "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 } 270