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.3 (Berkeley) 06/08/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 error = EINVAL; 181 goto release; 182 } 183 184 switch (req) { 185 case PRCO_GETOPT: 186 if (value==NULL) { 187 error = EINVAL; 188 goto release; 189 } 190 m = m_get(M_DONTWAIT, MT_DATA); 191 switch (name) { 192 case SO_HEADERS_ON_INPUT: 193 mask = NSP_RAWIN; 194 goto get_flags; 195 case SO_HEADERS_ON_OUTPUT: 196 mask = NSP_RAWOUT; 197 get_flags: 198 m->m_len = sizeof(short); 199 m->m_off = MMAXOFF - sizeof(short); 200 *mtod(m, short *) = nsp->nsp_flags & mask; 201 break; 202 case SO_DEFAULT_HEADERS: 203 m->m_len = sizeof(struct idp); 204 m->m_off = MMAXOFF - sizeof(struct idp); 205 { 206 register struct idp *idp = mtod(m, struct idp *); 207 idp->idp_len = 0; 208 idp->idp_sum = 0; 209 idp->idp_tc = 0; 210 idp->idp_pt = nsp->nsp_dpt; 211 idp->idp_dna = nsp->nsp_faddr; 212 idp->idp_sna = nsp->nsp_laddr; 213 } 214 } 215 *value = m; 216 break; 217 case PRCO_SETOPT: 218 switch (name) { 219 int mask, *ok; 220 221 case SO_HEADERS_ON_INPUT: 222 mask = NSP_RAWIN; 223 goto set_head; 224 case SO_HEADERS_ON_OUTPUT: 225 mask = NSP_RAWOUT; 226 set_head: 227 if (value && *value) { 228 ok = mtod(*value, int *); 229 if (*ok) 230 nsp->nsp_flags |= mask; 231 else 232 nsp->nsp_flags &= ~mask; 233 } else error = EINVAL; 234 break; 235 case SO_DEFAULT_HEADERS: 236 { 237 register struct idp *idp 238 = mtod(*value, struct idp *); 239 nsp->nsp_dpt = idp->idp_pt; 240 } 241 #ifdef NSIP 242 break; 243 case SO_NSIP_ROUTE: 244 error = nsip_route(*value); 245 break; 246 #endif NSIP 247 } 248 if (value && *value) 249 m_freem(*value); 250 break; 251 } 252 release: 253 return(error); 254 } 255 256 /*ARGSUSED*/ 257 idp_usrreq(so, req, m, nam, rights) 258 struct socket *so; 259 int req; 260 struct mbuf *m, *nam, *rights; 261 { 262 struct nspcb *nsp = sotonspcb(so); 263 int error = 0; 264 265 if (req == PRU_CONTROL) 266 return (ns_control(so, (int)m, (caddr_t)nam, 267 (struct ifnet *)rights)); 268 if (rights && rights->m_len) { 269 error = EINVAL; 270 goto release; 271 } 272 if (nsp == NULL && req != PRU_ATTACH) { 273 error = EINVAL; 274 goto release; 275 } 276 switch (req) { 277 278 case PRU_ATTACH: 279 if (nsp != NULL) { 280 error = EINVAL; 281 break; 282 } 283 error = ns_pcballoc(so, &nspcb); 284 if (error) 285 break; 286 error = soreserve(so, 2048, 2048); 287 if (error) 288 break; 289 break; 290 291 case PRU_DETACH: 292 if (nsp == NULL) { 293 error = ENOTCONN; 294 break; 295 } 296 ns_pcbdetach(nsp); 297 break; 298 299 case PRU_BIND: 300 error = ns_pcbbind(nsp, nam); 301 break; 302 303 case PRU_LISTEN: 304 error = EOPNOTSUPP; 305 break; 306 307 case PRU_CONNECT: 308 if (!ns_nullhost(nsp->nsp_faddr)) { 309 error = EISCONN; 310 break; 311 } 312 error = ns_pcbconnect(nsp, nam); 313 if (error == 0) 314 soisconnected(so); 315 break; 316 317 case PRU_CONNECT2: 318 error = EOPNOTSUPP; 319 break; 320 321 case PRU_ACCEPT: 322 error = EOPNOTSUPP; 323 break; 324 325 case PRU_DISCONNECT: 326 if (ns_nullhost(nsp->nsp_faddr)) { 327 error = ENOTCONN; 328 break; 329 } 330 ns_pcbdisconnect(nsp); 331 soisdisconnected(so); 332 break; 333 334 case PRU_SHUTDOWN: 335 socantsendmore(so); 336 break; 337 338 case PRU_SEND: 339 { 340 struct ns_addr laddr; 341 int s; 342 343 if (nam) { 344 laddr = nsp->nsp_laddr; 345 if (!ns_nullhost(nsp->nsp_faddr)) { 346 error = EISCONN; 347 break; 348 } 349 /* 350 * Must block input while temporarily connected. 351 */ 352 s = splnet(); 353 error = ns_pcbconnect(nsp, nam); 354 if (error) { 355 splx(s); 356 break; 357 } 358 } else { 359 if (ns_nullhost(nsp->nsp_faddr)) { 360 error = ENOTCONN; 361 break; 362 } 363 } 364 error = idp_output(nsp, m); 365 m = NULL; 366 if (nam) { 367 ns_pcbdisconnect(nsp); 368 splx(s); 369 nsp->nsp_laddr.x_host = laddr.x_host; 370 nsp->nsp_laddr.x_port = laddr.x_port; 371 } 372 } 373 break; 374 375 case PRU_ABORT: 376 ns_pcbdetach(nsp); 377 sofree(so); 378 soisdisconnected(so); 379 break; 380 381 case PRU_SOCKADDR: 382 ns_setsockaddr(nsp, nam); 383 break; 384 385 case PRU_PEERADDR: 386 ns_setpeeraddr(nsp, nam); 387 break; 388 389 case PRU_SENSE: 390 /* 391 * stat: don't bother with a blocksize. 392 */ 393 return (0); 394 395 case PRU_SENDOOB: 396 case PRU_FASTTIMO: 397 case PRU_SLOWTIMO: 398 case PRU_PROTORCV: 399 case PRU_PROTOSEND: 400 error = EOPNOTSUPP; 401 break; 402 403 case PRU_CONTROL: 404 case PRU_RCVD: 405 case PRU_RCVOOB: 406 return (EOPNOTSUPP); /* do not free mbuf's */ 407 408 default: 409 panic("idp_usrreq"); 410 } 411 release: 412 if (m != NULL) 413 m_freem(m); 414 return (error); 415 } 416 /*ARGSUSED*/ 417 idp_raw_usrreq(so, req, m, nam, rights) 418 struct socket *so; 419 int req; 420 struct mbuf *m, *nam, *rights; 421 { 422 int error = 0; 423 struct nspcb *nsp = sotonspcb(so); 424 extern struct nspcb nsrawpcb; 425 426 switch (req) { 427 428 case PRU_ATTACH: 429 430 if (!suser() || (nsp != NULL)) { 431 error = EINVAL; 432 break; 433 } 434 error = ns_pcballoc(so, &nsrawpcb); 435 if (error) 436 break; 437 error = soreserve(so, 2048, 2048); 438 if (error) 439 break; 440 nsp = sotonspcb(so); 441 nsp->nsp_faddr.x_host = ns_broadhost; 442 nsp->nsp_flags = NSP_RAWIN | NSP_RAWOUT; 443 break; 444 default: 445 error = idp_usrreq(so, req, m, nam, rights); 446 } 447 return(error); 448 } 449 450