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