1 /* 2 * Copyright (c) 1982 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.10 (Berkeley) 09/26/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 } 297 *value = m; 298 break; 299 300 case PRCO_SETOPT: 301 switch (name) { 302 int *ok; 303 304 case SO_ALL_PACKETS: 305 mask = NSP_ALL_PACKETS; 306 goto set_head; 307 308 case SO_HEADERS_ON_INPUT: 309 mask = NSP_RAWIN; 310 goto set_head; 311 312 case SO_HEADERS_ON_OUTPUT: 313 mask = NSP_RAWOUT; 314 set_head: 315 if (value && *value) { 316 ok = mtod(*value, int *); 317 if (*ok) 318 nsp->nsp_flags |= mask; 319 else 320 nsp->nsp_flags &= ~mask; 321 } else error = EINVAL; 322 break; 323 324 case SO_DEFAULT_HEADERS: 325 { 326 register struct idp *idp 327 = mtod(*value, struct idp *); 328 nsp->nsp_dpt = idp->idp_pt; 329 } 330 #ifdef NSIP 331 break; 332 333 case SO_NSIP_ROUTE: 334 error = nsip_route(*value); 335 #endif NSIP 336 } 337 if (value && *value) 338 m_freem(*value); 339 break; 340 } 341 return (error); 342 } 343 344 /*ARGSUSED*/ 345 idp_usrreq(so, req, m, nam, rights) 346 struct socket *so; 347 int req; 348 struct mbuf *m, *nam, *rights; 349 { 350 struct nspcb *nsp = sotonspcb(so); 351 int error = 0; 352 353 if (req == PRU_CONTROL) 354 return (ns_control(so, (int)m, (caddr_t)nam, 355 (struct ifnet *)rights)); 356 if (rights && rights->m_len) { 357 error = EINVAL; 358 goto release; 359 } 360 if (nsp == NULL && req != PRU_ATTACH) { 361 error = EINVAL; 362 goto release; 363 } 364 switch (req) { 365 366 case PRU_ATTACH: 367 if (nsp != NULL) { 368 error = EINVAL; 369 break; 370 } 371 error = ns_pcballoc(so, &nspcb); 372 if (error) 373 break; 374 error = soreserve(so, 2048, 2048); 375 if (error) 376 break; 377 break; 378 379 case PRU_DETACH: 380 if (nsp == NULL) { 381 error = ENOTCONN; 382 break; 383 } 384 ns_pcbdetach(nsp); 385 break; 386 387 case PRU_BIND: 388 error = ns_pcbbind(nsp, nam); 389 break; 390 391 case PRU_LISTEN: 392 error = EOPNOTSUPP; 393 break; 394 395 case PRU_CONNECT: 396 if (!ns_nullhost(nsp->nsp_faddr)) { 397 error = EISCONN; 398 break; 399 } 400 error = ns_pcbconnect(nsp, nam); 401 if (error == 0) 402 soisconnected(so); 403 break; 404 405 case PRU_CONNECT2: 406 error = EOPNOTSUPP; 407 break; 408 409 case PRU_ACCEPT: 410 error = EOPNOTSUPP; 411 break; 412 413 case PRU_DISCONNECT: 414 if (ns_nullhost(nsp->nsp_faddr)) { 415 error = ENOTCONN; 416 break; 417 } 418 ns_pcbdisconnect(nsp); 419 soisdisconnected(so); 420 break; 421 422 case PRU_SHUTDOWN: 423 socantsendmore(so); 424 break; 425 426 case PRU_SEND: 427 { 428 struct ns_addr laddr; 429 int s; 430 431 if (nam) { 432 laddr = nsp->nsp_laddr; 433 if (!ns_nullhost(nsp->nsp_faddr)) { 434 error = EISCONN; 435 break; 436 } 437 /* 438 * Must block input while temporarily connected. 439 */ 440 s = splnet(); 441 error = ns_pcbconnect(nsp, nam); 442 if (error) { 443 splx(s); 444 break; 445 } 446 } else { 447 if (ns_nullhost(nsp->nsp_faddr)) { 448 error = ENOTCONN; 449 break; 450 } 451 } 452 error = idp_output(nsp, m); 453 m = NULL; 454 if (nam) { 455 ns_pcbdisconnect(nsp); 456 splx(s); 457 nsp->nsp_laddr.x_host = laddr.x_host; 458 nsp->nsp_laddr.x_port = laddr.x_port; 459 } 460 } 461 break; 462 463 case PRU_ABORT: 464 ns_pcbdetach(nsp); 465 sofree(so); 466 soisdisconnected(so); 467 break; 468 469 case PRU_SOCKADDR: 470 ns_setsockaddr(nsp, nam); 471 break; 472 473 case PRU_PEERADDR: 474 ns_setpeeraddr(nsp, nam); 475 break; 476 477 case PRU_SENSE: 478 /* 479 * stat: don't bother with a blocksize. 480 */ 481 return (0); 482 483 case PRU_SENDOOB: 484 case PRU_FASTTIMO: 485 case PRU_SLOWTIMO: 486 case PRU_PROTORCV: 487 case PRU_PROTOSEND: 488 error = EOPNOTSUPP; 489 break; 490 491 case PRU_CONTROL: 492 case PRU_RCVD: 493 case PRU_RCVOOB: 494 return (EOPNOTSUPP); /* do not free mbuf's */ 495 496 default: 497 panic("idp_usrreq"); 498 } 499 release: 500 if (m != NULL) 501 m_freem(m); 502 return (error); 503 } 504 /*ARGSUSED*/ 505 idp_raw_usrreq(so, req, m, nam, rights) 506 struct socket *so; 507 int req; 508 struct mbuf *m, *nam, *rights; 509 { 510 int error = 0; 511 struct nspcb *nsp = sotonspcb(so); 512 extern struct nspcb nsrawpcb; 513 514 switch (req) { 515 516 case PRU_ATTACH: 517 518 if (!suser() || (nsp != NULL)) { 519 error = EINVAL; 520 break; 521 } 522 error = ns_pcballoc(so, &nsrawpcb); 523 if (error) 524 break; 525 error = soreserve(so, 2048, 2048); 526 if (error) 527 break; 528 nsp = sotonspcb(so); 529 nsp->nsp_faddr.x_host = ns_broadhost; 530 nsp->nsp_flags = NSP_RAWIN | NSP_RAWOUT; 531 break; 532 default: 533 error = idp_usrreq(so, req, m, nam, rights); 534 } 535 return (error); 536 } 537 538