|
|
1.1 ! root 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.