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