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