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