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