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