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