1: /*
   2:  * Copyright (c) 1982, 1986 Regents of the University of California.
   3:  * All rights reserved.
   4:  *
   5:  * Redistribution and use in source and binary forms are permitted
   6:  * provided that this notice is preserved and that due credit is given
   7:  * to the University of California at Berkeley. The name of the University
   8:  * may not be used to endorse or promote products derived from this
   9:  * software without specific prior written permission. This software
  10:  * is provided ``as is'' without express or implied warranty.
  11:  *
  12:  *	@(#)udp_usrreq.c	7.5.2 (2.11BSD GTE) 1995/10/09
  13:  */
  14: 
  15: #include "param.h"
  16: #include "user.h"
  17: #include "mbuf.h"
  18: #include "protosw.h"
  19: #include "socket.h"
  20: #include "socketvar.h"
  21: #include "errno.h"
  22: 
  23: #include "../net/if.h"
  24: #include "../net/route.h"
  25: 
  26: #include "domain.h"
  27: #include "in.h"
  28: #include "in_pcb.h"
  29: #include "in_systm.h"
  30: #include "ip.h"
  31: #include "ip_var.h"
  32: #include "ip_icmp.h"
  33: #include "udp.h"
  34: #include "udp_var.h"
  35: 
  36: struct  inpcb *udp_last_inpcb = &udb;
  37: 
  38: /*
  39:  * UDP protocol implementation.
  40:  * Per RFC 768, August, 1980.
  41:  */
  42: udp_init()
  43: {
  44: 
  45:     udb.inp_next = udb.inp_prev = &udb;
  46: }
  47: 
  48: #ifndef COMPAT_42
  49: int udpcksum = 1;
  50: #else
  51: int udpcksum = 0;       /* XXX */
  52: #endif
  53: 
  54: struct  sockaddr_in udp_in = { AF_INET };
  55: 
  56: udp_input(m0, ifp)
  57:     struct mbuf *m0;
  58:     struct ifnet *ifp;
  59: {
  60:     register struct udpiphdr *ui;
  61:     register struct inpcb *inp;
  62:     register struct mbuf *m;
  63:     int len;
  64:     struct ip ip;
  65: 
  66:     udpstat.udps_ipackets++;
  67: 
  68:     /*
  69: 	 * Get IP and UDP header together in first mbuf.
  70: 	 */
  71:     m = m0;
  72:     if ((m->m_off > MMAXOFF || m->m_len < sizeof (struct udpiphdr)) &&
  73:         (m = m_pullup(m, sizeof (struct udpiphdr))) == 0) {
  74:         udpstat.udps_hdrops++;
  75:         return;
  76:     }
  77:     ui = mtod(m, struct udpiphdr *);
  78:     if (((struct ip *)ui)->ip_hl > (sizeof (struct ip) >> 2))
  79:         ip_stripoptions((struct ip *)ui, (struct mbuf *)0);
  80: 
  81:     /*
  82: 	 * Make mbuf data length reflect UDP length.
  83: 	 * If not enough data to reflect UDP length, drop.
  84: 	 */
  85:     len = ntohs((u_short)ui->ui_ulen);
  86:     if (((struct ip *)ui)->ip_len != len) {
  87:         if (len > ((struct ip *)ui)->ip_len) {
  88:             udpstat.udps_badlen++;
  89:             goto bad;
  90:         }
  91:         m_adj(m, len - ((struct ip *)ui)->ip_len);
  92:         /* ((struct ip *)ui)->ip_len = len; */
  93:     }
  94:     /*
  95: 	 * Save a copy of the IP header in case we want restore it for ICMP.
  96: 	 */
  97:     ip = *(struct ip*)ui;
  98: 
  99:     /*
 100: 	 * Checksum extended UDP header and data.
 101: 	 */
 102:     if (udpcksum && ui->ui_sum) {
 103:         ui->ui_next = ui->ui_prev = 0;
 104:         ui->ui_pad = 0;
 105:         ui->ui_x1 = 0;
 106:         ui->ui_len = ui->ui_ulen;
 107:         if (ui->ui_sum = in_cksum(m, len + sizeof (struct ip))) {
 108:             udpstat.udps_badsum++;
 109:             m_freem(m);
 110:             return;
 111:         }
 112:     }
 113: 
 114:     /*
 115: 	 * Locate pcb for datagram.
 116: 	 */
 117:     inp = udp_last_inpcb;
 118:     if (inp->inp_lport != ui->ui_dport ||
 119:         inp->inp_fport != ui->ui_sport ||
 120:         inp->inp_faddr.s_addr != ui->ui_src.s_addr ||
 121:         inp->inp_laddr.s_addr != ui->ui_dst.s_addr) {
 122:         inp = in_pcblookup(&udb, ui->ui_src, ui->ui_sport,
 123:             ui->ui_dst, ui->ui_dport, INPLOOKUP_WILDCARD);
 124:         if (inp)
 125:             udp_last_inpcb = inp;
 126:         udpstat.udpps_pcbcachemiss++;
 127:     }
 128:     if (inp == 0) {
 129:         udpstat.udps_noport++;
 130:         /* don't send ICMP response for broadcast packet */
 131:         if (in_broadcast(ui->ui_dst)) {
 132:             udpstat.udps_noportbcast++;
 133:             goto bad;
 134:         }
 135:         *(struct ip *)ui = ip;
 136:         icmp_error((struct ip *)ui, ICMP_UNREACH, ICMP_UNREACH_PORT,
 137:             ifp);
 138:         return;
 139:     }
 140: 
 141:     /*
 142: 	 * Construct sockaddr format source address.
 143: 	 * Stuff source address and datagram in user buffer.
 144: 	 */
 145:     udp_in.sin_port = ui->ui_sport;
 146:     udp_in.sin_addr = ui->ui_src;
 147:     m->m_len -= sizeof (struct udpiphdr);
 148:     m->m_off += sizeof (struct udpiphdr);
 149:     if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in,
 150:         m, (struct mbuf *)0) == 0) {
 151:         udpstat.udps_fullsock++;
 152:         goto bad;
 153:     }
 154:     sorwakeup(inp->inp_socket);
 155:     return;
 156: bad:
 157:     m_freem(m);
 158: }
 159: 
 160: /*
 161:  * Notify a udp user of an asynchronous error;
 162:  * just wake up so that he can collect error status.
 163:  */
 164: udp_notify(inp, errno)
 165:     register struct inpcb *inp;
 166:     int errno;
 167: {
 168: 
 169:     inp->inp_socket->so_error = errno;
 170:     sorwakeup(inp->inp_socket);
 171:     sowwakeup(inp->inp_socket);
 172: }
 173: 
 174: udp_ctlinput(cmd, sa, ip)
 175:     register int cmd;
 176:     struct sockaddr *sa;
 177:     register struct ip *ip;
 178: {
 179:     register struct udphdr *uh;
 180:     extern struct in_addr zeroin_addr;
 181:     extern u_char inetctlerrmap[];
 182: 
 183:     if ((unsigned)cmd > PRC_NCMDS || inetctlerrmap[cmd] == 0)
 184:         return;
 185:     if (ip) {
 186:         uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2));
 187:         in_pcbnotify(&udb, sa, uh->uh_dport, ip->ip_src, uh->uh_sport,
 188:             cmd, udp_notify);
 189:     } else
 190:         in_pcbnotify(&udb, sa, 0, zeroin_addr, 0, cmd, udp_notify);
 191: }
 192: 
 193: udp_output(inp, m0, addr, control)
 194:     register struct inpcb *inp;
 195:     struct mbuf *m0;
 196:     struct mbuf *addr, *control;
 197: {
 198:     register struct mbuf *m = m0;
 199:     register struct udpiphdr *ui;
 200:     register int len = 0;
 201:     struct in_addr laddr;
 202:     int s, error = 0;
 203: 
 204:     if (addr) {
 205:         laddr = inp->inp_laddr;
 206:         if (inp->inp_faddr.s_addr != INADDR_ANY) {
 207:             error = EISCONN;
 208:             goto release;
 209:         }
 210:         /*
 211: 		 * Must block input while temporarily connected.
 212: 		 */
 213:         s = splnet();
 214:         error = in_pcbconnect(inp, addr);
 215:         if (error) {
 216:             splx(s);
 217:             goto release;
 218:         }
 219:     } else {
 220:         if (inp->inp_faddr.s_addr == INADDR_ANY) {
 221:             error = ENOTCONN;
 222:             goto release;
 223:         }
 224:     }
 225: 
 226:     /*
 227: 	 * Calculate data length and get a mbuf
 228: 	 * for UDP and IP headers.
 229: 	 */
 230:     for (m = m0; m; m = m->m_next)
 231:         len += m->m_len;
 232:     MGET(m, M_WAIT, MT_HEADER);
 233: 
 234:     /*
 235: 	 * Fill in mbuf with extended UDP header
 236: 	 * and addresses and length put into network format.
 237: 	 */
 238:     m->m_off = MMAXOFF - sizeof (struct udpiphdr);
 239:     m->m_len = sizeof (struct udpiphdr);
 240:     m->m_next = m0;
 241:     ui = mtod(m, struct udpiphdr *);
 242:     ui->ui_next = ui->ui_prev = 0;
 243:     ui->ui_pad = 0;
 244:     ui->ui_x1 = 0;
 245:     ui->ui_pr = IPPROTO_UDP;
 246:     ui->ui_len = htons((u_short)len + sizeof (struct udphdr));
 247:     ui->ui_src = inp->inp_laddr;
 248:     ui->ui_dst = inp->inp_faddr;
 249:     ui->ui_sport = inp->inp_lport;
 250:     ui->ui_dport = inp->inp_fport;
 251:     ui->ui_ulen = ui->ui_len;
 252: 
 253:     /*
 254: 	 * Stuff checksum and output datagram.
 255: 	 */
 256:     ui->ui_sum = 0;
 257:     if (udpcksum) {
 258:         if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0)
 259:         ui->ui_sum = 0xffff;
 260:     }
 261:     ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len;
 262:     ((struct ip *)ui)->ip_ttl = ip_defttl;
 263:     udpstat.udps_opackets++;
 264:     error = ip_output(m, inp->inp_options, &inp->inp_route,
 265:         inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST));
 266: 
 267:     if (addr) {
 268:         in_pcbdisconnect(inp);
 269:         inp->inp_laddr = laddr;
 270:         splx(s);
 271:     }
 272:     return(error);
 273: 
 274: release:
 275:     m_freem(m);
 276:     return(error);
 277: }
 278: 
 279: int udp_sendspace = 2048;       /* really max datagram size */
 280: int udp_recvspace = 4 * (1024+sizeof(struct sockaddr_in)); /* 4 1K dgrams */
 281: 
 282: /*ARGSUSED*/
 283: udp_usrreq(so, req, m, nam, rights)
 284:     struct socket *so;
 285:     int req;
 286:     struct mbuf *m, *nam, *rights;
 287: {
 288:     register struct inpcb *inp = sotoinpcb(so);
 289:     int error = 0;
 290:     register int s;
 291: 
 292:     if (req == PRU_CONTROL)
 293:         return (in_control(so, (int)m, (caddr_t)nam,
 294:             (struct ifnet *)rights));
 295:     if (rights && rights->m_len) {
 296:         error = EINVAL;
 297:         goto release;
 298:     }
 299:     if (inp == NULL && req != PRU_ATTACH) {
 300:         error = EINVAL;
 301:         goto release;
 302:     }
 303:     switch (req) {
 304: 
 305:     case PRU_ATTACH:
 306:         if (inp != NULL) {
 307:             error = EINVAL;
 308:             break;
 309:         }
 310:         s = splnet();
 311:         error = in_pcballoc(so, &udb);
 312:         splx(s);
 313:         if (error)
 314:             break;
 315:         error = soreserve(so, udp_sendspace, udp_recvspace);
 316:         if (error)
 317:             break;
 318:         break;
 319: 
 320:     case PRU_DETACH:
 321:         udp_detach(inp);
 322:         break;
 323: 
 324:     case PRU_BIND:
 325:         s = splnet();
 326:         error = in_pcbbind(inp, nam);
 327:         splx(s);
 328:         break;
 329: 
 330:     case PRU_LISTEN:
 331:         error = EOPNOTSUPP;
 332:         break;
 333: 
 334:     case PRU_CONNECT:
 335:         if (inp->inp_faddr.s_addr != INADDR_ANY) {
 336:             error = EISCONN;
 337:             break;
 338:         }
 339:         s = splnet();
 340:         error = in_pcbconnect(inp, nam);
 341:         splx(s);
 342:         if (error == 0)
 343:             soisconnected(so);
 344:         break;
 345: 
 346:     case PRU_CONNECT2:
 347:         error = EOPNOTSUPP;
 348:         break;
 349: 
 350:     case PRU_ACCEPT:
 351:         error = EOPNOTSUPP;
 352:         break;
 353: 
 354:     case PRU_DISCONNECT:
 355:         if (inp->inp_faddr.s_addr == INADDR_ANY) {
 356:             error = ENOTCONN;
 357:             break;
 358:         }
 359:         s = splnet();
 360:         in_pcbdisconnect(inp);
 361:         inp->inp_laddr.s_addr = INADDR_ANY;
 362:         splx(s);
 363:         so->so_state &= ~SS_ISCONNECTED;        /* XXX */
 364:         break;
 365: 
 366:     case PRU_SHUTDOWN:
 367:         socantsendmore(so);
 368:         break;
 369: 
 370:     case PRU_SEND:
 371:         return(udp_output(inp, m, nam, rights));
 372: 
 373:     case PRU_ABORT:
 374:         soisdisconnected(so);
 375:         udp_detach(inp);
 376:         break;
 377: 
 378:     case PRU_SOCKADDR:
 379:         in_setsockaddr(inp, nam);
 380:         break;
 381: 
 382:     case PRU_PEERADDR:
 383:         in_setpeeraddr(inp, nam);
 384:         break;
 385: 
 386:     case PRU_SENSE:
 387:         /*
 388: 		 * stat: don't bother with a blocksize.
 389: 		 */
 390:         return (0);
 391: 
 392:     case PRU_SENDOOB:
 393:     case PRU_FASTTIMO:
 394:     case PRU_SLOWTIMO:
 395:     case PRU_PROTORCV:
 396:     case PRU_PROTOSEND:
 397:         error =  EOPNOTSUPP;
 398:         break;
 399: 
 400:     case PRU_RCVD:
 401:     case PRU_RCVOOB:
 402:         return (EOPNOTSUPP);    /* do not free mbuf's */
 403: 
 404:     default:
 405:         panic("udp_usrreq");
 406:     }
 407: release:
 408:     if (m != NULL)
 409:         m_freem(m);
 410:     return (error);
 411: }
 412: 
 413: udp_detach(inp)
 414:     register struct inpcb *inp;
 415: {
 416:     register int s = splnet();
 417: 
 418:     if (inp == udp_last_inpcb)
 419:         udp_last_inpcb = &udb;
 420:     in_pcbdetach(inp);
 421:     splx(s);
 422: }
 423: 
 424: /*
 425:  * Sysctl for udp variables.
 426:  */
 427: udp_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
 428:     int *name;
 429:     u_int namelen;
 430:     void *oldp;
 431:     size_t *oldlenp;
 432:     void *newp;
 433:     size_t newlen;
 434: {
 435:     /* All sysctl names at this level are terminal. */
 436:     if (namelen != 1)
 437:         return (ENOTDIR);
 438: 
 439:     switch (name[0]) {
 440:     case UDPCTL_CHECKSUM:
 441:         return (sysctl_int(oldp, oldlenp, newp, newlen, &udpcksum));
 442:     default:
 443:         return (ENOPROTOOPT);
 444:     }
 445:     /* NOTREACHED */
 446: }

Defined functions

udp_ctlinput defined in line 174; never used
udp_detach defined in line 413; used 2 times
udp_init defined in line 42; never used
udp_input defined in line 56; never used
udp_notify defined in line 164; used 2 times
udp_output defined in line 193; used 1 times
udp_sysctl defined in line 427; never used
udp_usrreq defined in line 283; never used

Defined variables

udp_in defined in line 54; used 3 times
udp_last_inpcb defined in line 36; used 4 times
udp_recvspace defined in line 280; used 1 times
udp_sendspace defined in line 279; used 1 times
udpcksum defined in line 51; used 3 times
Last modified: 1995-10-11
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 4701
Valid CSS Valid XHTML 1.0 Strict