1 /**************************************************************************/
2 /*                                                                        */
3 /*                    miscellaneous ip routines                           */
4 /*                                                                        */
5 /**************************************************************************/
6 
7 
8 #include "../h/param.h"
9 #include "../h/mbuf.h"
10 #include "../h/protosw.h"
11 #include "../h/socket.h"
12 #include "../h/socketvar.h"
13 #include "../h/errno.h"
14 
15 #include "../net/if.h"
16 #include "../net/route.h"
17 #include "../net/af.h"
18 #include "../net/netisr.h"
19 
20 #include "../vax/mtpr.h"
21 
22 #include "../bbnnet/in.h"
23 #include "../bbnnet/in_var.h"
24 #include "../bbnnet/net.h"
25 #include "../bbnnet/in_pcb.h"
26 #include "../bbnnet/fsm.h"
27 #include "../bbnnet/ip.h"
28 #include "../bbnnet/icmp.h"
29 
30 
31 ip_ioctl (inp, command, data)
32 struct inpcb *inp;
33 int command;
34 caddr_t	data;
35 {
36     /* no IP ioctls */
37     return in_ioctl (command, data);
38 }
39 
40 ip_ctloutput(req, so, level, optname, optval)
41 int req;
42 struct socket *so;
43 int level, optname;
44 struct mbuf **optval;
45 {
46     struct inpcb *inp;
47 
48     /*
49      * O.K., with the berkeley method of using the protocol number for the level,
50      * what magic cookie should we use to distinguish between IP and the interfaces?
51      */
52     inp = sotoinpcb(so);
53 
54     switch(req)
55     {
56 	case PRCO_GETOPT:
57 	    return(ip_getopt(inp,optname,optval));
58 
59 	case PRCO_SETOPT:
60 	    return(ip_setopt(inp,optname,optval));
61 
62 	default:
63 	    panic("ip_ctloutput");
64     }
65     /*NOTREACHED*/
66 }
67 
68 ip_setopt (inpcb, command, data)
69 struct inpcb	*inpcb;
70 struct mbuf	**data;
71 {
72     register int error = 0;
73     register struct mbuf *m = *data;
74 
75     switch (command)
76     {
77       case SO_IPROUTE:
78 	/* this probably breaks!! */
79 	if (m->m_len == 0)
80 	{
81 	    /* turns off use of options */
82 	    inpcb->inp_optlen = 0;
83 	    break;
84 	}
85 	if ((m->m_len < (2 * sizeof(struct in_addr))) ||
86 	    (m->m_len > (MAX_IPOPTLEN - sizeof(struct in_addr))) ||
87 	    (m->m_len % sizeof(struct in_addr)))
88 	{
89 	    error = EINVAL;
90 	    break;
91 	}
92 	/*
93 	 * O.K., user process specifies it as:
94 	 *      ->A->B->C->D
95 	 * D must be our final destination (but we can't
96 	 * check that since we haven't connected yet).
97 	 * Convert this into a form for ip_output.
98 	 */
99 	inpcb->inp_optlen = m->m_len;
100 	bcopy (mtod(m, caddr_t), inpcb->inp_options, (unsigned)m->m_len);
101 
102 	/*
103 	 * Following could be moved to ip_send(), but let's
104 	 * do it once for efficiency even though user may
105 	 * retrieve different from what stored.
106 	 */
107 	{
108 	    char	*p;
109 	    struct in_addr *ipa;
110 
111 	    p = inpcb->inp_options;
112 	    ipa = (struct in_addr *) p;
113 	    ipa[m->m_len / sizeof(struct in_addr)] = ipa[0];
114 	    p[0] = IP_NOP_OPT;
115 	    p[1] = IP_LRTE_OPT;
116 	    p[2] = m->m_len -1;
117 	    p[3] = 4; /* offset: counting one based */
118 	}
119 	/*
120 	 * Now we have a correct IP source route recorded,
121 	 * and the first hop comes after the source route.
122 	 */
123 	break;
124       default:
125 	error = EINVAL;
126     }
127 
128     /* they can futz with m */
129     if (*data)
130 	m_freem(*data);
131 
132     return (error);
133 }
134 
135 ip_getopt (inpcb, command, data)
136 struct inpcb	*inpcb;
137 struct mbuf	**data;
138 {
139     register error = 0;
140     register struct mbuf *m = NULL;
141 
142     *data = NULL;	/* o.k. (no data sent on getsockopt) */
143 
144     switch (command)
145     {
146       case SO_IPROUTE:
147 	if (!inpcb->inp_optlen)
148 	    break;
149 
150 	m = m_get(M_WAIT, MT_SOOPTS);
151 
152 	if (m == 0)
153 	    return(ENOBUFS);
154 
155 	m->m_len = inpcb->inp_optlen;
156 
157 	bcopy (inpcb->inp_options, mtod(m, caddr_t), (unsigned)m->m_len);
158 	break;
159 
160       default:
161 	error = EINVAL;
162     }
163     *data = m;
164     return (error);
165 }
166 
167 u_char inetctlerrmap[PRC_NCMDS] =
168 {
169     ENETUNREACH,	/* PRC_IFDOWN: connection oriented protocols use
170 			 * interface with their local address.  Can't re-route.
171 			 */
172 
173 	ECONNABORTED,	0,		0,
174 	0,		0,		EHOSTDOWN,	EHOSTUNREACH,
175 	ENETUNREACH,	EHOSTUNREACH,	ECONNREFUSED,	ECONNREFUSED,
176 	EMSGSIZE,	0,		0,		0,
177 	0,		0,		0,		0
178 } ;
179