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.8 (Berkeley) 09/06/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) { 53 register struct ifaddr *ia; 54 55 for (ia = ifp->if_addrlist; 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 idp_output(nsp, m0) 111 struct nspcb *nsp; 112 struct mbuf *m0; 113 { 114 register struct mbuf *m; 115 register struct idp *idp; 116 register struct socket *so; 117 register int len = 0; 118 register struct route *ro; 119 struct mbuf *mprev; 120 extern int idpcksum; 121 122 /* 123 * Calculate data length. 124 */ 125 for (m = m0; m; m = m->m_next) { 126 mprev = m; 127 len += m->m_len; 128 } 129 /* 130 * Make sure packet is actually of even length. 131 */ 132 133 if (len & 1) { 134 m = mprev; 135 if (m->m_len + m->m_off < MMAXOFF) { 136 m->m_len++; 137 } else { 138 struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA); 139 140 if (m1 == 0) { 141 m_freem(m0); 142 return (ENOBUFS); 143 } 144 m1->m_len = 1; 145 m1->m_off = MMAXOFF - 1; 146 * mtod(m1, char *) = 0; 147 m->m_next = m1; 148 } 149 } 150 151 /* 152 * Fill in mbuf with extended IDP header 153 * and addresses and length put into network format. 154 */ 155 if (nsp->nsp_flags & NSP_RAWOUT) { 156 m = m0; 157 idp = mtod(m, struct idp *); 158 } else { 159 m = m_get(M_DONTWAIT, MT_HEADER); 160 if (m == 0) { 161 m_freem(m0); 162 return (ENOBUFS); 163 } 164 m->m_off = MMAXOFF - sizeof (struct idp); 165 m->m_len = sizeof (struct idp); 166 m->m_next = m0; 167 idp = mtod(m, struct idp *); 168 idp->idp_tc = 0; 169 idp->idp_pt = nsp->nsp_dpt; 170 idp->idp_sna = nsp->nsp_laddr; 171 idp->idp_dna = nsp->nsp_faddr; 172 len += sizeof (struct idp); 173 } 174 175 idp->idp_len = htons((u_short)len); 176 177 if (idpcksum) { 178 idp->idp_sum = 0; 179 len = ((len - 1) | 1) + 1; 180 idp->idp_sum = ns_cksum(m, len); 181 } else 182 idp->idp_sum = 0xffff; 183 184 /* 185 * Output datagram. 186 */ 187 so = nsp->nsp_socket; 188 if (so->so_options & SO_DONTROUTE) 189 return (ns_output(m, (struct route *)0, 190 (so->so_options & SO_BROADCAST) | NS_ROUTETOIF)); 191 /* 192 * Use cached route for previous datagram if 193 * this is also to the same destination. 194 * 195 * NB: We don't handle broadcasts because that 196 * would require 3 subroutine calls. 197 */ 198 ro = &nsp->nsp_route; 199 if (ro->ro_rt && 200 ((*(long *)&nsp->nsp_lastnet)!=ns_netof(idp->idp_dna)) && 201 !(ns_hosteq(satons_addr(ro->ro_dst), idp->idp_dna))) { 202 RTFREE(ro->ro_rt); 203 ro->ro_rt = (struct rtentry *)0; 204 nsp->nsp_lastnet = idp->idp_dna.x_net; 205 } 206 return (ns_output(m, ro, so->so_options & SO_BROADCAST)); 207 } 208 /* ARGSUSED */ 209 idp_ctloutput(req, so, level, name, value) 210 int req, level; 211 struct socket *so; 212 int name; 213 struct mbuf **value; 214 { 215 register struct mbuf *m; 216 struct nspcb *nsp = sotonspcb(so); 217 int mask, error = 0; 218 extern long ns_pexseq; 219 220 if (nsp == NULL) 221 return (EINVAL); 222 223 switch (req) { 224 225 case PRCO_GETOPT: 226 if (value==NULL) 227 return (EINVAL); 228 m = m_get(M_DONTWAIT, MT_DATA); 229 if (m==NULL) 230 return (ENOBUFS); 231 switch (name) { 232 233 case SO_ALL_PACKETS: 234 mask = NSP_ALL_PACKETS; 235 goto get_flags; 236 237 case SO_HEADERS_ON_INPUT: 238 mask = NSP_RAWIN; 239 goto get_flags; 240 241 case SO_HEADERS_ON_OUTPUT: 242 mask = NSP_RAWOUT; 243 get_flags: 244 m->m_len = sizeof(short); 245 m->m_off = MMAXOFF - sizeof(short); 246 *mtod(m, short *) = nsp->nsp_flags & mask; 247 break; 248 249 case SO_DEFAULT_HEADERS: 250 m->m_len = sizeof(struct idp); 251 m->m_off = MMAXOFF - sizeof(struct idp); 252 { 253 register struct idp *idp = mtod(m, struct idp *); 254 idp->idp_len = 0; 255 idp->idp_sum = 0; 256 idp->idp_tc = 0; 257 idp->idp_pt = nsp->nsp_dpt; 258 idp->idp_dna = nsp->nsp_faddr; 259 idp->idp_sna = nsp->nsp_laddr; 260 } 261 break; 262 263 case SO_SEQNO: 264 m->m_len = sizeof(long); 265 m->m_off = MMAXOFF - sizeof(long); 266 *mtod(m, long *) = ns_pexseq++; 267 } 268 *value = m; 269 break; 270 271 case PRCO_SETOPT: 272 switch (name) { 273 int *ok; 274 275 case SO_ALL_PACKETS: 276 mask = NSP_ALL_PACKETS; 277 goto set_head; 278 279 case SO_HEADERS_ON_INPUT: 280 mask = NSP_RAWIN; 281 goto set_head; 282 283 case SO_HEADERS_ON_OUTPUT: 284 mask = NSP_RAWOUT; 285 set_head: 286 if (value && *value) { 287 ok = mtod(*value, int *); 288 if (*ok) 289 nsp->nsp_flags |= mask; 290 else 291 nsp->nsp_flags &= ~mask; 292 } else error = EINVAL; 293 break; 294 295 case SO_DEFAULT_HEADERS: 296 { 297 register struct idp *idp 298 = mtod(*value, struct idp *); 299 nsp->nsp_dpt = idp->idp_pt; 300 } 301 #ifdef NSIP 302 break; 303 304 case SO_NSIP_ROUTE: 305 error = nsip_route(*value); 306 #endif NSIP 307 } 308 if (value && *value) 309 m_freem(*value); 310 break; 311 } 312 return (error); 313 } 314 315 /*ARGSUSED*/ 316 idp_usrreq(so, req, m, nam, rights) 317 struct socket *so; 318 int req; 319 struct mbuf *m, *nam, *rights; 320 { 321 struct nspcb *nsp = sotonspcb(so); 322 int error = 0; 323 324 if (req == PRU_CONTROL) 325 return (ns_control(so, (int)m, (caddr_t)nam, 326 (struct ifnet *)rights)); 327 if (rights && rights->m_len) { 328 error = EINVAL; 329 goto release; 330 } 331 if (nsp == NULL && req != PRU_ATTACH) { 332 error = EINVAL; 333 goto release; 334 } 335 switch (req) { 336 337 case PRU_ATTACH: 338 if (nsp != NULL) { 339 error = EINVAL; 340 break; 341 } 342 error = ns_pcballoc(so, &nspcb); 343 if (error) 344 break; 345 error = soreserve(so, 2048, 2048); 346 if (error) 347 break; 348 break; 349 350 case PRU_DETACH: 351 if (nsp == NULL) { 352 error = ENOTCONN; 353 break; 354 } 355 ns_pcbdetach(nsp); 356 break; 357 358 case PRU_BIND: 359 error = ns_pcbbind(nsp, nam); 360 break; 361 362 case PRU_LISTEN: 363 error = EOPNOTSUPP; 364 break; 365 366 case PRU_CONNECT: 367 if (!ns_nullhost(nsp->nsp_faddr)) { 368 error = EISCONN; 369 break; 370 } 371 error = ns_pcbconnect(nsp, nam); 372 if (error == 0) 373 soisconnected(so); 374 break; 375 376 case PRU_CONNECT2: 377 error = EOPNOTSUPP; 378 break; 379 380 case PRU_ACCEPT: 381 error = EOPNOTSUPP; 382 break; 383 384 case PRU_DISCONNECT: 385 if (ns_nullhost(nsp->nsp_faddr)) { 386 error = ENOTCONN; 387 break; 388 } 389 ns_pcbdisconnect(nsp); 390 soisdisconnected(so); 391 break; 392 393 case PRU_SHUTDOWN: 394 socantsendmore(so); 395 break; 396 397 case PRU_SEND: 398 { 399 struct ns_addr laddr; 400 int s; 401 402 if (nam) { 403 laddr = nsp->nsp_laddr; 404 if (!ns_nullhost(nsp->nsp_faddr)) { 405 error = EISCONN; 406 break; 407 } 408 /* 409 * Must block input while temporarily connected. 410 */ 411 s = splnet(); 412 error = ns_pcbconnect(nsp, nam); 413 if (error) { 414 splx(s); 415 break; 416 } 417 } else { 418 if (ns_nullhost(nsp->nsp_faddr)) { 419 error = ENOTCONN; 420 break; 421 } 422 } 423 error = idp_output(nsp, m); 424 m = NULL; 425 if (nam) { 426 ns_pcbdisconnect(nsp); 427 splx(s); 428 nsp->nsp_laddr.x_host = laddr.x_host; 429 nsp->nsp_laddr.x_port = laddr.x_port; 430 } 431 } 432 break; 433 434 case PRU_ABORT: 435 ns_pcbdetach(nsp); 436 sofree(so); 437 soisdisconnected(so); 438 break; 439 440 case PRU_SOCKADDR: 441 ns_setsockaddr(nsp, nam); 442 break; 443 444 case PRU_PEERADDR: 445 ns_setpeeraddr(nsp, nam); 446 break; 447 448 case PRU_SENSE: 449 /* 450 * stat: don't bother with a blocksize. 451 */ 452 return (0); 453 454 case PRU_SENDOOB: 455 case PRU_FASTTIMO: 456 case PRU_SLOWTIMO: 457 case PRU_PROTORCV: 458 case PRU_PROTOSEND: 459 error = EOPNOTSUPP; 460 break; 461 462 case PRU_CONTROL: 463 case PRU_RCVD: 464 case PRU_RCVOOB: 465 return (EOPNOTSUPP); /* do not free mbuf's */ 466 467 default: 468 panic("idp_usrreq"); 469 } 470 release: 471 if (m != NULL) 472 m_freem(m); 473 return (error); 474 } 475 /*ARGSUSED*/ 476 idp_raw_usrreq(so, req, m, nam, rights) 477 struct socket *so; 478 int req; 479 struct mbuf *m, *nam, *rights; 480 { 481 int error = 0; 482 struct nspcb *nsp = sotonspcb(so); 483 extern struct nspcb nsrawpcb; 484 485 switch (req) { 486 487 case PRU_ATTACH: 488 489 if (!suser() || (nsp != NULL)) { 490 error = EINVAL; 491 break; 492 } 493 error = ns_pcballoc(so, &nsrawpcb); 494 if (error) 495 break; 496 error = soreserve(so, 2048, 2048); 497 if (error) 498 break; 499 nsp = sotonspcb(so); 500 nsp->nsp_faddr.x_host = ns_broadhost; 501 nsp->nsp_flags = NSP_RAWIN | NSP_RAWOUT; 502 break; 503 default: 504 error = idp_usrreq(so, req, m, nam, rights); 505 } 506 return (error); 507 } 508 509