V4L/DVB (5935): dvb_frontend: Range check of frequency and symbol rate
authorOliver Endriss <o.endriss@gmx.de>
Tue, 24 Jul 2007 00:00:36 +0000 (21:00 -0300)
committerMauro Carvalho Chehab <mchehab@infradead.org>
Wed, 10 Oct 2007 01:03:28 +0000 (22:03 -0300)
Add range check of frequency and symbol rate to the FE_SET_FRONTEND ioctl.

This will also avoid a divide-by zero exception in the stv0297 driver,
if symbol rate is set to 0.

Signed-off-by: Oliver Endriss <o.endriss@gmx.de>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
drivers/media/dvb/dvb-core/dvb_frontend.c

index b6c7f6610ec53205f407e8e2b85c397af3974155..384b5b8959c1c1e5b6c588cd8e8b10e96354c925 100644 (file)
@@ -697,6 +697,47 @@ static int dvb_frontend_start(struct dvb_frontend *fe)
        return 0;
 }
 
+static int dvb_frontend_check_parameters(struct dvb_frontend *fe,
+                               struct dvb_frontend_parameters *parms)
+{
+       /* range check: frequency */
+       if ((fe->ops.info.frequency_min &&
+            parms->frequency < fe->ops.info.frequency_min) ||
+           (fe->ops.info.frequency_max &&
+            parms->frequency > fe->ops.info.frequency_max)) {
+               printk(KERN_WARNING "DVB: frontend %u frequency %u out of range (%u..%u)\n",
+                      fe->dvb->num, parms->frequency,
+                      fe->ops.info.frequency_min, fe->ops.info.frequency_max);
+               return -EINVAL;
+       }
+
+       /* range check: symbol rate */
+       if (fe->ops.info.type == FE_QPSK) {
+               if ((fe->ops.info.symbol_rate_min &&
+                    parms->u.qpsk.symbol_rate < fe->ops.info.symbol_rate_min) ||
+                   (fe->ops.info.symbol_rate_max &&
+                    parms->u.qpsk.symbol_rate > fe->ops.info.symbol_rate_max)) {
+                       printk(KERN_WARNING "DVB: frontend %u symbol rate %u out of range (%u..%u)\n",
+                              fe->dvb->num, parms->u.qpsk.symbol_rate,
+                              fe->ops.info.symbol_rate_min, fe->ops.info.symbol_rate_max);
+                       return -EINVAL;
+               }
+
+       } else if (fe->ops.info.type == FE_QAM) {
+               if ((fe->ops.info.symbol_rate_min &&
+                    parms->u.qam.symbol_rate < fe->ops.info.symbol_rate_min) ||
+                   (fe->ops.info.symbol_rate_max &&
+                    parms->u.qam.symbol_rate > fe->ops.info.symbol_rate_max)) {
+                       printk(KERN_WARNING "DVB: frontend %u symbol rate %u out of range (%u..%u)\n",
+                              fe->dvb->num, parms->u.qam.symbol_rate,
+                              fe->ops.info.symbol_rate_min, fe->ops.info.symbol_rate_max);
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
 static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
                        unsigned int cmd, void *parg)
 {
@@ -883,6 +924,11 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
        case FE_SET_FRONTEND: {
                struct dvb_frontend_tune_settings fetunesettings;
 
+               if (dvb_frontend_check_parameters(fe, parg) < 0) {
+                       err = -EINVAL;
+                       break;
+               }
+
                memcpy (&fepriv->parameters, parg,
                        sizeof (struct dvb_frontend_parameters));