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 * @(#)udp_usrreq.c 6.14 (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 "in.h" 23 #include "in_pcb.h" 24 #include "in_systm.h" 25 #include "ip.h" 26 #include "ip_var.h" 27 #include "ip_icmp.h" 28 #include "udp.h" 29 #include "udp_var.h" 30 31 /* 32 * UDP protocol implementation. 33 * Per RFC 768, August, 1980. 34 */ 35 udp_init() 36 { 37 38 udb.inp_next = udb.inp_prev = &udb; 39 } 40 41 int udpcksum = 1; 42 struct sockaddr_in udp_in = { AF_INET }; 43 44 udp_input(m0) 45 struct mbuf *m0; 46 { 47 register struct udpiphdr *ui; 48 register struct inpcb *inp; 49 register struct mbuf *m; 50 int len; 51 52 /* 53 * Get IP and UDP header together in first mbuf. 54 */ 55 m = m0; 56 if ((m->m_off > MMAXOFF || m->m_len < sizeof (struct udpiphdr)) && 57 (m = m_pullup(m, sizeof (struct udpiphdr))) == 0) { 58 udpstat.udps_hdrops++; 59 return; 60 } 61 ui = mtod(m, struct udpiphdr *); 62 if (((struct ip *)ui)->ip_hl > (sizeof (struct ip) >> 2)) 63 ip_stripoptions((struct ip *)ui, (struct mbuf *)0); 64 65 /* 66 * Make mbuf data length reflect UDP length. 67 * If not enough data to reflect UDP length, drop. 68 */ 69 len = ntohs((u_short)ui->ui_ulen); 70 if (((struct ip *)ui)->ip_len != len) { 71 if (len > ((struct ip *)ui)->ip_len) { 72 udpstat.udps_badlen++; 73 goto bad; 74 } 75 m_adj(m, len - ((struct ip *)ui)->ip_len); 76 /* (struct ip *)ui->ip_len = len; */ 77 } 78 79 /* 80 * Checksum extended UDP header and data. 81 */ 82 if (udpcksum && ui->ui_sum) { 83 ui->ui_next = ui->ui_prev = 0; 84 ui->ui_x1 = 0; 85 ui->ui_len = ui->ui_ulen; 86 if (ui->ui_sum = in_cksum(m, len + sizeof (struct ip))) { 87 udpstat.udps_badsum++; 88 m_freem(m); 89 return; 90 } 91 } 92 93 /* 94 * Locate pcb for datagram. 95 */ 96 inp = in_pcblookup(&udb, 97 ui->ui_src, ui->ui_sport, ui->ui_dst, ui->ui_dport, 98 INPLOOKUP_WILDCARD); 99 if (inp == 0) { 100 /* don't send ICMP response for broadcast packet */ 101 if (in_broadcast(ui->ui_dst)) 102 goto bad; 103 icmp_error((struct ip *)ui, ICMP_UNREACH, ICMP_UNREACH_PORT); 104 return; 105 } 106 107 /* 108 * Construct sockaddr format source address. 109 * Stuff source address and datagram in user buffer. 110 */ 111 udp_in.sin_port = ui->ui_sport; 112 udp_in.sin_addr = ui->ui_src; 113 m->m_len -= sizeof (struct udpiphdr); 114 m->m_off += sizeof (struct udpiphdr); 115 if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, 116 m, (struct mbuf *)0) == 0) 117 goto bad; 118 sorwakeup(inp->inp_socket); 119 return; 120 bad: 121 m_freem(m); 122 } 123 124 udp_abort(inp) 125 struct inpcb *inp; 126 { 127 struct socket *so = inp->inp_socket; 128 129 in_pcbdisconnect(inp); 130 soisdisconnected(so); 131 } 132 133 udp_ctlinput(cmd, arg) 134 int cmd; 135 caddr_t arg; 136 { 137 struct in_addr *in; 138 extern u_char inetctlerrmap[]; 139 int in_rtchange(); 140 141 if (cmd < 0 || cmd > PRC_NCMDS) 142 return; 143 switch (cmd) { 144 145 case PRC_ROUTEDEAD: 146 break; 147 148 case PRC_REDIRECT_NET: 149 case PRC_REDIRECT_HOST: 150 in = &((struct icmp *)arg)->icmp_ip.ip_dst; 151 in_pcbnotify(&udb, in, 0, in_rtchange); 152 break; 153 154 case PRC_IFDOWN: 155 in = &((struct sockaddr_in *)arg)->sin_addr; 156 goto notify; 157 158 case PRC_HOSTDEAD: 159 case PRC_HOSTUNREACH: 160 in = (struct in_addr *)arg; 161 goto notify; 162 163 default: 164 if (inetctlerrmap[cmd] == 0) 165 return; /* XXX */ 166 in = &((struct icmp *)arg)->icmp_ip.ip_dst; 167 notify: 168 in_pcbnotify(&udb, in, (int)inetctlerrmap[cmd], udp_abort); 169 } 170 } 171 172 udp_output(inp, m0) 173 struct inpcb *inp; 174 struct mbuf *m0; 175 { 176 register struct mbuf *m; 177 register struct udpiphdr *ui; 178 register struct socket *so; 179 register int len = 0; 180 register struct route *ro; 181 182 /* 183 * Calculate data length and get a mbuf 184 * for UDP and IP headers. 185 */ 186 for (m = m0; m; m = m->m_next) 187 len += m->m_len; 188 MGET(m, M_DONTWAIT, MT_HEADER); 189 if (m == 0) { 190 m_freem(m0); 191 return (ENOBUFS); 192 } 193 194 /* 195 * Fill in mbuf with extended UDP header 196 * and addresses and length put into network format. 197 */ 198 m->m_off = MMAXOFF - sizeof (struct udpiphdr); 199 m->m_len = sizeof (struct udpiphdr); 200 m->m_next = m0; 201 ui = mtod(m, struct udpiphdr *); 202 ui->ui_next = ui->ui_prev = 0; 203 ui->ui_x1 = 0; 204 ui->ui_pr = IPPROTO_UDP; 205 ui->ui_len = htons((u_short)len + sizeof (struct udphdr)); 206 ui->ui_src = inp->inp_laddr; 207 ui->ui_dst = inp->inp_faddr; 208 ui->ui_sport = inp->inp_lport; 209 ui->ui_dport = inp->inp_fport; 210 ui->ui_ulen = ui->ui_len; 211 212 /* 213 * Stuff checksum and output datagram. 214 */ 215 ui->ui_sum = 0; 216 if (udpcksum) { 217 if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0) 218 ui->ui_sum = -1; 219 } 220 ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len; 221 ((struct ip *)ui)->ip_ttl = MAXTTL; 222 so = inp->inp_socket; 223 if (so->so_options & SO_DONTROUTE) 224 return (ip_output(m, (struct mbuf *)0, (struct route *)0, 225 (so->so_options & SO_BROADCAST) | IP_ROUTETOIF)); 226 /* 227 * Use cached route for previous datagram if 228 * this is also to the same destination. 229 * 230 * NB: We don't handle broadcasts because that 231 * would require 3 subroutine calls. 232 */ 233 ro = &inp->inp_route; 234 #define satosin(sa) ((struct sockaddr_in *)(sa)) 235 if (ro->ro_rt && 236 satosin(&ro->ro_dst)->sin_addr.s_addr != ui->ui_dst.s_addr) { 237 RTFREE(ro->ro_rt); 238 ro->ro_rt = (struct rtentry *)0; 239 } 240 return (ip_output(m, (struct mbuf *)0, ro, 241 so->so_options & SO_BROADCAST)); 242 } 243 244 int udp_sendspace = 2048; /* really max datagram size */ 245 int udp_recvspace = 4 * (1024+sizeof(struct sockaddr_in)); /* 4 1K dgrams */ 246 247 /*ARGSUSED*/ 248 udp_usrreq(so, req, m, nam, rights) 249 struct socket *so; 250 int req; 251 struct mbuf *m, *nam, *rights; 252 { 253 struct inpcb *inp = sotoinpcb(so); 254 int error = 0; 255 256 if (req == PRU_CONTROL) 257 return (in_control(so, (int)m, (caddr_t)nam, 258 (struct ifnet *)rights)); 259 if (rights && rights->m_len) { 260 error = EINVAL; 261 goto release; 262 } 263 if (inp == NULL && req != PRU_ATTACH) { 264 error = EINVAL; 265 goto release; 266 } 267 switch (req) { 268 269 case PRU_ATTACH: 270 if (inp != NULL) { 271 error = EINVAL; 272 break; 273 } 274 error = in_pcballoc(so, &udb); 275 if (error) 276 break; 277 error = soreserve(so, udp_sendspace, udp_recvspace); 278 if (error) 279 break; 280 break; 281 282 case PRU_DETACH: 283 if (inp == NULL) { 284 error = ENOTCONN; 285 break; 286 } 287 in_pcbdetach(inp); 288 break; 289 290 case PRU_BIND: 291 error = in_pcbbind(inp, nam); 292 break; 293 294 case PRU_LISTEN: 295 error = EOPNOTSUPP; 296 break; 297 298 case PRU_CONNECT: 299 if (inp->inp_faddr.s_addr != INADDR_ANY) { 300 error = EISCONN; 301 break; 302 } 303 error = in_pcbconnect(inp, nam); 304 if (error == 0) 305 soisconnected(so); 306 break; 307 308 case PRU_CONNECT2: 309 error = EOPNOTSUPP; 310 break; 311 312 case PRU_ACCEPT: 313 error = EOPNOTSUPP; 314 break; 315 316 case PRU_DISCONNECT: 317 if (inp->inp_faddr.s_addr == INADDR_ANY) { 318 error = ENOTCONN; 319 break; 320 } 321 in_pcbdisconnect(inp); 322 soisdisconnected(so); 323 break; 324 325 case PRU_SHUTDOWN: 326 socantsendmore(so); 327 break; 328 329 case PRU_SEND: { 330 struct in_addr laddr; 331 int s; 332 333 if (nam) { 334 laddr = inp->inp_laddr; 335 if (inp->inp_faddr.s_addr != INADDR_ANY) { 336 error = EISCONN; 337 break; 338 } 339 /* 340 * Must block input while temporarily connected. 341 */ 342 s = splnet(); 343 error = in_pcbconnect(inp, nam); 344 if (error) { 345 splx(s); 346 break; 347 } 348 } else { 349 if (inp->inp_faddr.s_addr == INADDR_ANY) { 350 error = ENOTCONN; 351 break; 352 } 353 } 354 error = udp_output(inp, m); 355 m = NULL; 356 if (nam) { 357 in_pcbdisconnect(inp); 358 inp->inp_laddr = laddr; 359 splx(s); 360 } 361 } 362 break; 363 364 case PRU_ABORT: 365 in_pcbdetach(inp); 366 sofree(so); 367 soisdisconnected(so); 368 break; 369 370 case PRU_SOCKADDR: 371 in_setsockaddr(inp, nam); 372 break; 373 374 case PRU_PEERADDR: 375 in_setpeeraddr(inp, nam); 376 break; 377 378 case PRU_SENSE: 379 /* 380 * stat: don't bother with a blocksize. 381 */ 382 return (0); 383 384 case PRU_SENDOOB: 385 case PRU_FASTTIMO: 386 case PRU_SLOWTIMO: 387 case PRU_PROTORCV: 388 case PRU_PROTOSEND: 389 error = EOPNOTSUPP; 390 break; 391 392 case PRU_RCVD: 393 case PRU_RCVOOB: 394 return (EOPNOTSUPP); /* do not free mbuf's */ 395 396 default: 397 panic("udp_usrreq"); 398 } 399 release: 400 if (m != NULL) 401 m_freem(m); 402 return (error); 403 } 404