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