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