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