1: /* 2: * Copyright (c) 1982, 1986 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 7.1 (Berkeley) 6/5/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: /* 138: * Notify a udp user of an asynchronous error; 139: * just wake up so that he can collect error status. 140: */ 141: udp_notify(inp) 142: register struct inpcb *inp; 143: { 144: 145: sorwakeup(inp->inp_socket); 146: sowwakeup(inp->inp_socket); 147: } 148: 149: udp_ctlinput(cmd, sa) 150: int cmd; 151: struct sockaddr *sa; 152: { 153: extern u_char inetctlerrmap[]; 154: struct sockaddr_in *sin; 155: int in_rtchange(); 156: 157: if ((unsigned)cmd > PRC_NCMDS) 158: return; 159: if (sa->sa_family != AF_INET && sa->sa_family != AF_IMPLINK) 160: return; 161: sin = (struct sockaddr_in *)sa; 162: if (sin->sin_addr.s_addr == INADDR_ANY) 163: return; 164: 165: switch (cmd) { 166: 167: case PRC_QUENCH: 168: break; 169: 170: case PRC_ROUTEDEAD: 171: case PRC_REDIRECT_NET: 172: case PRC_REDIRECT_HOST: 173: case PRC_REDIRECT_TOSNET: 174: case PRC_REDIRECT_TOSHOST: 175: in_pcbnotify(&udb, &sin->sin_addr, 0, in_rtchange); 176: break; 177: 178: default: 179: if (inetctlerrmap[cmd] == 0) 180: return; /* XXX */ 181: in_pcbnotify(&udb, &sin->sin_addr, (int)inetctlerrmap[cmd], 182: udp_notify); 183: } 184: } 185: 186: udp_output(inp, m0) 187: register struct inpcb *inp; 188: struct mbuf *m0; 189: { 190: register struct mbuf *m; 191: register struct udpiphdr *ui; 192: register int len = 0; 193: 194: /* 195: * Calculate data length and get a mbuf 196: * for UDP and IP headers. 197: */ 198: for (m = m0; m; m = m->m_next) 199: len += m->m_len; 200: MGET(m, M_DONTWAIT, MT_HEADER); 201: if (m == 0) { 202: m_freem(m0); 203: return (ENOBUFS); 204: } 205: 206: /* 207: * Fill in mbuf with extended UDP header 208: * and addresses and length put into network format. 209: */ 210: m->m_off = MMAXOFF - sizeof (struct udpiphdr); 211: m->m_len = sizeof (struct udpiphdr); 212: m->m_next = m0; 213: ui = mtod(m, struct udpiphdr *); 214: ui->ui_next = ui->ui_prev = 0; 215: ui->ui_x1 = 0; 216: ui->ui_pr = IPPROTO_UDP; 217: ui->ui_len = htons((u_short)len + sizeof (struct udphdr)); 218: ui->ui_src = inp->inp_laddr; 219: ui->ui_dst = inp->inp_faddr; 220: ui->ui_sport = inp->inp_lport; 221: ui->ui_dport = inp->inp_fport; 222: ui->ui_ulen = ui->ui_len; 223: 224: /* 225: * Stuff checksum and output datagram. 226: */ 227: ui->ui_sum = 0; 228: if (udpcksum) { 229: if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0) 230: ui->ui_sum = -1; 231: } 232: ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len; 233: ((struct ip *)ui)->ip_ttl = UDP_TTL; 234: return (ip_output(m, inp->inp_options, &inp->inp_route, 235: inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST))); 236: } 237: 238: int udp_sendspace = 2048; /* really max datagram size */ 239: int udp_recvspace = 4 * (1024+sizeof(struct sockaddr_in)); /* 4 1K dgrams */ 240: 241: /*ARGSUSED*/ 242: udp_usrreq(so, req, m, nam, rights) 243: struct socket *so; 244: int req; 245: struct mbuf *m, *nam, *rights; 246: { 247: struct inpcb *inp = sotoinpcb(so); 248: int error = 0; 249: 250: if (req == PRU_CONTROL) 251: return (in_control(so, (int)m, (caddr_t)nam, 252: (struct ifnet *)rights)); 253: if (rights && rights->m_len) { 254: error = EINVAL; 255: goto release; 256: } 257: if (inp == NULL && req != PRU_ATTACH) { 258: error = EINVAL; 259: goto release; 260: } 261: switch (req) { 262: 263: case PRU_ATTACH: 264: if (inp != NULL) { 265: error = EINVAL; 266: break; 267: } 268: error = in_pcballoc(so, &udb); 269: if (error) 270: break; 271: error = soreserve(so, udp_sendspace, udp_recvspace); 272: if (error) 273: break; 274: break; 275: 276: case PRU_DETACH: 277: in_pcbdetach(inp); 278: break; 279: 280: case PRU_BIND: 281: error = in_pcbbind(inp, nam); 282: break; 283: 284: case PRU_LISTEN: 285: error = EOPNOTSUPP; 286: break; 287: 288: case PRU_CONNECT: 289: if (inp->inp_faddr.s_addr != INADDR_ANY) { 290: error = EISCONN; 291: break; 292: } 293: error = in_pcbconnect(inp, nam); 294: if (error == 0) 295: soisconnected(so); 296: break; 297: 298: case PRU_CONNECT2: 299: error = EOPNOTSUPP; 300: break; 301: 302: case PRU_ACCEPT: 303: error = EOPNOTSUPP; 304: break; 305: 306: case PRU_DISCONNECT: 307: if (inp->inp_faddr.s_addr == INADDR_ANY) { 308: error = ENOTCONN; 309: break; 310: } 311: in_pcbdisconnect(inp); 312: so->so_state &= ~SS_ISCONNECTED; /* XXX */ 313: break; 314: 315: case PRU_SHUTDOWN: 316: socantsendmore(so); 317: break; 318: 319: case PRU_SEND: { 320: struct in_addr laddr; 321: int s; 322: 323: if (nam) { 324: laddr = inp->inp_laddr; 325: if (inp->inp_faddr.s_addr != INADDR_ANY) { 326: error = EISCONN; 327: break; 328: } 329: /* 330: * Must block input while temporarily connected. 331: */ 332: s = splnet(); 333: error = in_pcbconnect(inp, nam); 334: if (error) { 335: splx(s); 336: break; 337: } 338: } else { 339: if (inp->inp_faddr.s_addr == INADDR_ANY) { 340: error = ENOTCONN; 341: break; 342: } 343: } 344: error = udp_output(inp, m); 345: m = NULL; 346: if (nam) { 347: in_pcbdisconnect(inp); 348: inp->inp_laddr = laddr; 349: splx(s); 350: } 351: } 352: break; 353: 354: case PRU_ABORT: 355: in_pcbdetach(inp); 356: sofree(so); 357: soisdisconnected(so); 358: break; 359: 360: case PRU_SOCKADDR: 361: in_setsockaddr(inp, nam); 362: break; 363: 364: case PRU_PEERADDR: 365: in_setpeeraddr(inp, nam); 366: break; 367: 368: case PRU_SENSE: 369: /* 370: * stat: don't bother with a blocksize. 371: */ 372: return (0); 373: 374: case PRU_SENDOOB: 375: case PRU_FASTTIMO: 376: case PRU_SLOWTIMO: 377: case PRU_PROTORCV: 378: case PRU_PROTOSEND: 379: error = EOPNOTSUPP; 380: break; 381: 382: case PRU_RCVD: 383: case PRU_RCVOOB: 384: return (EOPNOTSUPP); /* do not free mbuf's */ 385: 386: default: 387: panic("udp_usrreq"); 388: } 389: release: 390: if (m != NULL) 391: m_freem(m); 392: return (error); 393: }