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