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