1 /* 2 * Copyright (c) 1982, 1986 Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that this notice is preserved and that due credit is given 7 * to the University of California at Berkeley. The name of the University 8 * may not be used to endorse or promote products derived from this 9 * software without specific prior written permission. This software 10 * is provided ``as is'' without express or implied warranty. 11 * 12 * @(#)udp_usrreq.c 7.4 (Berkeley) 12/07/87 13 */ 14 15 #include "param.h" 16 #include "dir.h" 17 #include "user.h" 18 #include "mbuf.h" 19 #include "protosw.h" 20 #include "socket.h" 21 #include "socketvar.h" 22 #include "errno.h" 23 #include "stat.h" 24 25 #include "../net/if.h" 26 #include "../net/route.h" 27 28 #include "in.h" 29 #include "in_pcb.h" 30 #include "in_systm.h" 31 #include "ip.h" 32 #include "ip_var.h" 33 #include "ip_icmp.h" 34 #include "udp.h" 35 #include "udp_var.h" 36 37 /* 38 * UDP protocol implementation. 39 * Per RFC 768, August, 1980. 40 */ 41 udp_init() 42 { 43 44 udb.inp_next = udb.inp_prev = &udb; 45 } 46 47 #ifndef COMPAT_42 48 int udpcksum = 1; 49 #else 50 int udpcksum = 0; /* XXX */ 51 #endif 52 int udp_ttl = UDP_TTL; 53 54 struct sockaddr_in udp_in = { AF_INET }; 55 56 udp_input(m0, ifp) 57 struct mbuf *m0; 58 struct ifnet *ifp; 59 { 60 register struct udpiphdr *ui; 61 register struct inpcb *inp; 62 register struct mbuf *m; 63 int len; 64 struct ip ip; 65 66 /* 67 * Get IP and UDP header together in first mbuf. 68 */ 69 m = m0; 70 if ((m->m_off > MMAXOFF || m->m_len < sizeof (struct udpiphdr)) && 71 (m = m_pullup(m, sizeof (struct udpiphdr))) == 0) { 72 udpstat.udps_hdrops++; 73 return; 74 } 75 ui = mtod(m, struct udpiphdr *); 76 if (((struct ip *)ui)->ip_hl > (sizeof (struct ip) >> 2)) 77 ip_stripoptions((struct ip *)ui, (struct mbuf *)0); 78 79 /* 80 * Make mbuf data length reflect UDP length. 81 * If not enough data to reflect UDP length, drop. 82 */ 83 len = ntohs((u_short)ui->ui_ulen); 84 if (((struct ip *)ui)->ip_len != len) { 85 if (len > ((struct ip *)ui)->ip_len) { 86 udpstat.udps_badlen++; 87 goto bad; 88 } 89 m_adj(m, len - ((struct ip *)ui)->ip_len); 90 /* ((struct ip *)ui)->ip_len = len; */ 91 } 92 /* 93 * Save a copy of the IP header in case we want restore it for ICMP. 94 */ 95 ip = *(struct ip*)ui; 96 97 /* 98 * Checksum extended UDP header and data. 99 */ 100 if (udpcksum && ui->ui_sum) { 101 ui->ui_next = ui->ui_prev = 0; 102 ui->ui_x1 = 0; 103 ui->ui_len = ui->ui_ulen; 104 if (ui->ui_sum = in_cksum(m, len + sizeof (struct ip))) { 105 udpstat.udps_badsum++; 106 m_freem(m); 107 return; 108 } 109 } 110 111 /* 112 * Locate pcb for datagram. 113 */ 114 inp = in_pcblookup(&udb, 115 ui->ui_src, ui->ui_sport, ui->ui_dst, ui->ui_dport, 116 INPLOOKUP_WILDCARD); 117 if (inp == 0) { 118 /* don't send ICMP response for broadcast packet */ 119 if (in_broadcast(ui->ui_dst)) 120 goto bad; 121 *(struct ip *)ui = ip; 122 icmp_error((struct ip *)ui, ICMP_UNREACH, ICMP_UNREACH_PORT, 123 ifp); 124 return; 125 } 126 127 /* 128 * Construct sockaddr format source address. 129 * Stuff source address and datagram in user buffer. 130 */ 131 udp_in.sin_port = ui->ui_sport; 132 udp_in.sin_addr = ui->ui_src; 133 m->m_len -= sizeof (struct udpiphdr); 134 m->m_off += sizeof (struct udpiphdr); 135 if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, 136 m, (struct mbuf *)0) == 0) 137 goto bad; 138 sorwakeup(inp->inp_socket); 139 return; 140 bad: 141 m_freem(m); 142 } 143 144 /* 145 * Notify a udp user of an asynchronous error; 146 * just wake up so that he can collect error status. 147 */ 148 udp_notify(inp) 149 register struct inpcb *inp; 150 { 151 152 sorwakeup(inp->inp_socket); 153 sowwakeup(inp->inp_socket); 154 } 155 156 udp_ctlinput(cmd, sa) 157 int cmd; 158 struct sockaddr *sa; 159 { 160 extern u_char inetctlerrmap[]; 161 struct sockaddr_in *sin; 162 int in_rtchange(); 163 164 if ((unsigned)cmd > PRC_NCMDS) 165 return; 166 if (sa->sa_family != AF_INET && sa->sa_family != AF_IMPLINK) 167 return; 168 sin = (struct sockaddr_in *)sa; 169 if (sin->sin_addr.s_addr == INADDR_ANY) 170 return; 171 172 switch (cmd) { 173 174 case PRC_QUENCH: 175 break; 176 177 case PRC_ROUTEDEAD: 178 case PRC_REDIRECT_NET: 179 case PRC_REDIRECT_HOST: 180 case PRC_REDIRECT_TOSNET: 181 case PRC_REDIRECT_TOSHOST: 182 in_pcbnotify(&udb, &sin->sin_addr, 0, in_rtchange); 183 break; 184 185 default: 186 if (inetctlerrmap[cmd] == 0) 187 return; /* XXX */ 188 in_pcbnotify(&udb, &sin->sin_addr, (int)inetctlerrmap[cmd], 189 udp_notify); 190 } 191 } 192 193 udp_output(inp, m0) 194 register struct inpcb *inp; 195 struct mbuf *m0; 196 { 197 register struct mbuf *m; 198 register struct udpiphdr *ui; 199 register int len = 0; 200 201 /* 202 * Calculate data length and get a mbuf 203 * for UDP and IP headers. 204 */ 205 for (m = m0; m; m = m->m_next) 206 len += m->m_len; 207 MGET(m, M_DONTWAIT, MT_HEADER); 208 if (m == 0) { 209 m_freem(m0); 210 return (ENOBUFS); 211 } 212 213 /* 214 * Fill in mbuf with extended UDP header 215 * and addresses and length put into network format. 216 */ 217 m->m_off = MMAXOFF - sizeof (struct udpiphdr); 218 m->m_len = sizeof (struct udpiphdr); 219 m->m_next = m0; 220 ui = mtod(m, struct udpiphdr *); 221 ui->ui_next = ui->ui_prev = 0; 222 ui->ui_x1 = 0; 223 ui->ui_pr = IPPROTO_UDP; 224 ui->ui_len = htons((u_short)len + sizeof (struct udphdr)); 225 ui->ui_src = inp->inp_laddr; 226 ui->ui_dst = inp->inp_faddr; 227 ui->ui_sport = inp->inp_lport; 228 ui->ui_dport = inp->inp_fport; 229 ui->ui_ulen = ui->ui_len; 230 231 /* 232 * Stuff checksum and output datagram. 233 */ 234 ui->ui_sum = 0; 235 if (udpcksum) { 236 if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0) 237 ui->ui_sum = -1; 238 } 239 ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len; 240 ((struct ip *)ui)->ip_ttl = udp_ttl; 241 return (ip_output(m, inp->inp_options, &inp->inp_route, 242 inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST))); 243 } 244 245 int udp_sendspace = 2048; /* really max datagram size */ 246 int udp_recvspace = 4 * (1024+sizeof(struct sockaddr_in)); /* 4 1K dgrams */ 247 248 /*ARGSUSED*/ 249 udp_usrreq(so, req, m, nam, rights) 250 struct socket *so; 251 int req; 252 struct mbuf *m, *nam, *rights; 253 { 254 struct inpcb *inp = sotoinpcb(so); 255 int error = 0; 256 257 if (req == PRU_CONTROL) 258 return (in_control(so, (int)m, (caddr_t)nam, 259 (struct ifnet *)rights)); 260 if (rights && rights->m_len) { 261 error = EINVAL; 262 goto release; 263 } 264 if (inp == NULL && req != PRU_ATTACH) { 265 error = EINVAL; 266 goto release; 267 } 268 switch (req) { 269 270 case PRU_ATTACH: 271 if (inp != NULL) { 272 error = EINVAL; 273 break; 274 } 275 error = in_pcballoc(so, &udb); 276 if (error) 277 break; 278 error = soreserve(so, udp_sendspace, udp_recvspace); 279 if (error) 280 break; 281 break; 282 283 case PRU_DETACH: 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 so->so_state &= ~SS_ISCONNECTED; /* XXX */ 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 soisdisconnected(so); 363 in_pcbdetach(inp); 364 break; 365 366 case PRU_SOCKADDR: 367 in_setsockaddr(inp, nam); 368 break; 369 370 case PRU_PEERADDR: 371 in_setpeeraddr(inp, nam); 372 break; 373 374 case PRU_SENSE: 375 /* 376 * stat: don't bother with a blocksize. 377 */ 378 return (0); 379 380 case PRU_SENDOOB: 381 case PRU_FASTTIMO: 382 case PRU_SLOWTIMO: 383 case PRU_PROTORCV: 384 case PRU_PROTOSEND: 385 error = EOPNOTSUPP; 386 break; 387 388 case PRU_RCVD: 389 case PRU_RCVOOB: 390 return (EOPNOTSUPP); /* do not free mbuf's */ 391 392 default: 393 panic("udp_usrreq"); 394 } 395 release: 396 if (m != NULL) 397 m_freem(m); 398 return (error); 399 } 400