1 /* uipc_usrreq.c 1.1 82/10/28 */ 2 3 #include "../h/param.h" 4 #include "../h/dir.h" 5 #include "../h/user.h" 6 #include "../h/mbuf.h" 7 #include "../h/protosw.h" 8 #include "../h/socket.h" 9 #include "../h/socketvar.h" 10 #include "../h/unpcb.h" 11 #include "../h/un.h" 12 #include "../h/inode.h" 13 14 /* 15 * Unix communications domain. 16 */ 17 18 /*ARGSUSED*/ 19 uipc_usrreq(so, req, m, addr) 20 struct socket *so; 21 int req; 22 struct mbuf *m; 23 caddr_t addr; 24 { 25 struct unpcb *unp = sotounpcb(so); 26 register struct socket *so2; 27 int error = 0; 28 29 if (unp == 0 && req != PRU_ATTACH) 30 return (EINVAL); /* XXX */ 31 switch (req) { 32 33 case PRU_ATTACH: 34 if (unp) { 35 error = EINVAL; 36 break; 37 } 38 error = unp_attach(so, (struct sockaddr *)addr); 39 break; 40 41 case PRU_DETACH: 42 unp_detach(unp); 43 break; 44 45 case PRU_CONNECT: 46 error = unp_connect(so, (struct sockaddr_un *)addr); 47 break; 48 49 case PRU_DISCONNECT: 50 unp_disconnect(unp); 51 break; 52 53 /* BEGIN QUESTIONABLE */ 54 case PRU_ACCEPT: { 55 struct sockaddr_un *soun = (struct sockaddr_un *)addr; 56 57 if (soun) { 58 bzero((caddr_t)soun, sizeof (*soun)); 59 soun->sun_family = AF_UNIX; 60 /* XXX */ 61 } 62 } 63 break; 64 65 case PRU_SHUTDOWN: 66 socantsendmore(so); 67 unp_usrclosed(unp); 68 break; 69 /* END QUESTIONABLE */ 70 71 case PRU_RCVD: 72 switch (so->so_type) { 73 74 case SOCK_DGRAM: 75 panic("uipc 1"); 76 77 case SOCK_STREAM: { 78 #define rcv (&so->so_rcv) 79 #define snd (&so2->so_snd) 80 if (unp->unp_conn == 0) 81 break; 82 so2 = unp->unp_conn->unp_socket; 83 /* 84 * Transfer resources back to send port 85 * and wakeup any waiting to write. 86 */ 87 snd->sb_mbmax += rcv->sb_mbmax - rcv->sb_mbcnt; 88 rcv->sb_mbmax = rcv->sb_mbcnt; 89 snd->sb_hiwat += rcv->sb_hiwat - rcv->sb_cc; 90 rcv->sb_hiwat = rcv->sb_cc; 91 sbwakeup(snd); 92 #undef snd 93 #undef rcv 94 } 95 break; 96 97 default: 98 panic("uipc 2"); 99 } 100 break; 101 102 case PRU_SEND: 103 switch (so->so_type) { 104 105 case SOCK_DGRAM: 106 if (addr) { 107 if (unp->unp_conn) { 108 error = EISCONN; 109 break; 110 } 111 error = unp_connect(so, addr); 112 if (error) 113 break; 114 } else { 115 if (unp->unp_conn == 0) { 116 error = ENOTCONN; 117 break; 118 } 119 } 120 so2 = unp->unp_conn->unp_socket; 121 if (sbspace(&so2->so_rcv) > 0) /* XXX */ 122 sbappendaddr(so2, m, addr); /* XXX */ 123 if (addr) 124 unp_disconnect(so); 125 break; 126 127 case SOCK_STREAM: 128 #define rcv (&so2->so_rcv) 129 #define snd (&so->so_snd) 130 if (unp->unp_conn == 0) 131 panic("uipc 3"); 132 so2 = unp->unp_conn->unp_socket; 133 /* 134 * Send to paired receive port, and then 135 * give it enough resources to hold what it already has. 136 * Wake up readers. 137 */ 138 sbappend(rcv, m); 139 snd->sb_mbmax -= rcv->sb_mbcnt - rcv->sb_mbmax; 140 rcv->sb_mbmax = rcv->sb_mbcnt; 141 snd->sb_hiwat -= rcv->sb_cc - rcv->sb_hiwat; 142 rcv->sb_hiwat = rcv->sb_cc; 143 sbwakeup(rcv); 144 #undef snd 145 #undef rcv 146 break; 147 148 default: 149 panic("uipc 4"); 150 } 151 break; 152 153 case PRU_ABORT: 154 unp_drop(unp, ECONNABORTED); 155 break; 156 157 /* SOME AS YET UNIMPLEMENTED HOOKS */ 158 case PRU_CONTROL: 159 error = EOPNOTSUPP; 160 break; 161 162 case PRU_SENSE: 163 error = EOPNOTSUPP; 164 break; 165 /* END UNIMPLEMENTED HOOKS */ 166 167 case PRU_RCVOOB: 168 break; 169 170 case PRU_SENDOOB: 171 break; 172 173 case PRU_SOCKADDR: 174 break; 175 176 case PRU_SLOWTIMO: 177 break; 178 179 default: 180 panic("piusrreq"); 181 } 182 return (0); 183 } 184 185 int unp_sendspace = 1024*2; 186 int unp_recvspace = 1024*2; 187 188 unp_attach(so, soun) 189 struct socket *so; 190 struct sockaddr_un *soun; 191 { 192 register struct unpcb *unp; 193 struct mbuf *m; 194 int error; 195 196 error = soreserve(so, unp_sendspace, unp_recvspace); 197 if (error) 198 goto bad; 199 m = m_getclr(M_DONTWAIT); 200 if (m == 0) { 201 error = ENOBUFS; 202 goto bad; 203 } 204 unp = mtod(m, struct unpcb *); 205 so->so_pcb = (caddr_t)unp; 206 unp->unp_socket = so; 207 if (soun) { 208 error = unp_bind(unp, soun); 209 if (error) { 210 unp_detach(unp); 211 goto bad; 212 } 213 } 214 return (0); 215 bad: 216 return (error); 217 } 218 219 unp_disconnect(unp) 220 struct unpcb *unp; 221 { 222 register struct unpcb *unp2 = unp->unp_conn; 223 224 if (unp2 == 0) 225 return; 226 unp->unp_conn = 0; 227 soisdisconnected(unp->unp_socket); 228 switch (unp->unp_socket->so_type) { 229 230 case SOCK_DGRAM: 231 if (unp2->unp_refs == unp) 232 unp2->unp_refs = unp->unp_nextref; 233 else { 234 unp2 = unp2->unp_refs; 235 for (;;) { 236 if (unp2 == 0) 237 panic("unp_disconnect"); 238 if (unp2->unp_nextref == unp) 239 break; 240 unp2 = unp2->unp_nextref; 241 } 242 unp2->unp_nextref = unp->unp_nextref; 243 } 244 unp->unp_nextref = 0; 245 break; 246 247 case SOCK_STREAM: 248 unp2->unp_conn = 0; 249 soisdisconnected(unp2->unp_socket); 250 unp_drop(unp2, ECONNRESET); 251 break; 252 } 253 } 254 255 unp_abort(unp) 256 struct unpcb *unp; 257 { 258 259 unp_detach(unp); 260 } 261 262 unp_detach(unp) 263 struct unpcb *unp; 264 { 265 266 if (unp->unp_inode) { 267 irele(unp->unp_inode); 268 unp->unp_inode = 0; 269 } 270 if (unp->unp_conn) 271 unp_disconnect(unp); 272 while (unp->unp_refs) 273 unp_drop(unp->unp_refs, ECONNRESET); 274 soisdisconnected(unp->unp_socket); 275 unp->unp_socket->so_pcb = 0; 276 m_free(dtom(unp)); 277 } 278 279 unp_usrclosed(unp) 280 struct unpcb *unp; 281 { 282 register struct socket *so = unp->unp_socket; 283 284 #ifdef sometimes /* ??? */ 285 soisdisconnected(unp->unp_socket); 286 #endif 287 } 288 289 unp_drop(unp, errno) 290 struct unpcb *unp; 291 int errno; 292 { 293 294 unp->unp_socket->so_error = errno; 295 unp_disconnect(unp); 296 } 297 298 unp_drain() 299 { 300 301 } 302 303 unp_bind(unp, soun) 304 struct unpcb *unp; 305 struct sockaddr_un *soun; 306 { 307 register struct inode *ip; 308 int error; 309 extern schar(); 310 311 u.u_dirp = soun->sun_path; 312 soun->sun_path[sizeof(soun->sun_path)-1] = 0; 313 ip = namei(schar, 1, 1); 314 if (ip) { 315 iput(ip); 316 return (EEXIST); 317 } 318 ip = maknode(IFSOCK | 0777); 319 if (ip == NULL) { 320 error = u.u_error; /* XXX */ 321 u.u_error = 0; /* XXX */ 322 return (error); 323 } 324 ip->i_socket = unp->unp_socket; 325 unp->unp_inode = ip; 326 iunlock(ip); /* but keep reference */ 327 return (0); 328 } 329 330 unp_connect(so, soun) 331 struct socket *so; 332 struct sockaddr_un *soun; 333 { 334 struct inode *ip; 335 int error; 336 337 u.u_dirp = soun->sun_path; 338 soun->sun_path[sizeof(soun->sun_path)-1] = 0; 339 ip = namei(schar, 0, 1); 340 if (ip == 0) { 341 error = u.u_error; 342 u.u_error = 0; 343 return (ENOENT); 344 } 345 error = unp_connectip(so, ip); 346 return (error); 347 } 348 349 unp_connectip(so, ip) 350 struct socket *so; 351 struct inode *ip; 352 { 353 struct unpcb *unp = sotounpcb(so); 354 struct socket *so2, *so3; 355 int error; 356 struct unpcb *unp2; 357 358 if ((ip->i_mode&IFMT) != IFSOCK) { 359 error = ENOTSOCK; 360 goto bad; 361 } 362 so2 = ip->i_socket; 363 if (so2 == 0) { 364 error = ECONNREFUSED; 365 goto bad; 366 } 367 if (so2->so_type != so->so_type) { 368 error = EPROTOTYPE; 369 goto bad; 370 } 371 switch (so->so_type) { 372 373 case SOCK_DGRAM: 374 unp->unp_conn = sotounpcb(so2); 375 unp2 = sotounpcb(so2); 376 unp->unp_nextref = unp2->unp_refs; 377 unp2->unp_refs = unp; 378 break; 379 380 case SOCK_STREAM: 381 if ((so2->so_options&SO_ACCEPTCONN) == 0 || 382 (so3 = sonewconn(so2)) == 0) { 383 error = ECONNREFUSED; 384 goto bad; 385 } 386 unp->unp_conn = sotounpcb(so3); 387 break; 388 389 default: 390 panic("uipc connip"); 391 } 392 soisconnected(unp->unp_conn->unp_socket); 393 soisconnected(so); 394 iput(ip); 395 return (0); 396 bad: 397 iput(ip); 398 return (error); 399 } 400