1 /*- 2 * Copyright (c) 1991 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 * 7 * @(#)clnp_raw.c 7.10 (Berkeley) 10/11/92 8 */ 9 10 /*********************************************************** 11 Copyright IBM Corporation 1987 12 13 All Rights Reserved 14 15 Permission to use, copy, modify, and distribute this software and its 16 documentation for any purpose and without fee is hereby granted, 17 provided that the above copyright notice appear in all copies and that 18 both that copyright notice and this permission notice appear in 19 supporting documentation, and that the name of IBM not be 20 used in advertising or publicity pertaining to distribution of the 21 software without specific, written prior permission. 22 23 IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 24 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 25 IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 26 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 27 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 28 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 29 SOFTWARE. 30 31 ******************************************************************/ 32 33 /* 34 * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison 35 */ 36 /* $Header: clnp_raw.c,v 4.2 88/06/29 14:58:56 hagens Exp $ */ 37 /* $Source: /usr/argo/sys/netiso/RCS/clnp_raw.c,v $ */ 38 39 #include <sys/param.h> 40 #include <sys/mbuf.h> 41 #include <sys/domain.h> 42 #include <sys/protosw.h> 43 #include <sys/socket.h> 44 #include <sys/socketvar.h> 45 #include <sys/errno.h> 46 #include <sys/time.h> 47 48 #include <net/if.h> 49 #include <net/route.h> 50 #include <net/raw_cb.h> 51 52 #include <netiso/iso.h> 53 #include <netiso/iso_pcb.h> 54 #include <netiso/clnp.h> 55 #include <netiso/clnp_stat.h> 56 #include <netiso/argo_debug.h> 57 58 #include <netiso/tp_user.h> /* XXX -- defines SOL_NETWORK */ 59 60 struct sockproto rclnp_proto = { PF_ISO, 0 }; 61 /* 62 * FUNCTION: rclnp_input 63 * 64 * PURPOSE: Setup generic address an protocol structures for 65 * raw input routine, then pass them along with the 66 * mbuf chain. 67 * 68 * RETURNS: none 69 * 70 * SIDE EFFECTS: 71 * 72 * NOTES: The protocol field of rclnp_proto is set to zero indicating 73 * no protocol. 74 */ 75 rclnp_input(m, src, dst, hdrlen) 76 struct mbuf *m; /* ptr to packet */ 77 struct sockaddr_iso *src; /* ptr to src address */ 78 struct sockaddr_iso *dst; /* ptr to dest address */ 79 int hdrlen; /* length (in bytes) of clnp header */ 80 { 81 #ifdef TROLL 82 if (trollctl.tr_ops & TR_CHUCK) { 83 m_freem(m); 84 return; 85 } 86 #endif TROLL 87 88 if (raw_input(m, &rclnp_proto, (struct sockaddr *)src, 89 (struct sockaddr *)dst) == 0) { 90 clnp_stat.cns_delivered--; 91 clnp_stat.cns_noproto++; 92 } 93 } 94 95 /* 96 * FUNCTION: rclnp_output 97 * 98 * PURPOSE: Prepare to send a raw clnp packet. Setup src and dest 99 * addresses, count the number of bytes to send, and 100 * call clnp_output. 101 * 102 * RETURNS: success - 0 103 * failure - an appropriate error code 104 * 105 * SIDE EFFECTS: 106 * 107 * NOTES: 108 */ 109 rclnp_output(m0, so) 110 struct mbuf *m0; /* packet to send */ 111 struct socket *so; /* socket to send from */ 112 { 113 register struct mbuf *m; /* used to scan a chain */ 114 int len = 0; /* store length of chain here */ 115 struct rawisopcb *rp = sotorawisopcb(so); /* ptr to raw cb */ 116 int error; /* return value of function */ 117 int flags; /* flags for clnp_output */ 118 119 if (0 == (m0->m_flags & M_PKTHDR)) 120 return (EINVAL); 121 /* 122 * Set up src address. If user has bound socket to an address, use it. 123 * Otherwise, do not specify src (clnp_output will fill it in). 124 */ 125 if (rp->risop_rcb.rcb_laddr) { 126 if (rp->risop_isop.isop_sladdr.siso_family != AF_ISO) { 127 bad: 128 m_freem(m0); 129 return(EAFNOSUPPORT); 130 } 131 } 132 /* set up dest address */ 133 if (rp->risop_rcb.rcb_faddr == 0) 134 goto bad; 135 rp->risop_isop.isop_sfaddr = 136 *(struct sockaddr_iso *)rp->risop_rcb.rcb_faddr; 137 rp->risop_isop.isop_faddr = &rp->risop_isop.isop_sfaddr; 138 139 /* get flags and ship it off */ 140 flags = rp->risop_flags & CLNP_VFLAGS; 141 142 error = clnp_output(m0, &rp->risop_isop, m0->m_pkthdr.len, 143 flags|CLNP_NOCACHE); 144 145 return (error); 146 } 147 148 /* 149 * FUNCTION: rclnp_ctloutput 150 * 151 * PURPOSE: Raw clnp socket option processing 152 * All options are stored inside an mbuf. 153 * 154 * RETURNS: success - 0 155 * failure - unix error code 156 * 157 * SIDE EFFECTS: If the options mbuf does not exist, it the mbuf passed 158 * is used. 159 * 160 * NOTES: 161 */ 162 rclnp_ctloutput(op, so, level, optname, m) 163 int op; /* type of operation */ 164 struct socket *so; /* ptr to socket */ 165 int level; /* level of option */ 166 int optname; /* name of option */ 167 struct mbuf **m; /* ptr to ptr to option data */ 168 { 169 int error = 0; 170 register struct rawisopcb *rp = sotorawisopcb(so);/* raw cb ptr */ 171 172 IFDEBUG(D_CTLOUTPUT) 173 printf("rclnp_ctloutput: op = x%x, level = x%x, name = x%x\n", 174 op, level, optname); 175 if (*m != NULL) { 176 printf("rclnp_ctloutput: %d bytes of mbuf data\n", (*m)->m_len); 177 dump_buf(mtod((*m), caddr_t), (*m)->m_len); 178 } 179 ENDDEBUG 180 181 #ifdef SOL_NETWORK 182 if (level != SOL_NETWORK) 183 error = EINVAL; 184 else switch (op) { 185 #else 186 switch (op) { 187 #endif SOL_NETWORK 188 case PRCO_SETOPT: 189 switch (optname) { 190 case CLNPOPT_FLAGS: { 191 u_short usr_flags; 192 /* 193 * Insure that the data passed has exactly one short in it 194 */ 195 if ((*m == NULL) || ((*m)->m_len != sizeof(short))) { 196 error = EINVAL; 197 break; 198 } 199 200 /* 201 * Don't allow invalid flags to be set 202 */ 203 usr_flags = (*mtod((*m), short *)); 204 205 if ((usr_flags & (CLNP_VFLAGS)) != usr_flags) { 206 error = EINVAL; 207 } else 208 rp->risop_flags |= usr_flags; 209 210 } break; 211 212 case CLNPOPT_OPTS: 213 if (error = clnp_set_opts(&rp->risop_isop.isop_options, m)) 214 break; 215 rp->risop_isop.isop_optindex = m_get(M_WAIT, MT_SOOPTS); 216 (void) clnp_opt_sanity(rp->risop_isop.isop_options, 217 mtod(rp->risop_isop.isop_options, caddr_t), 218 rp->risop_isop.isop_options->m_len, 219 mtod(rp->risop_isop.isop_optindex, 220 struct clnp_optidx *)); 221 break; 222 } 223 break; 224 225 case PRCO_GETOPT: 226 #ifdef notdef 227 /* commented out to keep hi C quiet */ 228 switch (optname) { 229 default: 230 error = EINVAL; 231 break; 232 } 233 #endif notdef 234 break; 235 default: 236 error = EINVAL; 237 break; 238 } 239 if (op == PRCO_SETOPT) { 240 /* note: m_freem does not barf is *m is NULL */ 241 m_freem(*m); 242 *m = NULL; 243 } 244 245 return error; 246 } 247 248 /*ARGSUSED*/ 249 clnp_usrreq(so, req, m, nam, control) 250 register struct socket *so; 251 int req; 252 struct mbuf *m, *nam, *control; 253 { 254 register int error = 0; 255 register struct rawisopcb *rp = sotorawisopcb(so); 256 257 rp = sotorawisopcb(so); 258 switch (req) { 259 260 case PRU_ATTACH: 261 if (rp) 262 panic("rip_attach"); 263 MALLOC(rp, struct rawisopcb *, sizeof *rp, M_PCB, M_WAITOK); 264 if (rp == 0) 265 return (ENOBUFS); 266 bzero((caddr_t)rp, sizeof *rp); 267 so->so_pcb = (caddr_t)rp; 268 break; 269 270 case PRU_DETACH: 271 if (rp == 0) 272 panic("rip_detach"); 273 if (rp->risop_isop.isop_options) 274 m_freem(rp->risop_isop.isop_options); 275 if (rp->risop_isop.isop_route.ro_rt) 276 RTFREE(rp->risop_isop.isop_route.ro_rt); 277 if (rp->risop_rcb.rcb_laddr) 278 rp->risop_rcb.rcb_laddr = 0; 279 /* free clnp cached hdr if necessary */ 280 if (rp->risop_isop.isop_clnpcache != NULL) { 281 struct clnp_cache *clcp = 282 mtod(rp->risop_isop.isop_clnpcache, struct clnp_cache *); 283 if (clcp->clc_hdr != NULL) { 284 m_free(clcp->clc_hdr); 285 } 286 m_free(rp->risop_isop.isop_clnpcache); 287 } 288 if (rp->risop_isop.isop_optindex != NULL) 289 m_free(rp->risop_isop.isop_optindex); 290 291 break; 292 293 case PRU_BIND: 294 { 295 struct sockaddr_iso *addr = mtod(nam, struct sockaddr_iso *); 296 297 if (nam->m_len != sizeof(*addr)) 298 return (EINVAL); 299 if ((ifnet == 0) || 300 (addr->siso_family != AF_ISO) || 301 (addr->siso_addr.isoa_len && 302 ifa_ifwithaddr((struct sockaddr *)addr) == 0)) 303 return (EADDRNOTAVAIL); 304 rp->risop_isop.isop_sladdr = *addr; 305 rp->risop_rcb.rcb_laddr = (struct sockaddr *) 306 (rp->risop_isop.isop_laddr = &rp->risop_isop.isop_sladdr); 307 return (0); 308 } 309 case PRU_CONNECT: 310 { 311 struct sockaddr_iso *addr = mtod(nam, struct sockaddr_iso *); 312 313 if ((nam->m_len > sizeof(*addr)) || (addr->siso_len > sizeof(*addr))) 314 return (EINVAL); 315 if (ifnet == 0) 316 return (EADDRNOTAVAIL); 317 if (addr->siso_family != AF_ISO) 318 rp->risop_isop.isop_sfaddr = *addr; 319 rp->risop_rcb.rcb_faddr = (struct sockaddr *) 320 (rp->risop_isop.isop_faddr = &rp->risop_isop.isop_sfaddr); 321 soisconnected(so); 322 return (0); 323 } 324 } 325 error = raw_usrreq(so, req, m, nam, control); 326 327 if (error && req == PRU_ATTACH && so->so_pcb) 328 free((caddr_t)rp, M_PCB); 329 return (error); 330 } 331