Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / netproto / atm / ipatm / ipatm_usrreq.c
1 /*
2  *
3  * ===================================
4  * HARP  |  Host ATM Research Platform
5  * ===================================
6  *
7  *
8  * This Host ATM Research Platform ("HARP") file (the "Software") is
9  * made available by Network Computing Services, Inc. ("NetworkCS")
10  * "AS IS".  NetworkCS does not provide maintenance, improvements or
11  * support of any kind.
12  *
13  * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
14  * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
15  * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
16  * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
17  * In no event shall NetworkCS be responsible for any damages, including
18  * but not limited to consequential damages, arising from or relating to
19  * any use of the Software or related support.
20  *
21  * Copyright 1994-1998 Network Computing Services, Inc.
22  *
23  * Copies of this Software may be made, however, the above copyright
24  * notice must be reproduced on all copies.
25  *
26  *      @(#) $FreeBSD: src/sys/netatm/ipatm/ipatm_usrreq.c,v 1.5.2.1 2003/02/15 09:25:13 phk Exp $
27  *
28  */
29
30 /*
31  * IP Over ATM Support
32  * -------------------
33  *
34  * Process user requests
35  *
36  */
37
38 #include <netatm/kern_include.h>
39
40 #include <netatm/ipatm/ipatm_var.h>
41 #include <netatm/ipatm/ipatm_serv.h>
42
43 #ifndef lint
44 __RCSID("@(#) $FreeBSD: src/sys/netatm/ipatm/ipatm_usrreq.c,v 1.5.2.1 2003/02/15 09:25:13 phk Exp $");
45 #endif
46
47
48 /*
49  * Process IP PF_ATM ioctls
50  * 
51  * Called at splnet.
52  *
53  * Arguments:
54  *      code    PF_ATM sub-operation code
55  *      data    pointer to code specific parameter data area
56  *      arg1    pointer to code specific argument
57  *
58  * Returns:
59  *      0       request procesed
60  *      errno   error processing request - reason indicated
61  *
62  */
63 int
64 ipatm_ioctl(code, data, arg1)
65         int             code;
66         caddr_t         data;
67         caddr_t         arg1;
68 {
69         struct atmaddreq        *aap;
70         struct atmdelreq        *adp;
71         struct atminfreq        *aip;
72         struct air_ip_vcc_rsp   aivr;
73         struct atm_nif  *nip;
74         struct ip_nif   *inp;
75         struct ipvcc    *ivp;
76         struct vccb     *vcp;
77         struct ipatmpvc pv;
78         caddr_t         cp;
79         struct in_addr  ip;
80         int             space, err = 0;
81
82
83         switch (code) {
84
85         case AIOCS_ADD_PVC:
86                 /*
87                  * Add an IP PVC
88                  */
89                 aap = (struct atmaddreq *)data;
90
91                 /*
92                  * Find the IP network interface
93                  */
94                 if ((nip = atm_nifname(aap->aar_pvc_intf)) == NULL) {
95                         err = ENXIO;
96                         break;
97                 }
98
99                 for (inp = ipatm_nif_head; inp; inp = inp->inf_next) {
100                         if (inp->inf_nif == nip)
101                                 break;
102                 }
103                 if (inp == NULL) {
104                         err = ENXIO;
105                         break;
106                 }
107
108                 /*
109                  * Validate PVC params
110                  */
111                 if (aap->aar_pvc_aal == ATM_AAL5) {
112                         if ((aap->aar_pvc_encaps != ATM_ENC_LLC) &&
113                             (aap->aar_pvc_encaps != ATM_ENC_NULL)) {
114                                 err = EINVAL;
115                                 break;
116                         }
117                 } else if (aap->aar_pvc_aal == ATM_AAL3_4) {
118                         if (aap->aar_pvc_encaps != ATM_ENC_NULL) {
119                                 err = EINVAL;
120                                 break;
121                         }
122                 } else {
123                         err = EINVAL;
124                         break;
125                 }
126
127                 if (aap->aar_pvc_flags & PVC_DYN) {
128                         /*
129                          * For dynamic PVC destination addressing, the
130                          * network interface must have support for this
131                          */
132                         if ((inp->inf_serv == NULL) ||
133                             (inp->inf_serv->is_arp_pvcopen == NULL)) {
134                                 err = EDESTADDRREQ;
135                                 break;
136                         }
137                 } else {
138                         u_long  dst = ((struct sockaddr_in *)&aap->aar_pvc_dst)
139                                                 ->sin_addr.s_addr;
140
141                         if (dst == INADDR_ANY) {
142                                 err = EINVAL;
143                                 break;
144                         }
145                 }
146
147                 /*
148                  * Build connection request
149                  */
150                 pv.ipp_ipnif = inp;
151                 pv.ipp_vpi = aap->aar_pvc_vpi;
152                 pv.ipp_vci = aap->aar_pvc_vci;
153                 pv.ipp_encaps = aap->aar_pvc_encaps;
154                 pv.ipp_aal = aap->aar_pvc_aal;
155                 if (aap->aar_pvc_flags & PVC_DYN) {
156                         pv.ipp_dst.sin_addr.s_addr = INADDR_ANY;
157                 } else
158                         pv.ipp_dst = *(struct sockaddr_in *)&aap->aar_pvc_dst;
159
160                 /*
161                  * Open a new VCC
162                  */
163                 err = ipatm_openpvc(&pv, &ivp);
164                 break;
165
166         case AIOCS_ADD_ARP:
167                 /*
168                  * Add an ARP mapping
169                  */
170                 aap = (struct atmaddreq *)data;
171
172                 /*
173                  * Validate IP address
174                  */
175                 if (aap->aar_arp_dst.sa_family != AF_INET) {
176                         err = EAFNOSUPPORT;
177                         break;
178                 }
179                 ip = SATOSIN(&aap->aar_arp_dst)->sin_addr;
180
181                 if (aap->aar_arp_intf[0] == '\0') {
182                         /*
183                          * Find the IP network interface associated with
184                          * the supplied IP address
185                          */
186                         for (inp = ipatm_nif_head; inp; inp = inp->inf_next) {
187                                 if (ipatm_chknif(ip, inp) == 0)
188                                         break;
189                         }
190                         if (inp == NULL) {
191                                 err = EADDRNOTAVAIL;
192                                 break;
193                         }
194                 } else {
195                         /*
196                          * Find the specified IP network interface
197                          */
198                         if ((nip = atm_nifname(aap->aar_arp_intf)) == NULL) {
199                                 err = ENXIO;
200                                 break;
201                         }
202                         for (inp = ipatm_nif_head; inp; inp = inp->inf_next) {
203                                 if (inp->inf_nif == nip)
204                                         break;
205                         }
206                         if (inp == NULL) {
207                                 err = ENXIO;
208                                 break;
209                         }
210                 }
211
212                 if ((ip.s_addr == INADDR_ANY) ||
213 #if (defined(BSD) && (BSD >= 199306))   
214                     in_broadcast(ip, &inp->inf_nif->nif_if) ||
215 #else
216                     in_broadcast(ip) ||
217 #endif
218                     IN_MULTICAST(ntohl(ip.s_addr))) {
219                         err = EADDRNOTAVAIL;
220                         break;
221                 }
222
223                 /*
224                  * Notify the responsible ARP service
225                  *
226                  * XXX: if there is one.  No idea how this happens, but at
227                  * least don't panic on a NULL pointer if it does.
228                  */
229                 if (inp->inf_serv == NULL) {
230                         err = ENXIO;
231                         break;
232                 }
233                 err = (*inp->inf_serv->is_ioctl)(code, data, inp->inf_isintf);
234                 break;
235
236         case AIOCS_DEL_ARP:
237                 /*
238                  * Delete an ARP mapping
239                  */
240                 adp = (struct atmdelreq *)data;
241
242                 /*
243                  * Validate IP address
244                  */
245                 if (adp->adr_arp_dst.sa_family != AF_INET) {
246                         err = EAFNOSUPPORT;
247                         break;
248                 }
249                 ip = SATOSIN(&adp->adr_arp_dst)->sin_addr;
250
251                 if (adp->adr_arp_intf[0] == '\0') {
252                         /*
253                          * Find the IP network interface associated with
254                          * the supplied IP address
255                          */
256                         for (inp = ipatm_nif_head; inp; inp = inp->inf_next) {
257                                 if (ipatm_chknif(ip, inp) == 0)
258                                         break;
259                         }
260                         if (inp == NULL) {
261                                 err = EADDRNOTAVAIL;
262                                 break;
263                         }
264                 } else {
265                         /*
266                          * Find the specified IP network interface
267                          */
268                         if ((nip = atm_nifname(adp->adr_arp_intf)) == NULL) {
269                                 err = ENXIO;
270                                 break;
271                         }
272                         for (inp = ipatm_nif_head; inp; inp = inp->inf_next) {
273                                 if (inp->inf_nif == nip)
274                                         break;
275                         }
276                         if (inp == NULL) {
277                                 err = ENXIO;
278                                 break;
279                         }
280                 }
281
282                 if ((ip.s_addr == INADDR_ANY) ||
283 #if (defined(BSD) && (BSD >= 199306))   
284                     in_broadcast(ip, &inp->inf_nif->nif_if) ||
285 #else
286                     in_broadcast(ip) ||
287 #endif
288                     IN_MULTICAST(ntohl(ip.s_addr))) {
289                         err = EADDRNOTAVAIL;
290                         break;
291                 }
292
293                 /*
294                  * Notify the responsible ARP service
295                  */
296                 err = (*inp->inf_serv->is_ioctl)(code, data, inp->inf_isintf);
297                 break;
298
299         case AIOCS_INF_IPM:
300                 /*
301                  * Get IP VCC information
302                  */
303                 aip = (struct atminfreq *)data;
304
305                 if (aip->air_ip_addr.sa_family != AF_INET)
306                         break;
307                 ip = SATOSIN(&aip->air_ip_addr)->sin_addr;
308
309                 cp = aip->air_buf_addr;
310                 space = aip->air_buf_len;
311
312                 /*
313                  * Loop through all our interfaces
314                  */
315                 for (inp = ipatm_nif_head; inp; inp = inp->inf_next) {
316                         /*
317                          * Check out each VCC
318                          */
319                         for (ivp = Q_HEAD(inp->inf_vcq, struct ipvcc); ivp;
320                                     ivp = Q_NEXT(ivp, struct ipvcc, iv_elem)) {
321
322                                 if ((ip.s_addr != INADDR_ANY) &&
323                                     (ip.s_addr != ivp->iv_dst.s_addr))
324                                         continue;
325
326                                 /*
327                                  * Make sure there's room in user buffer
328                                  */
329                                 if (space < sizeof(aivr)) {
330                                         err = ENOSPC;
331                                         break;
332                                 }
333
334                                 /*
335                                  * Fill in info to be returned
336                                  */
337                                 KM_ZERO((caddr_t)&aivr, sizeof(aivr));
338                                 SATOSIN(&aivr.aip_dst_addr)->sin_family = 
339                                         AF_INET;
340                                 SATOSIN(&aivr.aip_dst_addr)->sin_addr.s_addr = 
341                                         ivp->iv_dst.s_addr;
342                                 (void) snprintf(aivr.aip_intf,
343                                     sizeof(aivr.aip_intf), "%s%d",
344                                         inp->inf_nif->nif_if.if_name,
345                                         inp->inf_nif->nif_if.if_unit);
346                                 if ((ivp->iv_conn) &&
347                                     (ivp->iv_conn->co_connvc) &&
348                                     (vcp = ivp->iv_conn->co_connvc->cvc_vcc)) {
349                                         aivr.aip_vpi = vcp->vc_vpi;
350                                         aivr.aip_vci = vcp->vc_vci;
351                                         aivr.aip_sig_proto = vcp->vc_proto;
352                                 } 
353                                 aivr.aip_flags = ivp->iv_flags;
354                                 aivr.aip_state = ivp->iv_state;
355
356                                 /*
357                                  * Copy data to user buffer and 
358                                  * update buffer controls
359                                  */
360                                 err = copyout((caddr_t)&aivr, cp, sizeof(aivr));
361                                 if (err)
362                                         break;
363                                 cp += sizeof(aivr);
364                                 space -= sizeof(aivr);
365                         }
366                         if (err)
367                                 break;
368                 }
369
370                 /*
371                  * Update buffer pointer/count
372                  */
373                 aip->air_buf_addr = cp;
374                 aip->air_buf_len = space;
375                 break;
376
377         default:
378                 err = EOPNOTSUPP;
379         }
380
381         return (err);
382 }
383
384
385 /*
386  * Get Connection's Application/Owner Name
387  * 
388  * Arguments:
389  *      tok     ipatm connection token (pointer to ipvcc)
390  *
391  * Returns:
392  *      addr    pointer to string containing our name
393  *
394  */
395 caddr_t
396 ipatm_getname(tok)
397         void            *tok;
398 {
399         return ("IP");
400 }
401