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