1 /* 2 * Copyright (c) 1984, 1985, 1986, 1987 Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 * 7 * @(#)idp_usrreq.c 7.13 (Berkeley) 05/25/93 8 */ 9 10 #include <sys/param.h> 11 #include <sys/malloc.h> 12 #include <sys/mbuf.h> 13 #include <sys/protosw.h> 14 #include <sys/socket.h> 15 #include <sys/socketvar.h> 16 #include <sys/errno.h> 17 #include <sys/stat.h> 18 19 #include <net/if.h> 20 #include <net/route.h> 21 22 #include <netns/ns.h> 23 #include <netns/ns_pcb.h> 24 #include <netns/ns_if.h> 25 #include <netns/idp.h> 26 #include <netns/idp_var.h> 27 #include <netns/ns_error.h> 28 29 /* 30 * IDP protocol implementation. 31 */ 32 33 struct sockaddr_ns idp_ns = { sizeof(idp_ns), AF_NS }; 34 35 /* 36 * This may also be called for raw listeners. 37 */ 38 idp_input(m, nsp) 39 struct mbuf *m; 40 register struct nspcb *nsp; 41 { 42 register struct idp *idp = mtod(m, struct idp *); 43 struct ifnet *ifp = m->m_pkthdr.rcvif; 44 45 if (nsp==0) 46 panic("No nspcb"); 47 /* 48 * Construct sockaddr format source address. 49 * Stuff source address and datagram in user buffer. 50 */ 51 idp_ns.sns_addr = idp->idp_sna; 52 if (ns_neteqnn(idp->idp_sna.x_net, ns_zeronet) && ifp) { 53 register struct ifaddr *ifa; 54 55 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { 56 if (ifa->ifa_addr->sa_family == AF_NS) { 57 idp_ns.sns_addr.x_net = 58 IA_SNS(ifa)->sns_addr.x_net; 59 break; 60 } 61 } 62 } 63 nsp->nsp_rpt = idp->idp_pt; 64 if ( ! (nsp->nsp_flags & NSP_RAWIN) ) { 65 m->m_len -= sizeof (struct idp); 66 m->m_pkthdr.len -= sizeof (struct idp); 67 m->m_data += sizeof (struct idp); 68 } 69 if (sbappendaddr(&nsp->nsp_socket->so_rcv, (struct sockaddr *)&idp_ns, 70 m, (struct mbuf *)0) == 0) 71 goto bad; 72 sorwakeup(nsp->nsp_socket); 73 return; 74 bad: 75 m_freem(m); 76 } 77 78 idp_abort(nsp) 79 struct nspcb *nsp; 80 { 81 struct socket *so = nsp->nsp_socket; 82 83 ns_pcbdisconnect(nsp); 84 soisdisconnected(so); 85 } 86 /* 87 * Drop connection, reporting 88 * the specified error. 89 */ 90 struct nspcb * 91 idp_drop(nsp, errno) 92 register struct nspcb *nsp; 93 int errno; 94 { 95 struct socket *so = nsp->nsp_socket; 96 97 /* 98 * someday, in the xerox world 99 * we will generate error protocol packets 100 * announcing that the socket has gone away. 101 */ 102 /*if (TCPS_HAVERCVDSYN(tp->t_state)) { 103 tp->t_state = TCPS_CLOSED; 104 (void) tcp_output(tp); 105 }*/ 106 so->so_error = errno; 107 ns_pcbdisconnect(nsp); 108 soisdisconnected(so); 109 } 110 111 int noIdpRoute; 112 idp_output(nsp, m0) 113 struct nspcb *nsp; 114 struct mbuf *m0; 115 { 116 register struct mbuf *m; 117 register struct idp *idp; 118 register struct socket *so; 119 register int len = 0; 120 register struct route *ro; 121 struct mbuf *mprev; 122 extern int idpcksum; 123 124 /* 125 * Calculate data length. 126 */ 127 for (m = m0; m; m = m->m_next) { 128 mprev = m; 129 len += m->m_len; 130 } 131 /* 132 * Make sure packet is actually of even length. 133 */ 134 135 if (len & 1) { 136 m = mprev; 137 if ((m->m_flags & M_EXT) == 0 && 138 (m->m_len + m->m_data < &m->m_dat[MLEN])) { 139 m->m_len++; 140 } else { 141 struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA); 142 143 if (m1 == 0) { 144 m_freem(m0); 145 return (ENOBUFS); 146 } 147 m1->m_len = 1; 148 * mtod(m1, char *) = 0; 149 m->m_next = m1; 150 } 151 m0->m_pkthdr.len++; 152 } 153 154 /* 155 * Fill in mbuf with extended IDP header 156 * and addresses and length put into network format. 157 */ 158 m = m0; 159 if (nsp->nsp_flags & NSP_RAWOUT) { 160 idp = mtod(m, struct idp *); 161 } else { 162 M_PREPEND(m, sizeof (struct idp), M_DONTWAIT); 163 if (m == 0) 164 return (ENOBUFS); 165 idp = mtod(m, struct idp *); 166 idp->idp_tc = 0; 167 idp->idp_pt = nsp->nsp_dpt; 168 idp->idp_sna = nsp->nsp_laddr; 169 idp->idp_dna = nsp->nsp_faddr; 170 len += sizeof (struct idp); 171 } 172 173 idp->idp_len = htons((u_short)len); 174 175 if (idpcksum) { 176 idp->idp_sum = 0; 177 len = ((len - 1) | 1) + 1; 178 idp->idp_sum = ns_cksum(m, len); 179 } else 180 idp->idp_sum = 0xffff; 181 182 /* 183 * Output datagram. 184 */ 185 so = nsp->nsp_socket; 186 if (so->so_options & SO_DONTROUTE) 187 return (ns_output(m, (struct route *)0, 188 (so->so_options & SO_BROADCAST) | NS_ROUTETOIF)); 189 /* 190 * Use cached route for previous datagram if 191 * possible. If the previous net was the same 192 * and the interface was a broadcast medium, or 193 * if the previous destination was identical, 194 * then we are ok. 195 * 196 * NB: We don't handle broadcasts because that 197 * would require 3 subroutine calls. 198 */ 199 ro = &nsp->nsp_route; 200 #ifdef ancient_history 201 /* 202 * I think that this will all be handled in ns_pcbconnect! 203 */ 204 if (ro->ro_rt) { 205 if(ns_neteq(nsp->nsp_lastdst, idp->idp_dna)) { 206 /* 207 * This assumes we have no GH type routes 208 */ 209 if (ro->ro_rt->rt_flags & RTF_HOST) { 210 if (!ns_hosteq(nsp->nsp_lastdst, idp->idp_dna)) 211 goto re_route; 212 213 } 214 if ((ro->ro_rt->rt_flags & RTF_GATEWAY) == 0) { 215 register struct ns_addr *dst = 216 &satons_addr(ro->ro_dst); 217 dst->x_host = idp->idp_dna.x_host; 218 } 219 /* 220 * Otherwise, we go through the same gateway 221 * and dst is already set up. 222 */ 223 } else { 224 re_route: 225 RTFREE(ro->ro_rt); 226 ro->ro_rt = (struct rtentry *)0; 227 } 228 } 229 nsp->nsp_lastdst = idp->idp_dna; 230 #endif /* ancient_history */ 231 if (noIdpRoute) ro = 0; 232 return (ns_output(m, ro, so->so_options & SO_BROADCAST)); 233 } 234 /* ARGSUSED */ 235 idp_ctloutput(req, so, level, name, value) 236 int req, level; 237 struct socket *so; 238 int name; 239 struct mbuf **value; 240 { 241 register struct mbuf *m; 242 struct nspcb *nsp = sotonspcb(so); 243 int mask, error = 0; 244 extern long ns_pexseq; 245 246 if (nsp == NULL) 247 return (EINVAL); 248 249 switch (req) { 250 251 case PRCO_GETOPT: 252 if (value==NULL) 253 return (EINVAL); 254 m = m_get(M_DONTWAIT, MT_DATA); 255 if (m==NULL) 256 return (ENOBUFS); 257 switch (name) { 258 259 case SO_ALL_PACKETS: 260 mask = NSP_ALL_PACKETS; 261 goto get_flags; 262 263 case SO_HEADERS_ON_INPUT: 264 mask = NSP_RAWIN; 265 goto get_flags; 266 267 case SO_HEADERS_ON_OUTPUT: 268 mask = NSP_RAWOUT; 269 get_flags: 270 m->m_len = sizeof(short); 271 *mtod(m, short *) = nsp->nsp_flags & mask; 272 break; 273 274 case SO_DEFAULT_HEADERS: 275 m->m_len = sizeof(struct idp); 276 { 277 register struct idp *idp = mtod(m, struct idp *); 278 idp->idp_len = 0; 279 idp->idp_sum = 0; 280 idp->idp_tc = 0; 281 idp->idp_pt = nsp->nsp_dpt; 282 idp->idp_dna = nsp->nsp_faddr; 283 idp->idp_sna = nsp->nsp_laddr; 284 } 285 break; 286 287 case SO_SEQNO: 288 m->m_len = sizeof(long); 289 *mtod(m, long *) = ns_pexseq++; 290 break; 291 292 default: 293 error = EINVAL; 294 } 295 *value = m; 296 break; 297 298 case PRCO_SETOPT: 299 switch (name) { 300 int *ok; 301 302 case SO_ALL_PACKETS: 303 mask = NSP_ALL_PACKETS; 304 goto set_head; 305 306 case SO_HEADERS_ON_INPUT: 307 mask = NSP_RAWIN; 308 goto set_head; 309 310 case SO_HEADERS_ON_OUTPUT: 311 mask = NSP_RAWOUT; 312 set_head: 313 if (value && *value) { 314 ok = mtod(*value, int *); 315 if (*ok) 316 nsp->nsp_flags |= mask; 317 else 318 nsp->nsp_flags &= ~mask; 319 } else error = EINVAL; 320 break; 321 322 case SO_DEFAULT_HEADERS: 323 { 324 register struct idp *idp 325 = mtod(*value, struct idp *); 326 nsp->nsp_dpt = idp->idp_pt; 327 } 328 break; 329 #ifdef NSIP 330 331 case SO_NSIP_ROUTE: 332 error = nsip_route(*value); 333 break; 334 #endif /* NSIP */ 335 default: 336 error = EINVAL; 337 } 338 if (value && *value) 339 m_freem(*value); 340 break; 341 } 342 return (error); 343 } 344 345 /*ARGSUSED*/ 346 idp_usrreq(so, req, m, nam, control) 347 struct socket *so; 348 int req; 349 struct mbuf *m, *nam, *control; 350 { 351 struct nspcb *nsp = sotonspcb(so); 352 int error = 0; 353 354 if (req == PRU_CONTROL) 355 return (ns_control(so, (int)m, (caddr_t)nam, 356 (struct ifnet *)control)); 357 if (control && control->m_len) { 358 error = EINVAL; 359 goto release; 360 } 361 if (nsp == NULL && req != PRU_ATTACH) { 362 error = EINVAL; 363 goto release; 364 } 365 switch (req) { 366 367 case PRU_ATTACH: 368 if (nsp != NULL) { 369 error = EINVAL; 370 break; 371 } 372 error = ns_pcballoc(so, &nspcb); 373 if (error) 374 break; 375 error = soreserve(so, (u_long) 2048, (u_long) 2048); 376 if (error) 377 break; 378 break; 379 380 case PRU_DETACH: 381 if (nsp == NULL) { 382 error = ENOTCONN; 383 break; 384 } 385 ns_pcbdetach(nsp); 386 break; 387 388 case PRU_BIND: 389 error = ns_pcbbind(nsp, nam); 390 break; 391 392 case PRU_LISTEN: 393 error = EOPNOTSUPP; 394 break; 395 396 case PRU_CONNECT: 397 if (!ns_nullhost(nsp->nsp_faddr)) { 398 error = EISCONN; 399 break; 400 } 401 error = ns_pcbconnect(nsp, nam); 402 if (error == 0) 403 soisconnected(so); 404 break; 405 406 case PRU_CONNECT2: 407 error = EOPNOTSUPP; 408 break; 409 410 case PRU_ACCEPT: 411 error = EOPNOTSUPP; 412 break; 413 414 case PRU_DISCONNECT: 415 if (ns_nullhost(nsp->nsp_faddr)) { 416 error = ENOTCONN; 417 break; 418 } 419 ns_pcbdisconnect(nsp); 420 soisdisconnected(so); 421 break; 422 423 case PRU_SHUTDOWN: 424 socantsendmore(so); 425 break; 426 427 case PRU_SEND: 428 { 429 struct ns_addr laddr; 430 int s; 431 432 if (nam) { 433 laddr = nsp->nsp_laddr; 434 if (!ns_nullhost(nsp->nsp_faddr)) { 435 error = EISCONN; 436 break; 437 } 438 /* 439 * Must block input while temporarily connected. 440 */ 441 s = splnet(); 442 error = ns_pcbconnect(nsp, nam); 443 if (error) { 444 splx(s); 445 break; 446 } 447 } else { 448 if (ns_nullhost(nsp->nsp_faddr)) { 449 error = ENOTCONN; 450 break; 451 } 452 } 453 error = idp_output(nsp, m); 454 m = NULL; 455 if (nam) { 456 ns_pcbdisconnect(nsp); 457 splx(s); 458 nsp->nsp_laddr.x_host = laddr.x_host; 459 nsp->nsp_laddr.x_port = laddr.x_port; 460 } 461 } 462 break; 463 464 case PRU_ABORT: 465 ns_pcbdetach(nsp); 466 sofree(so); 467 soisdisconnected(so); 468 break; 469 470 case PRU_SOCKADDR: 471 ns_setsockaddr(nsp, nam); 472 break; 473 474 case PRU_PEERADDR: 475 ns_setpeeraddr(nsp, nam); 476 break; 477 478 case PRU_SENSE: 479 /* 480 * stat: don't bother with a blocksize. 481 */ 482 return (0); 483 484 case PRU_SENDOOB: 485 case PRU_FASTTIMO: 486 case PRU_SLOWTIMO: 487 case PRU_PROTORCV: 488 case PRU_PROTOSEND: 489 error = EOPNOTSUPP; 490 break; 491 492 case PRU_CONTROL: 493 case PRU_RCVD: 494 case PRU_RCVOOB: 495 return (EOPNOTSUPP); /* do not free mbuf's */ 496 497 default: 498 panic("idp_usrreq"); 499 } 500 release: 501 if (control != NULL) 502 m_freem(control); 503 if (m != NULL) 504 m_freem(m); 505 return (error); 506 } 507 /*ARGSUSED*/ 508 idp_raw_usrreq(so, req, m, nam, control) 509 struct socket *so; 510 int req; 511 struct mbuf *m, *nam, *control; 512 { 513 int error = 0; 514 struct nspcb *nsp = sotonspcb(so); 515 extern struct nspcb nsrawpcb; 516 517 switch (req) { 518 519 case PRU_ATTACH: 520 521 if (!(so->so_state & SS_PRIV) || (nsp != NULL)) { 522 error = EINVAL; 523 break; 524 } 525 error = ns_pcballoc(so, &nsrawpcb); 526 if (error) 527 break; 528 error = soreserve(so, (u_long) 2048, (u_long) 2048); 529 if (error) 530 break; 531 nsp = sotonspcb(so); 532 nsp->nsp_faddr.x_host = ns_broadhost; 533 nsp->nsp_flags = NSP_RAWIN | NSP_RAWOUT; 534 break; 535 default: 536 error = idp_usrreq(so, req, m, nam, control); 537 } 538 return (error); 539 } 540 541