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