1 /* udp_usrreq.c 4.24 82/03/29 */ 2 3 #include "../h/param.h" 4 #include "../h/dir.h" 5 #include "../h/user.h" 6 #include "../h/mbuf.h" 7 #include "../h/protosw.h" 8 #include "../h/socket.h" 9 #include "../h/socketvar.h" 10 #include "../net/in.h" 11 #include "../net/route.h" 12 #include "../net/in_pcb.h" 13 #include "../net/in_systm.h" 14 #include "../net/ip.h" 15 #include "../net/ip_var.h" 16 #include "../net/udp.h" 17 #include "../net/udp_var.h" 18 19 /* 20 * UDP protocol implementation. 21 * Per RFC 768, August, 1980. 22 */ 23 udp_init() 24 { 25 26 COUNT(UDP_INIT); 27 udb.inp_next = udb.inp_prev = &udb; 28 } 29 30 int udpcksum; 31 struct sockaddr_in udp_in = { AF_INET }; 32 33 udp_input(m0) 34 struct mbuf *m0; 35 { 36 register struct udpiphdr *ui; 37 register struct inpcb *inp; 38 register struct mbuf *m; 39 int len, ulen; 40 41 COUNT(UDP_INPUT); 42 /* 43 * Get IP and UDP header together in first mbuf. 44 */ 45 m = m0; 46 if ((m->m_off > MMAXOFF || m->m_len < sizeof (struct udpiphdr)) && 47 (m = m_pullup(m, sizeof (struct udpiphdr))) == 0) { 48 udpstat.udps_hdrops++; 49 return; 50 } 51 ui = mtod(m, struct udpiphdr *); 52 if (((struct ip *)ui)->ip_hl > (sizeof (struct ip) >> 2)) 53 ip_stripoptions((struct ip *)ui, (struct mbuf *)0); 54 55 /* 56 * Make mbuf data length reflect UDP length. 57 * If not enough data to reflect UDP length, drop. 58 */ 59 ulen = ntohs((u_short)ui->ui_ulen); 60 len = sizeof (struct udphdr) + ulen; 61 if (((struct ip *)ui)->ip_len != len) { 62 if (len > ((struct ip *)ui)->ip_len) { 63 udpstat.udps_badlen++; 64 goto bad; 65 } 66 m_adj(m, ((struct ip *)ui)->ip_len - len); 67 /* (struct ip *)ui->ip_len = len; */ 68 } 69 70 /* 71 * Checksum extended UDP header and data. 72 */ 73 if (udpcksum) { 74 ui->ui_next = ui->ui_prev = 0; 75 ui->ui_x1 = 0; 76 ui->ui_len = htons((u_short)(sizeof (struct udphdr) + ulen)); 77 if (ui->ui_sum = in_cksum(m, len)) { 78 udpstat.udps_badsum++; 79 printf("udp cksum %x\n", ui->ui_sum); 80 m_freem(m); 81 return; 82 } 83 } 84 85 /* 86 * Locate pcb for datagram. On wildcard match, update 87 * control block to anchor network and host address. 88 */ 89 inp = in_pcblookup(&udb, 90 ui->ui_src, ui->ui_sport, ui->ui_dst, ui->ui_dport, 91 INPLOOKUP_WILDCARD); 92 if (inp == 0) 93 goto bad; 94 95 /* 96 * Construct sockaddr format source address. 97 * Stuff source address and datagram in user buffer. 98 */ 99 udp_in.sin_port = ui->ui_sport; 100 udp_in.sin_addr = ui->ui_src; 101 m->m_len -= sizeof (struct udpiphdr); 102 m->m_off += sizeof (struct udpiphdr); 103 if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, m) == 0) 104 goto bad; 105 sorwakeup(inp->inp_socket); 106 return; 107 bad: 108 m_freem(m); 109 } 110 111 udp_ctlinput(m) 112 struct mbuf *m; 113 { 114 115 COUNT(UDP_CTLINPUT); 116 m_freem(m); 117 } 118 119 udp_output(inp, m0) 120 struct inpcb *inp; 121 struct mbuf *m0; 122 { 123 register struct mbuf *m; 124 register struct udpiphdr *ui; 125 register int len = 0; 126 127 COUNT(UDP_OUTPUT); 128 /* 129 * Calculate data length and get a mbuf 130 * for UDP and IP headers. 131 */ 132 for (m = m0; m; m = m->m_next) 133 len += m->m_len; 134 m = m_get(M_DONTWAIT); 135 if (m == 0) 136 goto bad; 137 138 /* 139 * Fill in mbuf with extended UDP header 140 * and addresses and length put into network format. 141 */ 142 m->m_off = MMAXOFF - sizeof (struct udpiphdr); 143 m->m_len = sizeof (struct udpiphdr); 144 m->m_next = m0; 145 ui = mtod(m, struct udpiphdr *); 146 ui->ui_next = ui->ui_prev = 0; 147 ui->ui_x1 = 0; 148 ui->ui_pr = IPPROTO_UDP; 149 ui->ui_len = sizeof (struct udpiphdr) + len; 150 ui->ui_src = inp->inp_laddr; 151 ui->ui_dst = inp->inp_faddr; 152 ui->ui_sport = inp->inp_lport; 153 ui->ui_dport = inp->inp_fport; 154 ui->ui_ulen = htons((u_short)len); 155 156 /* 157 * Stuff checksum and output datagram. 158 */ 159 ui->ui_sum = 0; 160 ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len); 161 ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len; 162 ((struct ip *)ui)->ip_ttl = MAXTTL; 163 (void) ip_output(m, (struct mbuf *)0, 0, 164 inp->inp_socket->so_state & SS_PRIV); 165 return; 166 bad: 167 m_freem(m); 168 } 169 170 udp_usrreq(so, req, m, addr) 171 struct socket *so; 172 int req; 173 struct mbuf *m; 174 caddr_t addr; 175 { 176 struct inpcb *inp = sotoinpcb(so); 177 int error; 178 179 COUNT(UDP_USRREQ); 180 if (inp == 0 && req != PRU_ATTACH) 181 return (EINVAL); 182 switch (req) { 183 184 case PRU_ATTACH: 185 if (inp != 0) 186 return (EINVAL); 187 error = in_pcbattach(so, &udb, 2048, 2048, (struct sockaddr_in *)addr); 188 if (error) 189 return (error); 190 break; 191 192 case PRU_DETACH: 193 if (inp == 0) 194 return (ENOTCONN); 195 in_pcbdetach(inp); 196 break; 197 198 case PRU_CONNECT: 199 if (inp->inp_faddr.s_addr) 200 return (EISCONN); 201 error = in_pcbconnect(inp, (struct sockaddr_in *)addr); 202 if (error) 203 return (error); 204 soisconnected(so); 205 break; 206 207 case PRU_ACCEPT: 208 return (EOPNOTSUPP); 209 210 case PRU_DISCONNECT: 211 if (inp->inp_faddr.s_addr == 0) 212 return (ENOTCONN); 213 in_pcbdisconnect(inp); 214 soisdisconnected(so); 215 break; 216 217 case PRU_SHUTDOWN: 218 socantsendmore(so); 219 break; 220 221 case PRU_SEND: { 222 struct in_addr laddr; 223 224 if (addr) { 225 laddr = inp->inp_laddr; 226 if (inp->inp_faddr.s_addr) 227 return (EISCONN); 228 error = in_pcbconnect(inp, (struct sockaddr_in *)addr); 229 if (error) 230 return (error); 231 } else { 232 if (inp->inp_faddr.s_addr == 0) 233 return (ENOTCONN); 234 } 235 udp_output(inp, m); 236 if (addr) { 237 in_pcbdisconnect(inp); 238 inp->inp_laddr = laddr; 239 in_setsockaddr(inp); 240 } 241 } 242 break; 243 244 case PRU_ABORT: 245 in_pcbdetach(inp); 246 sofree(so); 247 soisdisconnected(so); 248 break; 249 250 case PRU_CONTROL: 251 return (EOPNOTSUPP); 252 253 default: 254 panic("udp_usrreq"); 255 } 256 return (0); 257 } 258