1 /* udp_usrreq.c 4.45 83/02/16 */ 2 /* 3 * UDP protocol implementation. 4 * Per RFC 768, August, 1980. 5 */ 6 7 #include "../h/param.h" 8 #include "../h/dir.h" 9 #include "../h/user.h" 10 #include "../h/mbuf.h" 11 #include "../h/protosw.h" 12 #include "../h/socket.h" 13 #include "../h/socketvar.h" 14 #include "../h/errno.h" 15 16 #include "../net/if.h" 17 #include "../net/route.h" 18 19 #include "../bbnnet/in.h" 20 #include "../bbnnet/in_var.h" 21 #include "../bbnnet/net.h" 22 #include "../bbnnet/in_pcb.h" 23 #include "../bbnnet/ip.h" 24 #include "../bbnnet/udp.h" 25 #include "../bbnnet/fsm.h" 26 #include "../bbnnet/tcp.h" 27 #include "../bbnnet/icmp.h" 28 29 extern udp_binding_used(); 30 extern struct inpcb udp; 31 32 struct pr_advice udp_advice = 33 { 34 UDP_RESERVED, /* all basically the same as TCP */ 35 UDP_USERRESERVED, 36 UDP_MAXPORT, 37 UDP_USERRESERVED+1, 38 sizeof(u_short), 39 udp_binding_used 40 } ; 41 42 udp_init() 43 { 44 udp.inp_next = udp.inp_prev = &udp; 45 ipsw[IPPROTO_UDP].ipsw_hlen = sizeof(struct udp); 46 } 47 48 udp_abort(inp) 49 struct inpcb *inp; 50 { 51 struct socket *so = inp->inp_socket; 52 53 in_pcbdisconnect(inp, (int(*)())0); 54 soisdisconnected(so); 55 } 56 57 /* 58 * Is a udp port/address pair already in use? 59 */ 60 int udp_binding_used(inp, lport, lsaddr, reuselocal) 61 struct inpcb *inp; 62 u_short lport; 63 u_long lsaddr; 64 { 65 register struct inpcb *i; 66 67 if (reuselocal) 68 /* 69 * But since UDP, unlike TCP, is not connection oriented, 70 * this allows for liars to exist. 71 */ 72 return (0); 73 74 for (i = udp.inp_next; i != &udp; i = i->inp_next) 75 { 76 if (i != inp) 77 if (i->inp_lport == lport) 78 if ((i->inp_laddr.s_addr == lsaddr) || 79 (i->inp_laddr.s_addr == INADDR_ANY) || 80 (lsaddr == INADDR_ANY)) 81 break; 82 } 83 return (i != &udp); 84 } 85 86 char *udp_conn_used(inp, lport, lsaddr, fport, fsaddr) 87 struct inpcb *inp; 88 u_short lport; 89 u_long lsaddr; 90 u_short fport; 91 u_long fsaddr; 92 { 93 register struct inpcb *i; 94 95 for (i = udp.inp_next; i != &udp; i = i->inp_next) 96 { 97 /* 98 * Since our inpcb is in this linked list, don't want to know 99 * if we, ourselves, are already using this connetion. 100 */ 101 if (i != inp) 102 if ((i->inp_lport == lport) && (i->inp_fport == fport) && 103 (i->inp_laddr.s_addr == lsaddr) && 104 (i->inp_faddr.s_addr == fsaddr)) 105 return((char *) i); 106 } 107 108 return ((char *) NULL); 109 } 110 111 112 /*ARGSUSED*/ 113 udp_usrreq(so, req, m, nam, rights) 114 struct socket *so; 115 register int req; 116 struct mbuf *m, *nam, *rights; 117 { 118 register int s; 119 struct inpcb *inp; 120 int error = 0; 121 122 s = splnet(); 123 inp = sotoinpcb(so); 124 125 if (rights && req != PRU_CONTROL) 126 { 127 if (rights->m_len) 128 { 129 error = EINVAL; 130 goto release; 131 } 132 } 133 134 if (inp == NULL && req != PRU_ATTACH) 135 { 136 error = EINVAL; 137 goto release; 138 } 139 140 switch (req) 141 { 142 143 case PRU_ATTACH: 144 if (inp != NULL) 145 { 146 error = EINVAL; 147 break; 148 } 149 error = soreserve(so, 2048, 2048); 150 if (error) 151 break; 152 error = in_pcballoc(so, &udp); 153 if (error) 154 break; 155 break; 156 157 case PRU_DETACH: 158 if (inp == NULL) 159 { 160 error = ENOTCONN; 161 break; 162 } 163 in_pcbdetach(inp, (int (*)())0); 164 break; 165 166 case PRU_BIND: 167 error = in_pcbbind(inp, nam, &udp_advice); 168 break; 169 170 case PRU_LISTEN: 171 error = EOPNOTSUPP; 172 break; 173 174 case PRU_CONNECT: 175 if (inp->inp_faddr.s_addr != INADDR_ANY) 176 { 177 error = EISCONN; 178 break; 179 } 180 if (inp->inp_lport == 0) 181 { 182 error = in_pcbbind(inp, (struct mbuf *)0, &udp_advice); 183 if (error) 184 break; 185 } 186 error = in_pcbconnect(inp, nam, udp_conn_used); 187 if (error == 0) 188 soisconnected(so); 189 break; 190 191 case PRU_ACCEPT: 192 error = EOPNOTSUPP; 193 break; 194 195 case PRU_DISCONNECT: 196 if (inp->inp_faddr.s_addr == INADDR_ANY) 197 { 198 error = ENOTCONN; 199 break; 200 } 201 in_pcbdisconnect(inp, (int(*)())0); 202 soisdisconnected(so); 203 break; 204 205 case PRU_SHUTDOWN: 206 socantsendmore(so); 207 break; 208 209 case PRU_SEND: 210 { 211 struct in_addr laddr; 212 213 if (nam) 214 { 215 laddr = inp->inp_laddr; 216 if (inp->inp_faddr.s_addr != INADDR_ANY) 217 { 218 error = EISCONN; 219 break; 220 } 221 if (inp->inp_lport == 0) 222 { 223 if (error = in_pcbbind(inp, (struct mbuf *)0, &udp_advice)) 224 break; 225 } 226 error = in_pcbconnect(inp, nam, udp_conn_used); 227 if (error) 228 break; 229 } 230 else 231 { 232 if (inp->inp_faddr.s_addr == INADDR_ANY) 233 { 234 error = ENOTCONN; 235 break; 236 } 237 } 238 error = udp_output(inp, m); 239 m = NULL; 240 if (nam) 241 { 242 in_pcbdisconnect(inp, (int(*))0); 243 inp->inp_laddr = laddr; 244 } 245 } 246 break; 247 248 case PRU_ABORT: 249 in_pcbdetach(inp, (int (*)())0); 250 break; 251 252 case PRU_CONTROL: 253 /* not our ioctl, let lower level try ioctl */ 254 error = ip_ioctl (inp, (int) m, (caddr_t) nam); 255 goto dontfree; 256 257 case PRU_SOCKADDR: 258 in_setsockaddr(inp, nam); 259 break; 260 261 default: 262 panic("udp_usrreq"); 263 } 264 265 release : 266 if (m != NULL) 267 m_freem(m); 268 dontfree: 269 splx(s); 270 return (error); 271 } 272 273 udp_ctlinput (prc_code, arg) 274 caddr_t arg; 275 { 276 int error; 277 278 error = inetctlerrmap[prc_code]; 279 280 switch (prc_code) 281 { 282 case PRC_UNREACH_PROTOCOL: /* icmp message */ 283 case PRC_UNREACH_PORT: 284 case PRC_MSGSIZE: 285 { 286 register struct udp *up; 287 struct inpcb *inp; 288 289 up = (struct udp *) (&((struct icmp *) arg)->ic_iphdr); 290 inp = (struct inpcb *)udp_conn_used ((struct inpcb *) 0, 291 up->u_src, up->u_s.s_addr, 292 up->u_dst, up->u_d.s_addr); 293 294 if (inp) 295 { 296 inp->inp_socket->so_error = error; 297 udp_abort(inp); 298 } 299 } 300 break; 301 302 case PRC_UNREACH_NET: 303 case PRC_UNREACH_HOST: 304 { 305 register struct udp *up; 306 struct inpcb *inp; 307 308 up = (struct udp *) (&((struct icmp *) arg)->ic_iphdr); 309 inp = (struct inpcb *)udp_conn_used ((struct inpcb *) 0, 310 up->u_src, up->u_s.s_addr, 311 up->u_dst, up->u_d.s_addr); 312 313 if (inp) 314 { 315 struct socket *so; 316 317 so = inp->inp_socket; 318 if ((so->so_state & SS_NOFDREF) == 0) 319 advise_user(so, error); 320 else 321 { 322 so->so_error = error; 323 udp_abort(inp); 324 } 325 } 326 } 327 break; 328 329 case PRC_GWDOWN: 330 in_gdown (&udp, (u_long) arg); 331 break; 332 333 case PRC_REDIRECT_NET: /* icmp message */ 334 case PRC_REDIRECT_HOST: 335 { 336 register struct udp *up; 337 struct inpcb *inp; 338 339 up = (struct udp *) (&((struct icmp *) arg)->ic_iphdr); 340 inp = (struct inpcb *)udp_conn_used ((struct inpcb *) 0, 341 up->u_src, up->u_s.s_addr, 342 up->u_dst, up->u_d.s_addr); 343 344 if (inp) 345 icmp_redirect_inp(inp, (struct icmp *) arg, 346 prc_code == PRC_REDIRECT_NET ? rtnet : rthost); 347 } 348 break; 349 350 case PRC_TIMXCEED_INTRANS: /* icmp message */ 351 case PRC_TIMXCEED_REASS: 352 case PRC_PARAMPROB: 353 case PRC_QUENCH: 354 break; 355 356 case PRC_IFDOWN: 357 { 358 u_long addr; 359 360 addr = ((struct sockaddr_in *)(arg))->sin_addr.s_addr; 361 inpcb_notify(&udp, addr, (u_long) 0, error); 362 inpcb_notify(&udp, (u_long) 0, addr, error); 363 } 364 break; 365 366 case PRC_HOSTDEAD: /* from imp interface */ 367 case PRC_HOSTUNREACH: 368 /* 369 * get same message for destination hosts and gateways. 370 */ 371 { 372 u_long addr; 373 374 addr = ((struct sockaddr_in *)arg)->sin_addr.s_addr; 375 in_gdown (&udp, addr); 376 inpcb_notify(&udp, (u_long) 0, addr, error); 377 } 378 break; 379 380 default: 381 panic("udp_ctlinput"); 382 } 383 } 384