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