1 /* 2 * Copyright (c) 1984,1985 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 6.11 (Berkeley) 10/30/85 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_netof(idp->idp_sna)==0 && 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); 166 m->m_len = sizeof (struct idp); 167 m->m_next = m0; 168 idp = mtod(m, struct idp *); 169 idp->idp_tc = 0; 170 idp->idp_pt = nsp->nsp_dpt; 171 idp->idp_sna = nsp->nsp_laddr; 172 idp->idp_dna = nsp->nsp_faddr; 173 len += sizeof (struct idp); 174 } 175 176 idp->idp_len = htons((u_short)len); 177 178 if (idpcksum) { 179 idp->idp_sum = 0; 180 len = ((len - 1) | 1) + 1; 181 idp->idp_sum = ns_cksum(m, len); 182 } else 183 idp->idp_sum = 0xffff; 184 185 /* 186 * Output datagram. 187 */ 188 so = nsp->nsp_socket; 189 if (so->so_options & SO_DONTROUTE) 190 return (ns_output(m, (struct route *)0, 191 (so->so_options & SO_BROADCAST) | NS_ROUTETOIF)); 192 /* 193 * Use cached route for previous datagram if 194 * possible. If the previous net was the same 195 * and the interface was a broadcast medium, or 196 * if the previous destination was identical, 197 * then we are ok. 198 * 199 * NB: We don't handle broadcasts because that 200 * would require 3 subroutine calls. 201 */ 202 ro = &nsp->nsp_route; 203 #ifdef ancient_history 204 /* 205 * I think that this will all be handled in ns_pcbconnect! 206 */ 207 if (ro->ro_rt) { 208 if(ns_neteq(nsp->nsp_lastdst, idp->idp_dna)) { 209 /* 210 * This assumes we have no GH type routes 211 */ 212 if (ro->ro_rt->rt_flags & RTF_HOST) { 213 if (!ns_hosteq(nsp->nsp_lastdst, idp->idp_dna)) 214 goto re_route; 215 216 } 217 if ((ro->ro_rt->rt_flags & RTF_GATEWAY) == 0) { 218 register struct ns_addr *dst = 219 &satons_addr(ro->ro_dst); 220 dst->x_host = idp->idp_dna.x_host; 221 } 222 /* 223 * Otherwise, we go through the same gateway 224 * and dst is already set up. 225 */ 226 } else { 227 re_route: 228 RTFREE(ro->ro_rt); 229 ro->ro_rt = (struct rtentry *)0; 230 } 231 } 232 nsp->nsp_lastdst = idp->idp_dna; 233 #endif ancient_history 234 if (noIdpRoute) ro = 0; 235 return (ns_output(m, ro, so->so_options & SO_BROADCAST)); 236 } 237 /* ARGSUSED */ 238 idp_ctloutput(req, so, level, name, value) 239 int req, level; 240 struct socket *so; 241 int name; 242 struct mbuf **value; 243 { 244 register struct mbuf *m; 245 struct nspcb *nsp = sotonspcb(so); 246 int mask, error = 0; 247 extern long ns_pexseq; 248 249 if (nsp == NULL) 250 return (EINVAL); 251 252 switch (req) { 253 254 case PRCO_GETOPT: 255 if (value==NULL) 256 return (EINVAL); 257 m = m_get(M_DONTWAIT, MT_DATA); 258 if (m==NULL) 259 return (ENOBUFS); 260 switch (name) { 261 262 case SO_ALL_PACKETS: 263 mask = NSP_ALL_PACKETS; 264 goto get_flags; 265 266 case SO_HEADERS_ON_INPUT: 267 mask = NSP_RAWIN; 268 goto get_flags; 269 270 case SO_HEADERS_ON_OUTPUT: 271 mask = NSP_RAWOUT; 272 get_flags: 273 m->m_len = sizeof(short); 274 m->m_off = MMAXOFF - sizeof(short); 275 *mtod(m, short *) = nsp->nsp_flags & mask; 276 break; 277 278 case SO_DEFAULT_HEADERS: 279 m->m_len = sizeof(struct idp); 280 m->m_off = MMAXOFF - sizeof(struct idp); 281 { 282 register struct idp *idp = mtod(m, struct idp *); 283 idp->idp_len = 0; 284 idp->idp_sum = 0; 285 idp->idp_tc = 0; 286 idp->idp_pt = nsp->nsp_dpt; 287 idp->idp_dna = nsp->nsp_faddr; 288 idp->idp_sna = nsp->nsp_laddr; 289 } 290 break; 291 292 case SO_SEQNO: 293 m->m_len = sizeof(long); 294 m->m_off = MMAXOFF - sizeof(long); 295 *mtod(m, long *) = ns_pexseq++; 296 break; 297 298 default: 299 error = EINVAL; 300 } 301 *value = m; 302 break; 303 304 case PRCO_SETOPT: 305 switch (name) { 306 int *ok; 307 308 case SO_ALL_PACKETS: 309 mask = NSP_ALL_PACKETS; 310 goto set_head; 311 312 case SO_HEADERS_ON_INPUT: 313 mask = NSP_RAWIN; 314 goto set_head; 315 316 case SO_HEADERS_ON_OUTPUT: 317 mask = NSP_RAWOUT; 318 set_head: 319 if (value && *value) { 320 ok = mtod(*value, int *); 321 if (*ok) 322 nsp->nsp_flags |= mask; 323 else 324 nsp->nsp_flags &= ~mask; 325 } else error = EINVAL; 326 break; 327 328 case SO_DEFAULT_HEADERS: 329 { 330 register struct idp *idp 331 = mtod(*value, struct idp *); 332 nsp->nsp_dpt = idp->idp_pt; 333 } 334 break; 335 #ifdef NSIP 336 337 case SO_NSIP_ROUTE: 338 error = nsip_route(*value); 339 break; 340 #endif NSIP 341 default: 342 error = EINVAL; 343 } 344 if (value && *value) 345 m_freem(*value); 346 break; 347 } 348 return (error); 349 } 350 351 /*ARGSUSED*/ 352 idp_usrreq(so, req, m, nam, rights) 353 struct socket *so; 354 int req; 355 struct mbuf *m, *nam, *rights; 356 { 357 struct nspcb *nsp = sotonspcb(so); 358 int error = 0; 359 360 if (req == PRU_CONTROL) 361 return (ns_control(so, (int)m, (caddr_t)nam, 362 (struct ifnet *)rights)); 363 if (rights && rights->m_len) { 364 error = EINVAL; 365 goto release; 366 } 367 if (nsp == NULL && req != PRU_ATTACH) { 368 error = EINVAL; 369 goto release; 370 } 371 switch (req) { 372 373 case PRU_ATTACH: 374 if (nsp != NULL) { 375 error = EINVAL; 376 break; 377 } 378 error = ns_pcballoc(so, &nspcb); 379 if (error) 380 break; 381 error = soreserve(so, 2048, 2048); 382 if (error) 383 break; 384 break; 385 386 case PRU_DETACH: 387 if (nsp == NULL) { 388 error = ENOTCONN; 389 break; 390 } 391 ns_pcbdetach(nsp); 392 break; 393 394 case PRU_BIND: 395 error = ns_pcbbind(nsp, nam); 396 break; 397 398 case PRU_LISTEN: 399 error = EOPNOTSUPP; 400 break; 401 402 case PRU_CONNECT: 403 if (!ns_nullhost(nsp->nsp_faddr)) { 404 error = EISCONN; 405 break; 406 } 407 error = ns_pcbconnect(nsp, nam); 408 if (error == 0) 409 soisconnected(so); 410 break; 411 412 case PRU_CONNECT2: 413 error = EOPNOTSUPP; 414 break; 415 416 case PRU_ACCEPT: 417 error = EOPNOTSUPP; 418 break; 419 420 case PRU_DISCONNECT: 421 if (ns_nullhost(nsp->nsp_faddr)) { 422 error = ENOTCONN; 423 break; 424 } 425 ns_pcbdisconnect(nsp); 426 soisdisconnected(so); 427 break; 428 429 case PRU_SHUTDOWN: 430 socantsendmore(so); 431 break; 432 433 case PRU_SEND: 434 { 435 struct ns_addr laddr; 436 int s; 437 438 if (nam) { 439 laddr = nsp->nsp_laddr; 440 if (!ns_nullhost(nsp->nsp_faddr)) { 441 error = EISCONN; 442 break; 443 } 444 /* 445 * Must block input while temporarily connected. 446 */ 447 s = splnet(); 448 error = ns_pcbconnect(nsp, nam); 449 if (error) { 450 splx(s); 451 break; 452 } 453 } else { 454 if (ns_nullhost(nsp->nsp_faddr)) { 455 error = ENOTCONN; 456 break; 457 } 458 } 459 error = idp_output(nsp, m); 460 m = NULL; 461 if (nam) { 462 ns_pcbdisconnect(nsp); 463 splx(s); 464 nsp->nsp_laddr.x_host = laddr.x_host; 465 nsp->nsp_laddr.x_port = laddr.x_port; 466 } 467 } 468 break; 469 470 case PRU_ABORT: 471 ns_pcbdetach(nsp); 472 sofree(so); 473 soisdisconnected(so); 474 break; 475 476 case PRU_SOCKADDR: 477 ns_setsockaddr(nsp, nam); 478 break; 479 480 case PRU_PEERADDR: 481 ns_setpeeraddr(nsp, nam); 482 break; 483 484 case PRU_SENSE: 485 /* 486 * stat: don't bother with a blocksize. 487 */ 488 return (0); 489 490 case PRU_SENDOOB: 491 case PRU_FASTTIMO: 492 case PRU_SLOWTIMO: 493 case PRU_PROTORCV: 494 case PRU_PROTOSEND: 495 error = EOPNOTSUPP; 496 break; 497 498 case PRU_CONTROL: 499 case PRU_RCVD: 500 case PRU_RCVOOB: 501 return (EOPNOTSUPP); /* do not free mbuf's */ 502 503 default: 504 panic("idp_usrreq"); 505 } 506 release: 507 if (m != NULL) 508 m_freem(m); 509 return (error); 510 } 511 /*ARGSUSED*/ 512 idp_raw_usrreq(so, req, m, nam, rights) 513 struct socket *so; 514 int req; 515 struct mbuf *m, *nam, *rights; 516 { 517 int error = 0; 518 struct nspcb *nsp = sotonspcb(so); 519 extern struct nspcb nsrawpcb; 520 521 switch (req) { 522 523 case PRU_ATTACH: 524 525 if (!suser() || (nsp != NULL)) { 526 error = EINVAL; 527 break; 528 } 529 error = ns_pcballoc(so, &nsrawpcb); 530 if (error) 531 break; 532 error = soreserve(so, 2048, 2048); 533 if (error) 534 break; 535 nsp = sotonspcb(so); 536 nsp->nsp_faddr.x_host = ns_broadhost; 537 nsp->nsp_flags = NSP_RAWIN | NSP_RAWOUT; 538 break; 539 default: 540 error = idp_usrreq(so, req, m, nam, rights); 541 } 542 return (error); 543 } 544 545